+// ----------------------------------------------------------------------------
+// A class for holding growable data buffers (not necessarily strings)
+// ----------------------------------------------------------------------------
+
+// This class manages the actual data buffer pointer and is ref-counted.
+class wxMemoryBufferData
+{
+public:
+ // the initial size and also the size added by ResizeIfNeeded()
+ enum { DefBufSize = 1024 };
+
+ friend class wxMemoryBuffer;
+
+ // everyting is private as it can only be used by wxMemoryBuffer
+private:
+ wxMemoryBufferData(size_t size = wxMemoryBufferData::DefBufSize)
+ : m_data(size ? malloc(size) : NULL), m_size(size), m_len(0), m_ref(0)
+ {
+ }
+ ~wxMemoryBufferData() { free(m_data); }
+
+
+ void ResizeIfNeeded(size_t newSize)
+ {
+ if (newSize > m_size)
+ {
+ void *dataOld = m_data;
+ m_data = realloc(m_data, newSize + wxMemoryBufferData::DefBufSize);
+ if ( !m_data )
+ {
+ free(dataOld);
+ }
+
+ m_size = newSize + wxMemoryBufferData::DefBufSize;
+ }
+ }
+
+ void IncRef() { m_ref += 1; }
+ void DecRef()
+ {
+ m_ref -= 1;
+ if (m_ref == 0) // are there no more references?
+ delete this;
+ }
+
+ void *release()
+ {
+ if ( m_data == NULL )
+ return NULL;
+
+ wxASSERT_MSG( m_ref == 1, "can't release shared buffer" );
+
+ void *p = m_data;
+ m_data = NULL;
+ m_len =
+ m_size = 0;
+
+ return p;
+ }
+
+
+ // the buffer containing the data
+ void *m_data;
+
+ // the size of the buffer
+ size_t m_size;
+
+ // the amount of data currently in the buffer
+ size_t m_len;
+
+ // the reference count
+ size_t m_ref;
+
+ wxDECLARE_NO_COPY_CLASS(wxMemoryBufferData);
+};
+
+
+class wxMemoryBuffer
+{
+public:
+ // ctor and dtor
+ wxMemoryBuffer(size_t size = wxMemoryBufferData::DefBufSize)
+ {
+ m_bufdata = new wxMemoryBufferData(size);
+ m_bufdata->IncRef();
+ }
+
+ ~wxMemoryBuffer() { m_bufdata->DecRef(); }
+
+
+ // copy and assignment
+ wxMemoryBuffer(const wxMemoryBuffer& src)
+ : m_bufdata(src.m_bufdata)
+ {
+ m_bufdata->IncRef();
+ }
+
+ wxMemoryBuffer& operator=(const wxMemoryBuffer& src)
+ {
+ if (&src != this)
+ {
+ m_bufdata->DecRef();
+ m_bufdata = src.m_bufdata;
+ m_bufdata->IncRef();
+ }
+ return *this;
+ }
+
+
+ // Accessors
+ void *GetData() const { return m_bufdata->m_data; }
+ size_t GetBufSize() const { return m_bufdata->m_size; }
+ size_t GetDataLen() const { return m_bufdata->m_len; }
+
+ bool IsEmpty() const { return GetDataLen() == 0; }
+
+ void SetBufSize(size_t size) { m_bufdata->ResizeIfNeeded(size); }
+ void SetDataLen(size_t len)
+ {
+ wxASSERT(len <= m_bufdata->m_size);
+ m_bufdata->m_len = len;
+ }
+
+ void Clear() { SetDataLen(0); }
+
+ // Ensure the buffer is big enough and return a pointer to it
+ void *GetWriteBuf(size_t sizeNeeded)
+ {
+ m_bufdata->ResizeIfNeeded(sizeNeeded);
+ return m_bufdata->m_data;
+ }
+
+ // Update the length after the write
+ void UngetWriteBuf(size_t sizeUsed) { SetDataLen(sizeUsed); }
+
+ // Like the above, but appends to the buffer
+ void *GetAppendBuf(size_t sizeNeeded)
+ {
+ m_bufdata->ResizeIfNeeded(m_bufdata->m_len + sizeNeeded);
+ return (char*)m_bufdata->m_data + m_bufdata->m_len;
+ }
+
+ // Update the length after the append
+ void UngetAppendBuf(size_t sizeUsed)
+ {
+ SetDataLen(m_bufdata->m_len + sizeUsed);
+ }
+
+ // Other ways to append to the buffer
+ void AppendByte(char data)
+ {
+ wxCHECK_RET( m_bufdata->m_data, wxT("invalid wxMemoryBuffer") );
+
+ m_bufdata->ResizeIfNeeded(m_bufdata->m_len + 1);
+ *(((char*)m_bufdata->m_data) + m_bufdata->m_len) = data;
+ m_bufdata->m_len += 1;
+ }
+
+ void AppendData(const void *data, size_t len)
+ {
+ memcpy(GetAppendBuf(len), data, len);
+ UngetAppendBuf(len);
+ }
+
+ operator const char *() const { return (const char*)GetData(); }
+
+ // gives up ownership of data, returns the pointer; after this call,
+ // data isn't freed by the buffer and its content is resent to empty
+ void *release()
+ {
+ return m_bufdata->release();
+ }
+
+private:
+ wxMemoryBufferData* m_bufdata;
+};
+