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