blocxx

BinarySerialization.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2006, Novell, Inc. All rights reserved.
00004 * 
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 * 
00008 *     * Redistributions of source code must retain the above copyright notice,
00009 *       this list of conditions and the following disclaimer.
00010 *     * Redistributions in binary form must reproduce the above copyright
00011 *       notice, this list of conditions and the following disclaimer in the
00012 *       documentation and/or other materials provided with the distribution.
00013 *     * Neither the name of 
00014 *       Vintela, Inc., 
00015 *       nor Novell, Inc., 
00016 *       nor the names of its contributors or employees may be used to 
00017 *       endorse or promote products derived from this software without 
00018 *       specific prior written permission.
00019 * 
00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00030 * POSSIBILITY OF SUCH DAMAGE.
00031 *******************************************************************************/
00032 
00033 
00039 #include "blocxx/BLOCXX_config.h"
00040 #include "blocxx/BinarySerialization.hpp"
00041 #include "blocxx/AutoPtr.hpp"
00042 #include "blocxx/ByteSwap.hpp"
00043 #include "blocxx/IOException.hpp"
00044 #include "blocxx/Format.hpp"
00045 #include <cerrno>
00046 
00047 namespace BLOCXX_NAMESPACE
00048 {
00049 
00050 namespace BinarySerialization
00051 {
00053 // STATIC
00054 void
00055 writeLen(std::streambuf & ostrm, UInt32 len)
00056 {
00057    // This is ASN.1 length encoding
00058    /*
00059     * short len if it's less than 128 - one byte giving the len,
00060     * with bit 8 0.
00061     */
00062    if (len < 128)
00063    {
00064       UInt8 length_byte = static_cast<UInt8>(len);
00065       write(ostrm, &length_byte, 1);
00066       return;
00067    }
00068    /*
00069     * long len otherwise - one byte with bit 8 set, giving the
00070     * length of the length, followed by the length itself.
00071     */
00072    /* find the first non-all-zero byte */
00073    UInt8 lenlen;
00074    if (len < (1 << 8))
00075    {
00076       lenlen = 1;
00077    }
00078    else if (len < (1 << 16))
00079    {
00080       lenlen = 2;
00081    }
00082    else if (len < (1 << 24))
00083    {
00084       lenlen = 3;
00085    }
00086    else
00087    {
00088       lenlen = 4;
00089    }
00090    UInt8 netlenlen = lenlen | 0x80UL;
00091    /* write the length of the length */
00092    write(ostrm, &netlenlen, 1);
00093    UInt8 netlen[sizeof(len)];
00094    for (int j = 0; j < lenlen; j++)
00095    {
00096       netlen[(sizeof(len)-1) - j] = static_cast<UInt8>(len & 0xffU);
00097       len >>= 8;
00098    }
00099    /* write the length itself */
00100    write(ostrm, static_cast<void *>(&netlen[sizeof(len)-lenlen]), lenlen);
00101 }
00103 // STATIC
00104 void
00105 readLen(std::streambuf & istrm, UInt32 & len)
00106 {
00107    // This is ASN.1 length encoding
00108    UInt8 lc;
00109    read(istrm, lc);
00110    if (lc & 0x80U) 
00111    {
00112       UInt8 noctets = lc & 0x7fU;
00113       if ( noctets > sizeof(len) ) 
00114       {
00115          BLOCXX_THROW(IOException, Format("Failed reading data: length length (%1) is too large (> %2)", static_cast<int>(noctets), sizeof(len)).c_str());
00116       }
00117       UInt8 netlen[sizeof(len)];
00118       read(istrm, static_cast<void *>(netlen), noctets);
00119       len = 0;
00120       for (int i = 0; i < noctets; i++ ) 
00121       {
00122          len <<= 8;
00123          len |= netlen[i];
00124       }
00125    } 
00126    else 
00127    {
00128       len = lc;
00129    }
00130 }
00132 // STATIC
00133 void
00134 write(std::streambuf & ostrm, void const * dataOut, size_t dataOutLen)
00135 {
00136    std::streamsize cnt = dataOutLen;
00137    if (ostrm.sputn(static_cast<char const *>(dataOut), cnt) != cnt)
00138    {
00139       BLOCXX_THROW_ERRNO_MSG(IOException, "Failed writing data");
00140    }
00141 }
00143 // STATIC
00144 void
00145 verifySignature(std::streambuf & istrm, UInt8 validSig)
00146 {
00147    UInt8 val;
00148    read(istrm, val);
00149    if (val != validSig)
00150    {
00151       BLOCXX_THROW(BadSignatureException,
00152          Format("Received invalid signature. Got: %1 Expected: %2", Int32(val),
00153             Int32(validSig)).c_str());
00154    }
00155 }
00157 // STATIC
00158 void
00159 writeStringArray(std::streambuf & ostrm, const StringArray * propertyList)
00160 {
00161    bool nullPropertyList = (propertyList == 0);
00162    writeBool(ostrm, nullPropertyList);
00163    if (!nullPropertyList)
00164    {
00165       writeStringArray(ostrm, *propertyList);
00166    }
00167 }
00169 // STATIC
00170 void
00171 read(std::streambuf & istrm, void * dataIn, size_t dataInLen)
00172 {
00173    std::streamsize cnt = dataInLen;
00174    if (istrm.sgetn(static_cast<char *>(dataIn), cnt) != cnt)
00175    {
00176       BLOCXX_THROW(IOException, "Failed reading data");
00177    }
00178 }
00179 
00180 } // namespace BinarySerialization
00181 
00182 } // end namespace BLOCXX_NAMESPACE
00183