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