Panda3D
 All Classes Functions Variables Enumerations
hashVal.cxx
1 // Filename: hashVal.cxx
2 // Created by: drose (14Nov00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "hashVal.h"
16 #include "virtualFileSystem.h"
17 #include <ctype.h>
18 
19 #ifdef HAVE_OPENSSL
20 #include "openSSLWrapper.h" // must be included before any other openssl.
21 #include "openssl/md5.h"
22 #endif // HAVE_OPENSSL
23 
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: HashVal::output_hex
27 // Access: Published
28 // Description: Outputs the HashVal as a 32-digit hexadecimal number.
29 ////////////////////////////////////////////////////////////////////
30 void HashVal::
31 output_hex(ostream &out) const {
32  char buffer[32];
33  encode_hex(_hv[0], buffer);
34  encode_hex(_hv[1], buffer + 8);
35  encode_hex(_hv[2], buffer + 16);
36  encode_hex(_hv[3], buffer + 24);
37  out.write(buffer, 32);
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: HashVal::input_hex
42 // Access: Published
43 // Description: Inputs the HashVal as a 32-digit hexadecimal number.
44 ////////////////////////////////////////////////////////////////////
45 void HashVal::
46 input_hex(istream &in) {
47  in >> ws;
48  char buffer[32];
49  size_t i = 0;
50  int ch = in.get();
51 
52  while (!in.eof() && !in.fail() && isxdigit(ch)) {
53  if (i < 32) {
54  buffer[i] = ch;
55  }
56  i++;
57  ch = in.get();
58  }
59 
60  if (i != 32) {
61  in.clear(ios::failbit|in.rdstate());
62  return;
63  }
64 
65  if (!in.eof()) {
66  in.putback(ch);
67  } else {
68  in.clear();
69  }
70 
71  decode_hex(buffer, _hv[0]);
72  decode_hex(buffer + 8, _hv[1]);
73  decode_hex(buffer + 16, _hv[2]);
74  decode_hex(buffer + 24, _hv[3]);
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: HashVal::output_binary
79 // Access: Published
80 // Description: Outputs the HashVal as a binary stream of bytes in
81 // order. This is not the same order generated by
82 // write_stream().
83 ////////////////////////////////////////////////////////////////////
84 void HashVal::
85 output_binary(ostream &out) const {
86  StreamWriter writer(out);
87  writer.add_be_uint32(_hv[0]);
88  writer.add_be_uint32(_hv[1]);
89  writer.add_be_uint32(_hv[2]);
90  writer.add_be_uint32(_hv[3]);
91 }
92 
93 ////////////////////////////////////////////////////////////////////
94 // Function: HashVal::input_binary
95 // Access: Published
96 // Description: Inputs the HashVal as a binary stream of bytes in
97 // order. This is not the same order expected by
98 // read_stream().
99 ////////////////////////////////////////////////////////////////////
100 void HashVal::
101 input_binary(istream &in) {
102  StreamReader reader(in);
103  _hv[0] = reader.get_be_uint32();
104  _hv[1] = reader.get_be_uint32();
105  _hv[2] = reader.get_be_uint32();
106  _hv[3] = reader.get_be_uint32();
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: HashVal::as_dec
111 // Access: Published
112 // Description: Returns the HashVal as a string with four decimal
113 // numbers.
114 ////////////////////////////////////////////////////////////////////
115 string HashVal::
116 as_dec() const {
117  ostringstream strm;
118  output_dec(strm);
119  return strm.str();
120 }
121 
122 ////////////////////////////////////////////////////////////////////
123 // Function: HashVal::set_from_dec
124 // Access: Published
125 // Description: Sets the HashVal from a string with four decimal
126 // numbers. Returns true if valid, false otherwise.
127 ////////////////////////////////////////////////////////////////////
128 bool HashVal::
129 set_from_dec(const string &text) {
130  istringstream strm(text);
131  input_dec(strm);
132  return !strm.fail();
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: HashVal::as_hex
137 // Access: Published
138 // Description: Returns the HashVal as a 32-byte hexadecimal string.
139 ////////////////////////////////////////////////////////////////////
140 string HashVal::
141 as_hex() const {
142  char buffer[32];
143  encode_hex(_hv[0], buffer);
144  encode_hex(_hv[1], buffer + 8);
145  encode_hex(_hv[2], buffer + 16);
146  encode_hex(_hv[3], buffer + 24);
147  return string(buffer, 32);
148 }
149 
150 ////////////////////////////////////////////////////////////////////
151 // Function: HashVal::set_from_hex
152 // Access: Published
153 // Description: Sets the HashVal from a 32-byte hexademical string.
154 // Returns true if successful, false otherwise.
155 ////////////////////////////////////////////////////////////////////
156 bool HashVal::
157 set_from_hex(const string &text) {
158  istringstream strm(text);
159  input_hex(strm);
160  return !strm.fail();
161 }
162 
163 ////////////////////////////////////////////////////////////////////
164 // Function: HashVal::as_bin
165 // Access: Published
166 // Description: Returns the HashVal as a 16-byte binary string.
167 ////////////////////////////////////////////////////////////////////
168 string HashVal::
169 as_bin() const {
170  Datagram dg;
171  write_datagram(dg);
172  return dg.get_message();
173 }
174 
175 ////////////////////////////////////////////////////////////////////
176 // Function: HashVal::set_from_bin
177 // Access: Published
178 // Description: Sets the HashVal from a 16-byte binary string.
179 // Returns true if successful, false otherwise.
180 ////////////////////////////////////////////////////////////////////
181 bool HashVal::
182 set_from_bin(const string &text) {
183  nassertr(text.size() == 16, false);
184  Datagram dg(text);
185  DatagramIterator dgi(dg);
186  read_datagram(dgi);
187  return true;
188 }
189 
190 #ifdef HAVE_OPENSSL
191 ////////////////////////////////////////////////////////////////////
192 // Function: HashVal::hash_file
193 // Access: Published
194 // Description: Generates the hash value from the indicated file.
195 // Returns true on success, false if the file cannot be
196 // read. This method is only defined if we have the
197 // OpenSSL library (which provides md5 functionality)
198 // available.
199 ////////////////////////////////////////////////////////////////////
200 bool HashVal::
201 hash_file(const Filename &filename) {
202  Filename bin_filename = Filename::binary_filename(filename);
204  istream *istr = vfs->open_read_file(bin_filename, false);
205  if (istr == (istream *)NULL) {
206  (*this) = HashVal();
207  return false;
208  }
209 
210  bool result = hash_stream(*istr);
211  vfs->close_read_file(istr);
212 
213  return result;
214 }
215 #endif // HAVE_OPENSSL
216 
217 #ifdef HAVE_OPENSSL
218 ////////////////////////////////////////////////////////////////////
219 // Function: HashVal::hash_stream
220 // Access: Published
221 // Description: Generates the hash value from the indicated file.
222 // Returns true on success, false if the file cannot be
223 // read. This method is only defined if we have the
224 // OpenSSL library (which provides md5 functionality)
225 // available.
226 ////////////////////////////////////////////////////////////////////
227 bool HashVal::
228 hash_stream(istream &stream) {
229  unsigned char md[16];
230 
231  MD5_CTX ctx;
232  MD5_Init(&ctx);
233 
234  static const int buffer_size = 1024;
235  char buffer[buffer_size];
236 
237  // Seek the stream to the beginning in case it wasn't there already.
238  stream.seekg(0, ios::beg);
239 
240  stream.read(buffer, buffer_size);
241  size_t count = stream.gcount();
242  while (count != 0) {
243  MD5_Update(&ctx, buffer, count);
244  stream.read(buffer, buffer_size);
245  count = stream.gcount();
246  }
247 
248  // Clear the fail bit so the caller can still read the stream (if it
249  // wants to).
250  stream.clear();
251 
252  MD5_Final(md, &ctx);
253 
254  // Store the individual bytes as big-endian ints, from historical
255  // convention.
256  _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
257  _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
258  _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
259  _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
260 
261  return true;
262 }
263 #endif // HAVE_OPENSSL
264 
265 
266 #ifdef HAVE_OPENSSL
267 ////////////////////////////////////////////////////////////////////
268 // Function: HashVal::hash_buffer
269 // Access: Published
270 // Description: Generates the hash value by hashing the indicated
271 // data. This method is only defined if we have the
272 // OpenSSL library (which provides md5 functionality)
273 // available.
274 ////////////////////////////////////////////////////////////////////
275 void HashVal::
276 hash_buffer(const char *buffer, int length) {
277  unsigned char md[16];
278  MD5((const unsigned char *)buffer, length, md);
279 
280  // Store the individual bytes as big-endian ints, from historical
281  // convention.
282  _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
283  _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
284  _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
285  _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
286 }
287 
288 #endif // HAVE_OPENSSL
289 
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: HashVal::encode_hex
293 // Access: Private, Static
294 // Description: Encodes the indicated unsigned int into an
295 // eight-digit hex string, stored at the indicated
296 // buffer and the following 8 positions.
297 ////////////////////////////////////////////////////////////////////
298 void HashVal::
299 encode_hex(PN_uint32 val, char *buffer) {
300  buffer[0] = tohex(val >> 28);
301  buffer[1] = tohex(val >> 24);
302  buffer[2] = tohex(val >> 20);
303  buffer[3] = tohex(val >> 16);
304  buffer[4] = tohex(val >> 12);
305  buffer[5] = tohex(val >> 8);
306  buffer[6] = tohex(val >> 4);
307  buffer[7] = tohex(val);
308 }
309 
310 ////////////////////////////////////////////////////////////////////
311 // Function: HashVal::decode_hex
312 // Access: Private, Static
313 // Description: Decodes the indicated eight-digit hex string into an
314 // unsigned integer.
315 ////////////////////////////////////////////////////////////////////
316 void HashVal::
317 decode_hex(const char *buffer, PN_uint32 &val) {
318  unsigned int bytes[8];
319  for (int i = 0; i < 8; i++) {
320  bytes[i] = fromhex(buffer[i]);
321  }
322 
323  val = ((bytes[0] << 28) |
324  (bytes[1] << 24) |
325  (bytes[2] << 20) |
326  (bytes[3] << 16) |
327  (bytes[4] << 12) |
328  (bytes[5] << 8) |
329  (bytes[6] << 4) |
330  (bytes[7]));
331 }
332 
A StreamWriter object is used to write sequential binary data directly to an ostream.
Definition: streamWriter.h:33
string get_message() const
Returns the datagram&#39;s data as a string.
Definition: datagram.I:431
void input_dec(istream &in)
Inputs the HashVal as four unsigned decimal integers.
Definition: hashVal.I:135
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
string as_dec() const
Returns the HashVal as a string with four decimal numbers.
Definition: hashVal.cxx:116
Stores a 128-bit value that represents the hashed contents (typically MD5) of a file or buffer...
Definition: hashVal.h:32
bool set_from_hex(const string &text)
Sets the HashVal from a 32-byte hexademical string.
Definition: hashVal.cxx:157
void input_hex(istream &in)
Inputs the HashVal as a 32-digit hexadecimal number.
Definition: hashVal.cxx:46
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
bool set_from_dec(const string &text)
Sets the HashVal from a string with four decimal numbers.
Definition: hashVal.cxx:129
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void add_be_uint32(PN_uint32 value)
Adds an unsigned 32-bit big-endian integer to the streamWriter.
Definition: streamWriter.I:270
void output_hex(ostream &out) const
Outputs the HashVal as a 32-digit hexadecimal number.
Definition: hashVal.cxx:31
bool set_from_bin(const string &text)
Sets the HashVal from a 16-byte binary string.
Definition: hashVal.cxx:182
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void output_dec(ostream &out) const
Outputs the HashVal as four unsigned decimal integers.
Definition: hashVal.I:125
void output_binary(ostream &out) const
Outputs the HashVal as a binary stream of bytes in order.
Definition: hashVal.cxx:85
istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read...
string as_bin() const
Returns the HashVal as a 16-byte binary string.
Definition: hashVal.cxx:169
A class to retrieve the individual data elements previously stored in a Datagram. ...
string as_hex() const
Returns the HashVal as a 32-byte hexadecimal string.
Definition: hashVal.cxx:141
A class to read sequential binary data directly from an istream.
Definition: streamReader.h:30
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
PN_uint32 get_be_uint32()
Extracts an unsigned big-endian 32-bit integer.
Definition: streamReader.I:303
void input_binary(istream &in)
Inputs the HashVal as a binary stream of bytes in order.
Definition: hashVal.cxx:101