Panda3D
|
00001 // Filename: hashVal.cxx 00002 // Created by: drose (14Nov00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "hashVal.h" 00016 #include "virtualFileSystem.h" 00017 00018 #include <ctype.h> 00019 00020 #ifdef HAVE_OPENSSL 00021 #include "openssl/md5.h" 00022 #endif // HAVE_OPENSSL 00023 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: HashVal::output_hex 00027 // Access: Published 00028 // Description: Outputs the HashVal as a 32-digit hexadecimal number. 00029 //////////////////////////////////////////////////////////////////// 00030 void HashVal:: 00031 output_hex(ostream &out) const { 00032 char buffer[32]; 00033 encode_hex(_hv[0], buffer); 00034 encode_hex(_hv[1], buffer + 8); 00035 encode_hex(_hv[2], buffer + 16); 00036 encode_hex(_hv[3], buffer + 24); 00037 out.write(buffer, 32); 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: HashVal::input_hex 00042 // Access: Published 00043 // Description: Inputs the HashVal as a 32-digit hexadecimal number. 00044 //////////////////////////////////////////////////////////////////// 00045 void HashVal:: 00046 input_hex(istream &in) { 00047 in >> ws; 00048 char buffer[32]; 00049 size_t i = 0; 00050 int ch = in.get(); 00051 00052 while (!in.eof() && !in.fail() && isxdigit(ch)) { 00053 if (i < 32) { 00054 buffer[i] = ch; 00055 } 00056 i++; 00057 ch = in.get(); 00058 } 00059 00060 if (i != 32) { 00061 in.clear(ios::failbit|in.rdstate()); 00062 return; 00063 } 00064 00065 if (!in.eof()) { 00066 in.putback(ch); 00067 } else { 00068 in.clear(); 00069 } 00070 00071 decode_hex(buffer, _hv[0]); 00072 decode_hex(buffer + 8, _hv[1]); 00073 decode_hex(buffer + 16, _hv[2]); 00074 decode_hex(buffer + 24, _hv[3]); 00075 } 00076 00077 //////////////////////////////////////////////////////////////////// 00078 // Function: HashVal::output_binary 00079 // Access: Published 00080 // Description: Outputs the HashVal as a binary stream of bytes in 00081 // order. This is not the same order generated by 00082 // write_stream(). 00083 //////////////////////////////////////////////////////////////////// 00084 void HashVal:: 00085 output_binary(ostream &out) const { 00086 StreamWriter writer(out); 00087 writer.add_be_uint32(_hv[0]); 00088 writer.add_be_uint32(_hv[1]); 00089 writer.add_be_uint32(_hv[2]); 00090 writer.add_be_uint32(_hv[3]); 00091 } 00092 00093 //////////////////////////////////////////////////////////////////// 00094 // Function: HashVal::input_binary 00095 // Access: Published 00096 // Description: Inputs the HashVal as a binary stream of bytes in 00097 // order. This is not the same order expected by 00098 // read_stream(). 00099 //////////////////////////////////////////////////////////////////// 00100 void HashVal:: 00101 input_binary(istream &in) { 00102 StreamReader reader(in); 00103 _hv[0] = reader.get_be_uint32(); 00104 _hv[1] = reader.get_be_uint32(); 00105 _hv[2] = reader.get_be_uint32(); 00106 _hv[3] = reader.get_be_uint32(); 00107 } 00108 00109 //////////////////////////////////////////////////////////////////// 00110 // Function: HashVal::as_dec 00111 // Access: Published 00112 // Description: Returns the HashVal as a string with four decimal 00113 // numbers. 00114 //////////////////////////////////////////////////////////////////// 00115 string HashVal:: 00116 as_dec() const { 00117 ostringstream strm; 00118 output_dec(strm); 00119 return strm.str(); 00120 } 00121 00122 //////////////////////////////////////////////////////////////////// 00123 // Function: HashVal::set_from_dec 00124 // Access: Published 00125 // Description: Sets the HashVal from a string with four decimal 00126 // numbers. Returns true if valid, false otherwise. 00127 //////////////////////////////////////////////////////////////////// 00128 bool HashVal:: 00129 set_from_dec(const string &text) { 00130 istringstream strm(text); 00131 input_dec(strm); 00132 return !strm.fail(); 00133 } 00134 00135 //////////////////////////////////////////////////////////////////// 00136 // Function: HashVal::as_hex 00137 // Access: Published 00138 // Description: Returns the HashVal as a 32-byte hexadecimal string. 00139 //////////////////////////////////////////////////////////////////// 00140 string HashVal:: 00141 as_hex() const { 00142 char buffer[32]; 00143 encode_hex(_hv[0], buffer); 00144 encode_hex(_hv[1], buffer + 8); 00145 encode_hex(_hv[2], buffer + 16); 00146 encode_hex(_hv[3], buffer + 24); 00147 return string(buffer, 32); 00148 } 00149 00150 //////////////////////////////////////////////////////////////////// 00151 // Function: HashVal::set_from_hex 00152 // Access: Published 00153 // Description: Sets the HashVal from a 32-byte hexademical string. 00154 // Returns true if successful, false otherwise. 00155 //////////////////////////////////////////////////////////////////// 00156 bool HashVal:: 00157 set_from_hex(const string &text) { 00158 istringstream strm(text); 00159 input_hex(strm); 00160 return !strm.fail(); 00161 } 00162 00163 //////////////////////////////////////////////////////////////////// 00164 // Function: HashVal::as_bin 00165 // Access: Published 00166 // Description: Returns the HashVal as a 16-byte binary string. 00167 //////////////////////////////////////////////////////////////////// 00168 string HashVal:: 00169 as_bin() const { 00170 Datagram dg; 00171 write_datagram(dg); 00172 return dg.get_message(); 00173 } 00174 00175 //////////////////////////////////////////////////////////////////// 00176 // Function: HashVal::set_from_bin 00177 // Access: Published 00178 // Description: Sets the HashVal from a 16-byte binary string. 00179 // Returns true if successful, false otherwise. 00180 //////////////////////////////////////////////////////////////////// 00181 bool HashVal:: 00182 set_from_bin(const string &text) { 00183 nassertr(text.size() == 16, false); 00184 Datagram dg(text); 00185 DatagramIterator dgi(dg); 00186 read_datagram(dgi); 00187 return true; 00188 } 00189 00190 #ifdef HAVE_OPENSSL 00191 //////////////////////////////////////////////////////////////////// 00192 // Function: HashVal::hash_file 00193 // Access: Published 00194 // Description: Generates the hash value from the indicated file. 00195 // Returns true on success, false if the file cannot be 00196 // read. This method is only defined if we have the 00197 // OpenSSL library (which provides md5 functionality) 00198 // available. 00199 //////////////////////////////////////////////////////////////////// 00200 bool HashVal:: 00201 hash_file(const Filename &filename) { 00202 Filename bin_filename = Filename::binary_filename(filename); 00203 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00204 istream *istr = vfs->open_read_file(bin_filename, false); 00205 if (istr == (istream *)NULL) { 00206 (*this) = HashVal(); 00207 return false; 00208 } 00209 00210 bool result = hash_stream(*istr); 00211 vfs->close_read_file(istr); 00212 00213 return result; 00214 } 00215 #endif // HAVE_OPENSSL 00216 00217 #ifdef HAVE_OPENSSL 00218 //////////////////////////////////////////////////////////////////// 00219 // Function: HashVal::hash_stream 00220 // Access: Published 00221 // Description: Generates the hash value from the indicated file. 00222 // Returns true on success, false if the file cannot be 00223 // read. This method is only defined if we have the 00224 // OpenSSL library (which provides md5 functionality) 00225 // available. 00226 //////////////////////////////////////////////////////////////////// 00227 bool HashVal:: 00228 hash_stream(istream &stream) { 00229 unsigned char md[16]; 00230 00231 MD5_CTX ctx; 00232 MD5_Init(&ctx); 00233 00234 static const int buffer_size = 1024; 00235 char buffer[buffer_size]; 00236 00237 // Seek the stream to the beginning in case it wasn't there already. 00238 stream.seekg(0, ios::beg); 00239 00240 stream.read(buffer, buffer_size); 00241 size_t count = stream.gcount(); 00242 while (count != 0) { 00243 MD5_Update(&ctx, buffer, count); 00244 stream.read(buffer, buffer_size); 00245 count = stream.gcount(); 00246 } 00247 00248 // Clear the fail bit so the caller can still read the stream (if it 00249 // wants to). 00250 stream.clear(); 00251 00252 MD5_Final(md, &ctx); 00253 00254 // Store the individual bytes as big-endian ints, from historical 00255 // convention. 00256 _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]); 00257 _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]); 00258 _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]); 00259 _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]); 00260 00261 return true; 00262 } 00263 #endif // HAVE_OPENSSL 00264 00265 00266 #ifdef HAVE_OPENSSL 00267 //////////////////////////////////////////////////////////////////// 00268 // Function: HashVal::hash_buffer 00269 // Access: Published 00270 // Description: Generates the hash value by hashing the indicated 00271 // data. This method is only defined if we have the 00272 // OpenSSL library (which provides md5 functionality) 00273 // available. 00274 //////////////////////////////////////////////////////////////////// 00275 void HashVal:: 00276 hash_buffer(const char *buffer, int length) { 00277 unsigned char md[16]; 00278 MD5((const unsigned char *)buffer, length, md); 00279 00280 // Store the individual bytes as big-endian ints, from historical 00281 // convention. 00282 _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]); 00283 _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]); 00284 _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]); 00285 _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]); 00286 } 00287 00288 #endif // HAVE_OPENSSL 00289 00290 00291 //////////////////////////////////////////////////////////////////// 00292 // Function: HashVal::encode_hex 00293 // Access: Private, Static 00294 // Description: Encodes the indicated unsigned int into an 00295 // eight-digit hex string, stored at the indicated 00296 // buffer and the following 8 positions. 00297 //////////////////////////////////////////////////////////////////// 00298 void HashVal:: 00299 encode_hex(PN_uint32 val, char *buffer) { 00300 buffer[0] = tohex(val >> 28); 00301 buffer[1] = tohex(val >> 24); 00302 buffer[2] = tohex(val >> 20); 00303 buffer[3] = tohex(val >> 16); 00304 buffer[4] = tohex(val >> 12); 00305 buffer[5] = tohex(val >> 8); 00306 buffer[6] = tohex(val >> 4); 00307 buffer[7] = tohex(val); 00308 } 00309 00310 //////////////////////////////////////////////////////////////////// 00311 // Function: HashVal::decode_hex 00312 // Access: Private, Static 00313 // Description: Decodes the indicated eight-digit hex string into an 00314 // unsigned integer. 00315 //////////////////////////////////////////////////////////////////// 00316 void HashVal:: 00317 decode_hex(const char *buffer, PN_uint32 &val) { 00318 unsigned int bytes[8]; 00319 for (int i = 0; i < 8; i++) { 00320 bytes[i] = fromhex(buffer[i]); 00321 } 00322 00323 val = ((bytes[0] << 28) | 00324 (bytes[1] << 24) | 00325 (bytes[2] << 20) | 00326 (bytes[3] << 16) | 00327 (bytes[4] << 12) | 00328 (bytes[5] << 8) | 00329 (bytes[6] << 4) | 00330 (bytes[7])); 00331 } 00332