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