diff --git a/Code/DataStructs/BitVect.cpp b/Code/DataStructs/BitVect.cpp index f389fe541..49a8d023a 100644 --- a/Code/DataStructs/BitVect.cpp +++ b/Code/DataStructs/BitVect.cpp @@ -40,7 +40,7 @@ void BitVect::initFromText(const char *data,const unsigned int dataLen, // earlier versions of the code did not have the version number encoded, so // we'll use that to distinguish version 0 - ss.read((char *)&size,sizeof(size)); + RDKit::streamRead(ss,size); if(size<0){ version = -1*size; if (version == 16) { @@ -52,12 +52,11 @@ void BitVect::initFromText(const char *data,const unsigned int dataLen, else { throw ValueErrorException("bad version in BitVect pickle"); } - - ss.read((char *)&size,sizeof(size)); + RDKit::streamRead(ss,size); } else if( !allowOldFormat ) { throw ValueErrorException("invalid BitVect pickle"); } - ss.read((char *)&nOn,sizeof(nOn)); + RDKit::streamRead(ss,nOn); _initForSize(static_cast(size)); // if the either have older version or or version 16 with ints for on bits @@ -65,13 +64,13 @@ void BitVect::initFromText(const char *data,const unsigned int dataLen, ( (format == 1) && (size >= std::numeric_limits::max()) ) ) { boost::uint32_t tmp; for(unsigned int i=0; i(d_data.get()[i]); + ss.write((const char *)td,d_numInts*sizeof(tInt)); + delete [] td; +#else ss.write((const char *)d_data.get(),d_numInts*sizeof(tInt)); - +#endif std::string res(ss.str()); return res; }; @@ -177,7 +184,15 @@ namespace RDKit { d_numInts=tInt; boost::uint32_t *data = new boost::uint32_t[d_numInts]; ss.read((char *)data,d_numInts*sizeof(boost::uint32_t)); + +#if defined(BOOST_BIG_ENDIAN) + boost::uint32_t *td = new boost::uint32_t[d_numInts]; + for(unsigned int i=0;i(data[i]); + d_data.reset(td); + delete [] data; +#else d_data.reset(data); +#endif }; diff --git a/Code/DataStructs/testDatastructs.cpp b/Code/DataStructs/testDatastructs.cpp index 39390a6ee..e6d1a4f72 100644 --- a/Code/DataStructs/testDatastructs.cpp +++ b/Code/DataStructs/testDatastructs.cpp @@ -1174,15 +1174,9 @@ int main(){ ss.write((const char *)&v1,sizeof(v1)); ss.write((const char *)&v2,sizeof(v2)); -#if 0 - ss.close(); - fstream ss2("blah.bin",ios_base::binary|ios_base::in); - ss2.read((char *)&v3,sizeof(v3)); - ss2.read((char *)&v4,sizeof(v4)); -#endif ss.seekp(0,ios_base::beg); - ss.read((char *)&v3,sizeof(v3)); - ss.read((char *)&v4,sizeof(v4)); + RDKit::streamRead(ss,v3); + RDKit::streamRead(ss,v4); TXTMSG("v3",v3); TXTMSG("v4",v4); diff --git a/Code/RDGeneral/StreamOps.h b/Code/RDGeneral/StreamOps.h index 1c1995e94..93307ed87 100644 --- a/Code/RDGeneral/StreamOps.h +++ b/Code/RDGeneral/StreamOps.h @@ -16,10 +16,72 @@ #include #include #include - +#include namespace RDKit{ - + // this code block for handling endian problems is from : + // http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c + enum EEndian + { + LITTLE_ENDIAN_ORDER, + BIG_ENDIAN_ORDER, +#if defined(BOOST_LITTLE_ENDIAN) + HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER +#elif defined(BOOST_BIG_ENDIAN) + HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER +#else +#error "Failed to determine the system endian value" +#endif + }; + + // this function swap the bytes of values given it's size as a template + // parameter (could sizeof be used?). + template + inline T SwapBytes(T value) + { + union + { + T value; + char bytes[size]; + } in, out; + + in.value = value; + + for (unsigned int i = 0; i < size / 2; ++i) + { + out.bytes[i] = in.bytes[size - 1 - i]; + out.bytes[size - 1 - i] = in.bytes[i]; + } + + return out.value; + } + + // Here is the function you will use. Again there is two compile-time assertion + // that use the boost librarie. You could probably comment them out, but if you + // do be cautious not to use this function for anything else than integers + // types. This function need to be calles like this : + // + // int x = someValue; + // int i = EndianSwapBytes(x); + // + template + inline T EndianSwapBytes(T value) + { + // A : La donnée à swapper à une taille de 2, 4 ou 8 octets + BOOST_STATIC_ASSERT(sizeof(T)==1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8); + if(sizeof(T)==1) return value; + + // A : La donnée à swapper est d'un type arithmetic + //BOOST_STATIC_ASSERT(boost::is_arithmetic::value); + + // Si from et to sont du même type on ne swap pas. + if (from == to) + return value; + + return SwapBytes(value); + } + // -------------------------------------- + //! Packs an integer and outputs it to a stream inline void appendPackedIntToStream(std::stringstream &ss, boost::uint32_t num) { int nbytes, bix; @@ -27,7 +89,7 @@ namespace RDKit{ char tc; CHECK_INVARIANT(num >= 0, ""); - res = num; + res = EndianSwapBytes(num); while (1) { if (res < (1<<7)) { val = (res<<1); @@ -100,6 +162,7 @@ namespace RDKit{ offset = (1<<7) + (1<<14) + (1<<21); } num = (val >> shift) + offset; + num = EndianSwapBytes(num); return num; } @@ -147,18 +210,22 @@ namespace RDKit{ offset = (1<<7) + (1<<14) + (1<<21); } num = (val >> shift) + offset; + num = EndianSwapBytes(num); return num; } //! does a binary write of an object to a stream template void streamWrite(std::ostream &ss,const T &val){ - ss.write((const char *)&val,sizeof(T)); + T tval=EndianSwapBytes(val); + ss.write((const char *)&tval,sizeof(T)); } //! does a binary read of an object from a stream template void streamRead(std::istream &ss,T &loc){ - ss.read((char *)&loc,sizeof(T)); + T tloc; + ss.read((char *)&tloc,sizeof(T)); + loc = EndianSwapBytes(tloc); } //! grabs the next line from an instream and returns it.