Vault  4.1
vbinaryiostream.cpp
Go to the documentation of this file.
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 

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.