xref: /haiku/src/libs/icon/flat_icon/LittleEndianBuffer.cpp (revision 55b40aa53a835472ec7952b138ae4256203d02e4)
1 /*
2  * Copyright 2006, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include "LittleEndianBuffer.h"
10 
11 #include <malloc.h>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <ByteOrder.h>
16 
17 #define CHUNK_SIZE 256
18 
19 // constructor
20 LittleEndianBuffer::LittleEndianBuffer()
21 	: fBuffer((uint8*)malloc(CHUNK_SIZE)),
22 	  fHandle(fBuffer),
23 	  fBufferEnd(fBuffer + CHUNK_SIZE),
24 	  fSize(CHUNK_SIZE),
25 	  fOwnsBuffer(true)
26 {
27 }
28 
29 // constructor
30 LittleEndianBuffer::LittleEndianBuffer(size_t size)
31 	: fBuffer((uint8*)malloc(size)),
32 	  fHandle(fBuffer),
33 	  fBufferEnd(fBuffer + size),
34 	  fSize(size),
35 	  fOwnsBuffer(true)
36 {
37 }
38 
39 // constructor
40 LittleEndianBuffer::LittleEndianBuffer(uint8* buffer, size_t size)
41 	: fBuffer(buffer),
42 	  fHandle(fBuffer),
43 	  fBufferEnd(fBuffer + size),
44 	  fSize(size),
45 	  fOwnsBuffer(false)
46 {
47 }
48 
49 // destructor
50 LittleEndianBuffer::~LittleEndianBuffer()
51 {
52 	if (fOwnsBuffer)
53 		free(fBuffer);
54 }
55 
56 // Write 8
57 bool
58 LittleEndianBuffer::Write(uint8 value)
59 {
60 	if (fHandle == fBufferEnd)
61 		_SetSize(fSize + CHUNK_SIZE);
62 
63 	if (!fBuffer)
64 		return false;
65 
66 	*fHandle = value;
67 	fHandle++;
68 
69 	return true;
70 }
71 
72 // Write 16
73 bool
74 LittleEndianBuffer::Write(uint16 value)
75 {
76 	if ((fHandle + 1) >= fBufferEnd)
77 		_SetSize(fSize + CHUNK_SIZE);
78 
79 	if (!fBuffer)
80 		return false;
81 
82 	*(uint16*)fHandle = B_HOST_TO_LENDIAN_INT16(value);
83 	fHandle += 2;
84 
85 	return true;
86 }
87 
88 // Write 32
89 bool
90 LittleEndianBuffer::Write(uint32 value)
91 {
92 	if ((fHandle + 3) >= fBufferEnd)
93 		_SetSize(fSize + CHUNK_SIZE);
94 
95 	if (!fBuffer)
96 		return false;
97 
98 	*(uint32*)fHandle = B_HOST_TO_LENDIAN_INT32(value);
99 	fHandle += 4;
100 
101 	return true;
102 }
103 
104 // Write double
105 bool
106 LittleEndianBuffer::Write(float value)
107 {
108 	if ((fHandle + sizeof(float) - 1) >= fBufferEnd)
109 		_SetSize(fSize + CHUNK_SIZE);
110 
111 	if (!fBuffer)
112 		return false;
113 
114 	*(float*)fHandle = B_HOST_TO_LENDIAN_FLOAT(value);
115 	fHandle += sizeof(float);
116 
117 	return true;
118 }
119 
120 // Write double
121 bool
122 LittleEndianBuffer::Write(double value)
123 {
124 	if ((fHandle + sizeof(double) - 1) >= fBufferEnd)
125 		_SetSize(fSize + CHUNK_SIZE);
126 
127 	if (!fBuffer)
128 		return false;
129 
130 	*(double*)fHandle = B_HOST_TO_LENDIAN_DOUBLE(value);
131 	fHandle += sizeof(double);
132 
133 	return true;
134 }
135 
136 // Write LittleEndianBuffer
137 bool
138 LittleEndianBuffer::Write(const LittleEndianBuffer& other)
139 {
140 	return Write(other.Buffer(), other.SizeUsed());
141 }
142 
143 // Write buffer
144 bool
145 LittleEndianBuffer::Write(const uint8* buffer, size_t bytes)
146 {
147 	if (bytes == 0)
148 		return true;
149 
150 	// figure out needed size and suitable new size
151 	size_t neededSize = SizeUsed() + bytes;
152 	size_t newSize = fSize;
153 	while (newSize < neededSize)
154 		newSize += CHUNK_SIZE;
155 
156 	// resize if necessary
157 	if (newSize > fSize)
158 		_SetSize(newSize);
159 
160 	if (!fBuffer)
161 		return false;
162 
163 	// paste buffer
164 	memcpy(fHandle, buffer, bytes);
165 	fHandle += bytes;
166 
167 	return true;
168 }
169 
170 // #pragma mark -
171 
172 // Read 8
173 bool
174 LittleEndianBuffer::Read(uint8& value)
175 {
176 	if (fHandle >= fBufferEnd)
177 		return false;
178 
179 	value = *fHandle++;
180 
181 	return true;
182 }
183 
184 // Read 16
185 bool
186 LittleEndianBuffer::Read(uint16& value)
187 {
188 	if ((fHandle + 1) >= fBufferEnd)
189 		return false;
190 
191 	value = B_LENDIAN_TO_HOST_INT16(*(uint16*)fHandle);
192 	fHandle += 2;
193 
194 	return true;
195 }
196 
197 // Read 32
198 bool
199 LittleEndianBuffer::Read(uint32& value)
200 {
201 	if ((fHandle + 3) >= fBufferEnd)
202 		return false;
203 
204 	value = B_LENDIAN_TO_HOST_INT32(*(uint32*)fHandle);
205 	fHandle += 4;
206 
207 	return true;
208 }
209 
210 // Read float
211 bool
212 LittleEndianBuffer::Read(float& value)
213 {
214 	if ((fHandle + sizeof(float) - 1) >= fBufferEnd)
215 		return false;
216 
217 	value = B_LENDIAN_TO_HOST_FLOAT(*(float*)fHandle);
218 	fHandle += sizeof(float);
219 
220 	return true;
221 }
222 
223 // Read double
224 bool
225 LittleEndianBuffer::Read(double& value)
226 {
227 	if ((fHandle + sizeof(double) - 1) >= fBufferEnd)
228 		return false;
229 
230 	value = B_LENDIAN_TO_HOST_DOUBLE(*(double*)fHandle);
231 	fHandle += sizeof(double);
232 
233 	return true;
234 }
235 
236 // Read LittleEndianBuffer
237 bool
238 LittleEndianBuffer::Read(LittleEndianBuffer& other, size_t bytes)
239 {
240 	if ((fHandle + bytes - 1) >= fBufferEnd)
241 		return false;
242 
243 	if (other.Write(fHandle, bytes)) {
244 		// reset other handle to beginning of pasted data
245 		other.fHandle -= bytes;
246 		fHandle += bytes;
247 		return true;
248 	}
249 
250 	return false;
251 }
252 
253 // #pragma mark -
254 
255 // Skip
256 void
257 LittleEndianBuffer::Skip(size_t bytes)
258 {
259 	// NOTE: is ment to be used while reading!!
260 	// when used while writing, the growing will not work reliably
261 	fHandle += bytes;
262 }
263 
264 // Reset
265 void
266 LittleEndianBuffer::Reset()
267 {
268 	fHandle = fBuffer;
269 }
270 
271 // #pragma mark -
272 
273 // _SetSize
274 void
275 LittleEndianBuffer::_SetSize(size_t size)
276 {
277 	if (!fOwnsBuffer) {
278 		// prevent user error
279 		// (we are in read mode)
280 		fBuffer = NULL;
281 		return;
282 	}
283 
284 	int32 pos = fHandle - fBuffer;
285 	fBuffer = (uint8*)realloc((void*)fBuffer, size);
286 	fHandle = fBuffer + pos;
287 	fBufferEnd = fBuffer + size;
288 	fSize = size;
289 }
290 
291