1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_FLIP_FRAME_BUILDER_H_ 6 #define NET_FLIP_FRAME_BUILDER_H_ 7 8 #ifdef WIN32 9 #include <winsock2.h> // for htonl() functions 10 #else 11 #include <arpa/inet.h> 12 #endif 13 14 #include <string> 15 16 #include "base/logging.h" 17 #include "flip_protocol.h" // cross-google3 directory naming. 18 19 namespace flip { 20 21 // This class provides facilities for basic binary value packing and unpacking 22 // into Flip frames. 23 // 24 // The FlipFrameBuilder supports appending primitive values (int, string, etc) 25 // to a frame instance. The FlipFrameBuilder grows its internal memory buffer 26 // dynamically to hold the sequence of primitive values. The internal memory 27 // buffer is exposed as the "data" of the FlipFrameBuilder. 28 // 29 // When reading from a FlipFrameBuilder the consumer must know what value types 30 // to read and in what order to read them as the FlipFrameBuilder does not keep 31 // track of the type of data written to it. 32 class FlipFrameBuilder { 33 public: 34 FlipFrameBuilder(); 35 ~FlipFrameBuilder(); 36 37 // Initializes a FlipFrameBuilder from a const block of data. The data is 38 // not copied; instead the data is merely referenced by this 39 // FlipFrameBuilder. Only const methods should be used when initialized 40 // this way. 41 FlipFrameBuilder(const char* data, int data_len); 42 43 // Returns the size of the FlipFrameBuilder's data. length()44 int length() const { return length_; } 45 46 // Takes the buffer from the FlipFrameBuilder. take()47 FlipFrame* take() { 48 FlipFrame* rv = new FlipFrame(buffer_, true); 49 buffer_ = NULL; 50 capacity_ = 0; 51 length_ = 0; 52 return rv; 53 } 54 55 // Methods for reading the payload of the FlipFrameBuilder. To read from the 56 // start of the FlipFrameBuilder, initialize *iter to NULL. If successful, 57 // these methods return true. Otherwise, false is returned to indicate that 58 // the result could not be extracted. 59 bool ReadUInt16(void** iter, uint16* result) const; 60 bool ReadUInt32(void** iter, uint32* result) const; 61 bool ReadString(void** iter, std::string* result) const; 62 bool ReadBytes(void** iter, const char** data, uint16 length) const; 63 bool ReadData(void** iter, const char** data, uint16* length) const; 64 65 // Methods for adding to the payload. These values are appended to the end 66 // of the FlipFrameBuilder payload. When reading values, you must read them 67 // in the order they were added. Note - binary integers are converted from 68 // host to network form. WriteUInt16(uint16 value)69 bool WriteUInt16(uint16 value) { 70 value = htons(value); 71 return WriteBytes(&value, sizeof(value)); 72 } WriteUInt32(uint32 value)73 bool WriteUInt32(uint32 value) { 74 value = htonl(value); 75 return WriteBytes(&value, sizeof(value)); 76 } 77 bool WriteString(const std::string& value); 78 bool WriteBytes(const void* data, uint16 data_len); 79 80 // Write an integer to a particular offset in the data buffer. WriteUInt32ToOffset(int offset,uint32 value)81 bool WriteUInt32ToOffset(int offset, uint32 value) { 82 value = htonl(value); 83 return WriteBytesToOffset(offset, &value, sizeof(value)); 84 } 85 86 // Write to a particular offset in the data buffer. WriteBytesToOffset(int offset,const void * data,uint32 data_len)87 bool WriteBytesToOffset(int offset, const void* data, uint32 data_len) { 88 if (offset + data_len > length_) 89 return false; 90 char *ptr = buffer_ + offset; 91 memcpy(ptr, data, data_len); 92 return true; 93 } 94 95 // Allows the caller to write data directly into the FlipFrameBuilder. 96 // This saves a copy when the data is not already available in a buffer. 97 // The caller must not write more than the length it declares it will. 98 // Use ReadData to get the data. 99 // Returns NULL on failure. 100 // 101 // The returned pointer will only be valid until the next write operation 102 // on this FlipFrameBuilder. 103 char* BeginWriteData(uint16 length); 104 105 // Returns true if the given iterator could point to data with the given 106 // length. If there is no room for the given data before the end of the 107 // payload, returns false. IteratorHasRoomFor(const void * iter,int len)108 bool IteratorHasRoomFor(const void* iter, int len) const { 109 const char* end_of_region = reinterpret_cast<const char*>(iter) + len; 110 if (len < 0 || 111 iter < buffer_ || 112 iter > end_of_payload() || 113 iter > end_of_region || 114 end_of_region > end_of_payload()) 115 return false; 116 117 // Watch out for overflow in pointer calculation, which wraps. 118 return (iter <= end_of_region) && (end_of_region <= end_of_payload()); 119 } 120 121 protected: capacity()122 size_t capacity() const { 123 return capacity_; 124 } 125 end_of_payload()126 const char* end_of_payload() const { return buffer_ + length_; } 127 128 // Resizes the buffer for use when writing the specified amount of data. The 129 // location that the data should be written at is returned, or NULL if there 130 // was an error. Call EndWrite with the returned offset and the given length 131 // to pad out for the next write. 132 char* BeginWrite(size_t length); 133 134 // Completes the write operation by padding the data with NULL bytes until it 135 // is padded. Should be paired with BeginWrite, but it does not necessarily 136 // have to be called after the data is written. 137 void EndWrite(char* dest, int length); 138 139 // Resize the capacity, note that the input value should include the size of 140 // the header: new_capacity = sizeof(Header) + desired_payload_capacity. 141 // A new failure will cause a Resize failure... and caller should check 142 // the return result for true (i.e., successful resizing). 143 bool Resize(size_t new_capacity); 144 145 // Moves the iterator by the given number of bytes. UpdateIter(void ** iter,int bytes)146 static void UpdateIter(void** iter, int bytes) { 147 *iter = static_cast<char*>(*iter) + bytes; 148 } 149 150 // Initial size of the payload. 151 static const int kInitialPayload = 1024; 152 153 private: 154 char* buffer_; 155 size_t capacity_; // Allocation size of payload (or -1 if buffer is const). 156 size_t length_; // current length of the buffer 157 size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer. 158 }; 159 160 } // namespace flip 161 162 #endif // NET_FLIP_FRAME_BUILDER_H_ 163 164