Panda3D
 All Classes Functions Variables Enumerations
hashVal.cxx
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 #include <ctype.h>
00018 
00019 #ifdef HAVE_OPENSSL
00020 #include "openSSLWrapper.h"  // must be included before any other 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 
 All Classes Functions Variables Enumerations