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 26LittleEndianBuffer::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 36LittleEndianBuffer::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 46LittleEndianBuffer::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 56LittleEndianBuffer::~LittleEndianBuffer() 57{ 58 if (fOwnsBuffer) 59 free(fBuffer); 60} 61 62// Write 8 63bool 64LittleEndianBuffer::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 79bool 80LittleEndianBuffer::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 95bool 96LittleEndianBuffer::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 111bool 112LittleEndianBuffer::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 127bool 128LittleEndianBuffer::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 143bool 144LittleEndianBuffer::Write(const LittleEndianBuffer& other) 145{ 146 return Write(other.Buffer(), other.SizeUsed()); 147} 148 149// Write buffer 150bool 151LittleEndianBuffer::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 179bool 180LittleEndianBuffer::Read(uint8& value) 181{ 182 if (fHandle >= fBufferEnd) 183 return false; 184 185 value = *fHandle++; 186 187 return true; 188} 189 190// Read 16 191bool 192LittleEndianBuffer::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 204bool 205LittleEndianBuffer::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 217bool 218LittleEndianBuffer::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 230bool 231LittleEndianBuffer::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 243bool 244LittleEndianBuffer::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 262void 263LittleEndianBuffer::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 271void 272LittleEndianBuffer::Reset() 273{ 274 fHandle = fBuffer; 275} 276 277// #pragma mark - 278 279// _SetSize 280void 281LittleEndianBuffer::_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