diff options
Diffstat (limited to 'net/flip/flip_frame_builder.h')
-rw-r--r-- | net/flip/flip_frame_builder.h | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/net/flip/flip_frame_builder.h b/net/flip/flip_frame_builder.h new file mode 100644 index 0000000..809f451 --- /dev/null +++ b/net/flip/flip_frame_builder.h @@ -0,0 +1,184 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_FLIP_FRAME_BUILDER_H_ +#define NET_FLIP_FRAME_BUILDER_H_ + +#ifdef WIN32 +#include <winsock2.h> // for htonl() functions +#else +#include <arpa/inet.h> +#endif + +#include <string> + +#include "base/logging.h" +#include "flip_protocol.h" // cross-google3 directory naming. + +#ifdef WIN32 +#undef VLOG +#define VLOG(x) LOG_IF(INFO, false) +#endif // WIN32 + +namespace flip { + +// This class provides facilities for basic binary value packing and unpacking +// into Flip frames. Note: this is similar to Chrome's pickle class, but is +// simplified to work in both the client and server, and without excess +// padding. +// +// The FlipFrameBuilder supports appending primitive values (int, string, etc) +// to a frame instance. The FlipFrameBuilder grows its internal memory buffer +// dynamically to hold the sequence of primitive values. The internal memory +// buffer is exposed as the "data" of the FlipFrameBuilder. +// +// When reading from a FlipFrameBuilder the consumer must know what value types +// to read and in what order to read them as the FlipFrameBuilder does not keep +// track of the type of data written to it. +class FlipFrameBuilder { + public: + FlipFrameBuilder(); + ~FlipFrameBuilder(); + + // Initializes a FlipFrameBuilder from a const block of data. The data is + // not copied; instead the data is merely referenced by this + // FlipFrameBuilder. Only const methods should be used when initialized + // this way. + FlipFrameBuilder(const char* data, int data_len); + + // Returns the size of the FlipFrameBuilder's data. + int length() const { return length_; } + + // Returns the data for this FlipFrameBuilder. + const FlipFrame* data() const { + return reinterpret_cast<FlipFrame*>(buffer_); + } + + // Takes the buffer from the FlipFrameBuilder. + FlipFrame* take() { + FlipFrame* rv = reinterpret_cast<FlipFrame*>(buffer_); + buffer_ = NULL; + capacity_ = 0; + length_ = 0; + return rv; + } + + // Methods for reading the payload of the FlipFrameBuilder. To read from the + // start of the FlipFrameBuilder, initialize *iter to NULL. If successful, + // these methods return true. Otherwise, false is returned to indicate that + // the result could not be extracted. + bool ReadUInt16(void** iter, uint16* result) const; + bool ReadUInt32(void** iter, uint32* result) const; + bool ReadString(void** iter, std::string* result) const; + bool ReadBytes(void** iter, const char** data, uint16 length) const; + bool ReadData(void** iter, const char** data, uint16* length) const; + + // Methods for adding to the payload. These values are appended to the end + // of the FlipFrameBuilder payload. When reading values, you must read them + // in the order they were added. Note - binary integers are converted from + // host to network form. + bool WriteUInt16(uint16 value) { + value = htons(value); + return WriteBytes(&value, sizeof(value)); + } + bool WriteUInt32(uint32 value) { + value = htonl(value); + return WriteBytes(&value, sizeof(value)); + } + bool WriteString(const std::string& value); + bool WriteBytes(const void* data, uint16 data_len); + + // Write an integer to a particular offset in the data buffer. + bool WriteUInt32ToOffset(int offset, uint32 value) { + if (offset + sizeof(value) > length_) + return false; + value = htonl(value); + char *ptr = buffer_ + offset; + memcpy(ptr, &value, sizeof(value)); + return true; + } + + // Allows the caller to write data directly into the FlipFrameBuilder. + // This saves a copy when the data is not already available in a buffer. + // The caller must not write more than the length it declares it will. + // Use ReadData to get the data. + // Returns NULL on failure. + // + // The returned pointer will only be valid until the next write operation + // on this FlipFrameBuilder. + char* BeginWriteData(uint16 length); + + // Returns true if the given iterator could point to data with the given + // length. If there is no room for the given data before the end of the + // payload, returns false. + bool IteratorHasRoomFor(const void* iter, int len) const { + const char* end_of_region = reinterpret_cast<const char*>(iter) + len; + VLOG(1) << "len: " << len; + if (len < 0) { + VLOG(1) << "Len < 0"; + return false; + } else if (iter < buffer_) { + VLOG(1) << "iter < buffer_"; + return false; + } else if (iter > end_of_payload()) { + VLOG(1) << "iter > end_of_payload())"; + return false; + } else if (iter > end_of_region) { + VLOG(1) << "iter > end_of_region)"; + return false; + } else if (end_of_region > end_of_payload()) { + VLOG(1) << "end_of_region > end_of_payload()"; + VLOG(1) << "end_of_region - end_of_payload(): " + << (end_of_region - end_of_payload()); + + return false; + } + + // Watch out for overflow in pointer calculation, which wraps. + return (iter <= end_of_region) && (end_of_region <= end_of_payload()); + } + + protected: + size_t capacity() const { + return capacity_; + } + + const char* end_of_payload() const { return buffer_ + length_; } + + // Resizes the buffer for use when writing the specified amount of data. The + // location that the data should be written at is returned, or NULL if there + // was an error. Call EndWrite with the returned offset and the given length + // to pad out for the next write. + char* BeginWrite(size_t length); + + // Completes the write operation by padding the data with NULL bytes until it + // is padded. Should be paired with BeginWrite, but it does not necessarily + // have to be called after the data is written. + void EndWrite(char* dest, int length); + + // Resize the capacity, note that the input value should include the size of + // the header: new_capacity = sizeof(Header) + desired_payload_capacity. + // A new failure will cause a Resize failure... and caller should check + // the return result for true (i.e., successful resizing). + bool Resize(size_t new_capacity); + + // Moves the iterator by the given number of bytes. + static void UpdateIter(void** iter, int bytes) { + *iter = static_cast<char*>(*iter) + bytes; + } + + // Initial size of the payload. + static const int kInitialPayload = 1024; + + private: + char* buffer_; + size_t capacity_; // Allocation size of payload (or -1 if buffer is const). + size_t length_; // current length of the buffer + size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer. +}; + +} // namespace flip + +#endif // NET_FLIP_FRAME_BUILDER_H_ + |