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 (ch != 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 (ch != 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,...
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's data.
Definition: datagram.I:327