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