1/*
2 * Copyright 2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *              Bruno Albuquerque, bga@bug-br.org.br
7 */
8
9#include "DynamicBuffer.h"
10
11#include <stdio.h>
12#include <string.h>
13
14#include <Errors.h>
15#include <SupportDefs.h>
16
17#include <new>
18
19DynamicBuffer::DynamicBuffer(size_t initialSize) :
20	fBuffer(NULL),
21	fBufferSize(0),
22	fDataStart(0),
23	fDataEnd(0),
24	fInit(B_NO_INIT)
25{
26	if (initialSize >= 0) {
27		fBuffer = new (std::nothrow) unsigned char[initialSize];
28		if (fBuffer != NULL) {
29			fBufferSize = initialSize;
30			fInit = B_OK;
31		}
32	}
33}
34
35
36DynamicBuffer::~DynamicBuffer()
37{
38	delete[] fBuffer;
39	fBufferSize = 0;
40	fDataStart = 0;
41	fDataEnd = 0;
42}
43
44
45DynamicBuffer::DynamicBuffer(const DynamicBuffer& buffer) :
46	fBuffer(NULL),
47	fBufferSize(0),
48	fDataStart(0),
49	fDataEnd(0),
50	fInit(B_NO_INIT)
51{
52	fInit = buffer.fInit;
53	if (fInit == B_OK) {
54		status_t result = _GrowToFit(buffer.fBufferSize, true);
55		if (result == B_OK) {
56			memcpy(fBuffer, buffer.fBuffer, fBufferSize);
57			fDataStart = buffer.fDataStart;
58			fDataEnd = buffer.fDataEnd;
59		} else
60			fInit = result;
61	}
62}
63
64
65status_t
66DynamicBuffer::InitCheck() const
67{
68	return fInit;
69}
70
71
72status_t
73DynamicBuffer::Insert(const void* data, size_t size)
74{
75	if (fInit != B_OK)
76		return fInit;
77
78	status_t result = _GrowToFit(size);
79	if (result != B_OK)
80		return result;
81
82	memcpy(fBuffer + fDataEnd, data, size);
83	fDataEnd += size;
84
85	return B_OK;
86}
87
88
89status_t
90DynamicBuffer::Remove(void* data, size_t size)
91{
92	if (fInit != B_OK)
93		return fInit;
94
95	if (fDataStart + size > fDataEnd)
96		return B_BUFFER_OVERFLOW;
97
98	memcpy(data, fBuffer + fDataStart, size);
99	fDataStart += size;
100
101	if (fDataStart == fDataEnd)
102		fDataStart = fDataEnd = 0;
103
104	return B_OK;
105}
106
107
108unsigned char*
109DynamicBuffer::Data() const
110{
111	return fBuffer + fDataStart;
112}
113
114
115size_t
116DynamicBuffer::Size() const
117{
118	return fDataEnd - fDataStart;
119}
120
121
122size_t
123DynamicBuffer::BytesRemaining() const
124{
125	return fBufferSize - fDataEnd;
126}
127
128
129void
130DynamicBuffer::PrintToStream()
131{
132	printf("Current buffer size : %ld\n", fBufferSize);
133	printf("Data start position : %ld\n", fDataStart);
134	printf("Data end position   : %ld\n", fDataEnd);
135	printf("Bytes wasted        : %ld\n", fDataStart);
136	printf("Bytes available     : %ld\n", fBufferSize - fDataEnd);
137}
138
139
140status_t
141DynamicBuffer::_GrowToFit(size_t size, bool exact)
142{
143	if (size <= fBufferSize - fDataEnd)
144		return B_OK;
145
146	size_t newSize;
147	if (!exact)
148		newSize = (fBufferSize + size) * 2;
149	else
150		newSize = size;
151
152	unsigned char* newBuffer = new (std::nothrow) unsigned char[newSize];
153	if (newBuffer == NULL)
154		return B_NO_MEMORY;
155
156	if (fDataStart != fDataEnd) {
157		memcpy(newBuffer, fBuffer + fDataStart, fDataEnd - fDataStart);
158	}
159
160	delete[] fBuffer;
161	fBuffer = newBuffer;
162	fDataEnd -= fDataStart;
163	fDataStart = 0;
164	fBufferSize = newSize;
165
166	return B_OK;
167}
168