Vault
4.1
|
00001 /* 00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved. 00003 This file is part of the Code Vault version 4.1 00004 http://www.bombaydigital.com/ 00005 License: MIT. See LICENSE.md in the Vault top level directory. 00006 */ 00007 00010 #include "vbinaryiostream.h" 00011 00012 #include "vinstant.h" 00013 #include "vexception.h" 00014 00015 static const Vs64 MAX_ONE_BYTE_LENGTH = CONST_S64(0x00000000000000FC); 00016 static const Vu8 THREE_BYTE_LENGTH_INDICATOR_BYTE = 0xFF; 00017 static const Vu8 FIVE_BYTE_LENGTH_INDICATOR_BYTE = 0xFE; 00018 static const Vu8 NINE_BYTE_LENGTH_INDICATOR_BYTE = 0xFD; 00019 00020 #undef sscanf 00021 00022 VBinaryIOStream::VBinaryIOStream(VStream& rawStream) 00023 : VIOStream(rawStream) 00024 { 00025 } 00026 00027 Vs8 VBinaryIOStream::readS8() { 00028 Vs8 value; 00029 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(1)); 00030 return value; 00031 } 00032 00033 Vu8 VBinaryIOStream::readU8() { 00034 Vu8 value; 00035 this->readGuaranteed(&value, CONST_S64(1)); 00036 return value; 00037 } 00038 00039 Vs16 VBinaryIOStream::readS16() { 00040 Vs16 value; 00041 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(2)); 00042 V_BYTESWAP_NTOH_S16_IN_PLACE(value); 00043 return value; 00044 } 00045 00046 Vu16 VBinaryIOStream::readU16() { 00047 Vu16 value; 00048 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(2)); 00049 V_BYTESWAP_NTOH_U16_IN_PLACE(value); 00050 return value; 00051 } 00052 00053 Vs32 VBinaryIOStream::readS32() { 00054 Vs32 value; 00055 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(4)); 00056 V_BYTESWAP_NTOH_S32_IN_PLACE(value); 00057 return value; 00058 } 00059 00060 int VBinaryIOStream::readInt32() { 00061 return static_cast<int>(this->readS32()); 00062 } 00063 00064 Vu32 VBinaryIOStream::readU32() { 00065 Vu32 value; 00066 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(4)); 00067 V_BYTESWAP_NTOH_U32_IN_PLACE(value); 00068 return value; 00069 } 00070 00071 Vs64 VBinaryIOStream::readS64() { 00072 Vs64 value; 00073 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(8)); 00074 V_BYTESWAP_NTOH_S64_IN_PLACE(value); 00075 return value; 00076 } 00077 00078 Vu64 VBinaryIOStream::readU64() { 00079 Vu64 value; 00080 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(8)); 00081 V_BYTESWAP_NTOH_U64_IN_PLACE(value); 00082 return value; 00083 } 00084 00085 VFloat VBinaryIOStream::readFloat() { 00086 VFloat value; 00087 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(4)); 00088 V_BYTESWAP_NTOH_F_IN_PLACE(value); 00089 return value; 00090 } 00091 00092 VDouble VBinaryIOStream::readDouble() { 00093 VDouble value; 00094 this->readGuaranteed(reinterpret_cast<Vu8*>(&value), CONST_S64(8)); 00095 V_BYTESWAP_NTOH_D_IN_PLACE(value); 00096 return value; 00097 } 00098 00099 bool VBinaryIOStream::readBool() { 00100 return (this->readU8() != 0); 00101 } 00102 00103 void VBinaryIOStream::readString(VString& s) { 00104 Vs64 length = this->readDynamicCount(); 00105 00106 if (length > V_MAX_S32) { 00107 throw VStackTraceException("String with unsupported length > 2GB encountered in stream."); 00108 } 00109 00110 if (length == 0) { // Avoid forced allocation of a buffer if none is needed. 00111 s = VString::EMPTY(); 00112 } else { 00113 s.preflight((int) length); 00114 this->readGuaranteed(s.getDataBuffer(), length); 00115 s.postflight((int) length); 00116 } 00117 } 00118 00119 VString VBinaryIOStream::readString() { 00120 /* 00121 Note that this API is far less efficient than the one above, because 00122 it incurs TWO copies instead of none -- one when a temporary VString 00123 is created by the compiler to hold the return value, and one when 00124 that temporary VString is copied to the caller's lvalue. 00125 */ 00126 00127 VString s; 00128 this->readString(s); 00129 return s; 00130 } 00131 00132 void VBinaryIOStream::readString32(VString& s) { 00133 int length = (int) this->readS32(); 00134 00135 if (length == 0) { // Avoid forced allocation of a buffer if none is needed. 00136 if (s.isNotEmpty()) { // Avoid unnecessary do-nothing work if s is already empty. 00137 s = VString::EMPTY(); 00138 } 00139 } else { 00140 s.preflight(length); 00141 this->readGuaranteed(s.getDataBuffer(), length); 00142 s.postflight(length); 00143 } 00144 } 00145 00146 VString VBinaryIOStream::readString32() { 00147 /* 00148 Note that this API is far less efficient than the one above, because 00149 it incurs TWO copies instead of none -- one when a temporary VString 00150 is created by the compiler to hold the return value, and one when 00151 that temporary VString is copied to the caller's lvalue. 00152 */ 00153 00154 VString s; 00155 this->readString32(s); 00156 return s; 00157 } 00158 00159 void VBinaryIOStream::readInstant(VInstant& i) { 00160 Vs64 value = this->readS64(); 00161 i.setValue(value); 00162 } 00163 00164 VInstant VBinaryIOStream::readInstant() { 00165 /* 00166 Note that this API is less efficient than the one above, because 00167 it incurs TWO copies instead of none -- one when a temporary VInstant 00168 is created by the compiler to hold the return value, and one when 00169 that temporary VInstant is copied to the caller's lvalue. (Unless the 00170 compiler can optimize part of that away.) 00171 */ 00172 Vs64 value = this->readS64(); 00173 return VInstant::instantFromRawValue(value); 00174 } 00175 00176 void VBinaryIOStream::readDuration(VDuration& d) { 00177 Vs64 value = this->readS64(); 00178 d.setDurationMilliseconds(value); 00179 } 00180 00181 VDuration VBinaryIOStream::readDuration() { 00182 /* 00183 Note that this API is less efficient than the one above, because 00184 it incurs TWO copies instead of none -- one when a temporary VInstant 00185 is created by the compiler to hold the return value, and one when 00186 that temporary VInstant is copied to the caller's lvalue. (Unless the 00187 compiler can optimize part of that away.) 00188 */ 00189 Vs64 value = this->readS64(); 00190 return VDuration::MILLISECOND() * value; 00191 } 00192 00193 Vs64 VBinaryIOStream::readDynamicCount() { 00194 // See comments below in writeDynamicCount for the format. 00195 00196 Vu8 lengthKind = this->readU8(); 00197 00198 if (lengthKind == THREE_BYTE_LENGTH_INDICATOR_BYTE) 00199 return (Vs64) this->readU16(); 00200 else if (lengthKind == FIVE_BYTE_LENGTH_INDICATOR_BYTE) 00201 return (Vs64) this->readU32(); 00202 else if (lengthKind == NINE_BYTE_LENGTH_INDICATOR_BYTE) 00203 return (Vs64) this->readU64(); 00204 else 00205 return (Vs64) lengthKind; 00206 } 00207 00208 void VBinaryIOStream::writeS8(Vs8 i) { 00209 Vs8 value = i; 00210 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(1)); 00211 } 00212 00213 void VBinaryIOStream::writeU8(Vu8 i) { 00214 Vu8 value = i; 00215 (void) this->write(&value, CONST_S64(1)); 00216 } 00217 00218 void VBinaryIOStream::writeS16(Vs16 i) { 00219 Vs16 value = i; 00220 V_BYTESWAP_HTON_S16_IN_PLACE(value); 00221 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(2)); 00222 } 00223 00224 void VBinaryIOStream::writeU16(Vu16 i) { 00225 Vu16 value = i; 00226 V_BYTESWAP_HTON_U16_IN_PLACE(value); 00227 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(2)); 00228 } 00229 00230 void VBinaryIOStream::writeS32(Vs32 i) { 00231 Vs32 value = i; 00232 V_BYTESWAP_HTON_S32_IN_PLACE(value); 00233 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(4)); 00234 } 00235 00236 void VBinaryIOStream::writeSize32(VSizeType i) { 00237 this->writeS32(static_cast<Vs32>(i)); 00238 } 00239 00240 void VBinaryIOStream::writeInt32(int i) { 00241 this->writeS32(static_cast<Vs32>(i)); 00242 } 00243 00244 void VBinaryIOStream::writeU32(Vu32 i) { 00245 Vu32 value = i; 00246 V_BYTESWAP_HTON_U32_IN_PLACE(value); 00247 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(4)); 00248 } 00249 00250 void VBinaryIOStream::writeS64(Vs64 i) { 00251 Vs64 value = i; 00252 V_BYTESWAP_HTON_S64_IN_PLACE(value); 00253 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(8)); 00254 } 00255 00256 void VBinaryIOStream::writeU64(Vu64 i) { 00257 Vu64 value = i; 00258 V_BYTESWAP_HTON_U64_IN_PLACE(value); 00259 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(8)); 00260 } 00261 00262 void VBinaryIOStream::writeFloat(VFloat f) { 00263 VFloat value = f; 00264 V_BYTESWAP_HTON_F_IN_PLACE(value); 00265 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(4)); 00266 } 00267 00268 void VBinaryIOStream::writeDouble(VDouble d) { 00269 VDouble value = d; 00270 V_BYTESWAP_HTON_D_IN_PLACE(value); 00271 (void) this->write(reinterpret_cast<Vu8*>(&value), CONST_S64(8)); 00272 } 00273 00274 void VBinaryIOStream::writeBool(bool i) { 00275 this->writeU8(i ? static_cast<Vu8>(1) : static_cast<Vu8>(0)); 00276 } 00277 00278 void VBinaryIOStream::writeString(const VString& s) { 00279 this->writeDynamicCount((Vs64) s.length()); 00280 (void) this->write(s.getDataBufferConst(), static_cast<Vs64>(s.length())); 00281 } 00282 00283 void VBinaryIOStream::writeString32(const VString& s) { 00284 this->writeS32((Vs32) s.length()); 00285 (void) this->write(s.getDataBufferConst(), static_cast<Vs64>(s.length())); 00286 } 00287 00288 void VBinaryIOStream::writeInstant(const VInstant& i) { 00289 this->writeS64(i.getValue()); 00290 } 00291 00292 void VBinaryIOStream::writeDuration(const VDuration& d) { 00293 this->writeS64(d.getDurationMilliseconds()); 00294 } 00295 00296 void VBinaryIOStream::writeDynamicCount(Vs64 count) { 00297 /* 00298 The idea here is use the least number of bytes possible to indicate a 00299 data length. 00300 We want to use 1 byte. Since we'll occasionally need to use that byte 00301 for a special indicator value, we can't quite go up to 255 in length 00302 indicator in 1 byte. We need 3 special indicator values, so we will use 00303 the values 255, 254, 253 for those. Thus in 1 byte we can indicate a 00304 length from 0 to 252. 00305 00306 So: 00307 00308 count from 0 to 252: 00309 write the count as 1 byte 00310 00311 count over 252 but fits in 16 bits: 00312 first byte contains 0xFF = 255 00313 next two bytes contain count as a U16 00314 00315 count too big for 16 bits but fits in 32 bits: 00316 first byte contains 0xFE = 254 00317 next four bytes contain count as a U32 00318 00319 otherwise: 00320 first byte contains 0xFD = 253 00321 next eight bytes contain count as a U64 00322 */ 00323 if (count <= MAX_ONE_BYTE_LENGTH) { 00324 this->writeU8(static_cast<Vu8>(count)); 00325 } else if (count <= V_MAX_U16) { 00326 this->writeU8(THREE_BYTE_LENGTH_INDICATOR_BYTE); 00327 this->writeU16(static_cast<Vu16>(count)); 00328 } else if (count <= V_MAX_U32) { 00329 this->writeU8(FIVE_BYTE_LENGTH_INDICATOR_BYTE); 00330 this->writeU32(static_cast<Vu32>(count)); 00331 } else { 00332 this->writeU8(NINE_BYTE_LENGTH_INDICATOR_BYTE); 00333 this->writeU64(static_cast<Vu64>(count)); 00334 } 00335 } 00336 00337 // static 00338 int VBinaryIOStream::getDynamicCountLength(Vs64 count) { 00339 if (count <= MAX_ONE_BYTE_LENGTH) { 00340 return 1; 00341 } else if (count <= V_MAX_U16) { 00342 return 3; 00343 } else if (count <= V_MAX_U32) { 00344 return 5; 00345 } else { 00346 return 9; 00347 } 00348 } 00349