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