00001 /* 00002 Ishtar - A network transparent read/write interface with 00003 probing and enumeration support. 00004 network part : convenient cross-platform packaging for tcp/ip networking 00005 Copyright (C) 2003-2005 Stephane Magnenat <stephane at magnenat dot net> 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program; if not, write to the Free Software 00019 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 */ 00021 00022 #ifndef __ISHTAR_STREAM_H 00023 #define __ISHTAR_STREAM_H 00024 00025 #include <algorithm> 00026 00055 00056 namespace Ishtar 00057 { 00059 typedef signed char Int8; 00061 typedef unsigned char UInt8; 00063 typedef signed short Int16; 00065 typedef unsigned short UInt16; 00067 typedef signed int Int32; 00069 typedef unsigned int UInt32; 00071 typedef size_t Size; 00072 00074 struct EndianDiscoverer 00075 { 00077 bool isLittleEndian; 00079 bool isInvertedDouble; 00080 00082 EndianDiscoverer(); 00083 }; 00084 00086 extern EndianDiscoverer endianDiscoverer; 00087 00089 template<typename T> void swapBytesIfRequired(T &v) 00090 { 00091 // we save files in little endian as most user architecture are little endian 00092 if (!endianDiscoverer.isLittleEndian) 00093 { 00094 UInt8 *data = reinterpret_cast<UInt8 *>(&v); 00095 Size size = sizeof(T); 00096 for(Size p = 0; p < (size>>1); p++) 00097 std::swap(data[p], data[size-1-p]); 00098 } 00099 } 00100 00101 // Endian safe read and write 00102 // ========================== 00103 00105 class OutputStream 00106 { 00107 public: 00109 virtual ~OutputStream() { } 00110 00112 virtual void write(const void *data, const Size size) = 0; 00113 00115 virtual void flush(void) = 0; 00116 00118 template<typename T> void writeEndianIndependant(const T &v) 00119 { 00120 T swapedValue = v; 00121 swapBytesIfRequired(swapedValue); 00122 write(&swapedValue, sizeof(T)); 00123 } 00124 00126 inline void writeInt8(const Int8 v) { this->write(&v, 1); } 00128 inline void writeUInt8(const UInt8 v) { this->write(&v, 1); } 00130 inline void writeInt16(const Int16 v) { this->writeEndianIndependant(v); } 00132 inline void writeUInt16(const UInt16 v) { this->writeEndianIndependant(v); } 00134 inline void writeInt32(const Int32 v) { this->writeEndianIndependant(v); } 00136 inline void writeUInt32(const UInt32 v) { this->writeEndianIndependant(v); } 00138 inline void writeFloat(const float v) { this->writeEndianIndependant(v); } 00140 inline void writeDouble(const double v) 00141 { 00142 double value = v; 00143 // arm inverted double forces us to do this 00144 if (endianDiscoverer.isInvertedDouble) 00145 { 00146 UInt32 *ptr = reinterpret_cast<UInt32 *>(&value); 00147 UInt32 tempValue = *ptr; 00148 *ptr = *(ptr+1); 00149 *(ptr+1) = tempValue; 00150 } 00151 this->writeEndianIndependant(value); 00152 } 00153 }; 00154 00156 class InputStream 00157 { 00158 public: 00160 virtual ~InputStream() { } 00161 00163 virtual void read(void *data, Size size) = 0; 00164 00166 template<typename T> T readEndianIndependant() 00167 { 00168 T v; 00169 read(&v, sizeof(T)); 00170 swapBytesIfRequired(v); 00171 return v; 00172 } 00173 00175 inline Int8 readInt8(void) { Int8 i; this->read(&i, 1); return i; } 00177 inline UInt8 readUInt8(void) { UInt8 i; this->read(&i, 1); return i; } 00179 inline Int16 readInt16(void) { return this->readEndianIndependant<Int16>(); } 00181 inline UInt16 readUInt16(void) { return this->readEndianIndependant<UInt16>(); } 00183 inline Int32 readInt32(void) { return this->readEndianIndependant<Int32>(); } 00185 inline UInt32 readUInt32(void) { return this->readEndianIndependant<UInt32>(); } 00187 inline float readFloat(void) { return this->readEndianIndependant<float>(); } 00189 inline double readDouble(void) 00190 { 00191 double value = this->readEndianIndependant<double>(); 00192 // arm inverted double forces us to do this 00193 if (endianDiscoverer.isInvertedDouble) 00194 { 00195 UInt32 *ptr = reinterpret_cast<UInt32 *>(&value); 00196 UInt32 tempValue = *ptr; 00197 *ptr = *(ptr+1); 00198 *(ptr+1) = tempValue; 00199 } 00200 return value; 00201 } 00202 }; 00203 } 00204 00205 #endif