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 <algorithm>
15
16#include <Errors.h>
17#include <SupportDefs.h>
18
19#include <new>
20
21DynamicBuffer::DynamicBuffer(size_t initialSize) :
22	fBuffer(NULL),
23	fBufferSize(0),
24	fDataStart(0),
25	fDataEnd(0),
26	fInit(B_NO_INIT)
27{
28	fBuffer = new (std::nothrow) unsigned char[initialSize];
29	if (fBuffer != NULL) {
30		fBufferSize = initialSize;
31		fInit = B_OK;
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
72ssize_t
73DynamicBuffer::Write(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 (ssize_t)size;
86}
87
88
89ssize_t
90DynamicBuffer::Read(void* data, size_t size)
91{
92	if (fInit != B_OK)
93		return fInit;
94
95	size = std::min(size, Size());
96	if (size == 0)
97		return 0;
98
99	memcpy(data, fBuffer + fDataStart, size);
100	fDataStart += size;
101
102	if (fDataStart == fDataEnd)
103		fDataStart = fDataEnd = 0;
104
105	return size;
106}
107
108
109unsigned char*
110DynamicBuffer::Data() const
111{
112	return fBuffer + fDataStart;
113}
114
115
116size_t
117DynamicBuffer::Size() const
118{
119	return fDataEnd - fDataStart;
120}
121
122
123size_t
124DynamicBuffer::BytesRemaining() const
125{
126	return fBufferSize - fDataEnd;
127}
128
129
130void
131DynamicBuffer::PrintToStream()
132{
133	printf("Current buffer size : %ld\n", fBufferSize);
134	printf("Data start position : %ld\n", fDataStart);
135	printf("Data end position   : %ld\n", fDataEnd);
136	printf("Bytes wasted        : %ld\n", fDataStart);
137	printf("Bytes available     : %ld\n", fBufferSize - fDataEnd);
138}
139
140
141status_t
142DynamicBuffer::_GrowToFit(size_t size, bool exact)
143{
144	if (size <= fBufferSize - fDataEnd)
145		return B_OK;
146
147	size_t newSize;
148	if (!exact)
149		newSize = (fBufferSize + size) * 2;
150	else
151		newSize = size;
152
153	unsigned char* newBuffer = new (std::nothrow) unsigned char[newSize];
154	if (newBuffer == NULL)
155		return B_NO_MEMORY;
156
157	if (fDataStart != fDataEnd)
158		memcpy(newBuffer, fBuffer + fDataStart, fDataEnd - fDataStart);
159
160	delete[] fBuffer;
161	fBuffer = newBuffer;
162	fDataEnd -= fDataStart;
163	fDataStart = 0;
164	fBufferSize = newSize;
165
166	return B_OK;
167}
168