1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/block_graph/block_hash.h"
16 :
17 : namespace block_graph {
18 :
19 : using base::MD5Context;
20 : using base::MD5Final;
21 : using base::MD5Init;
22 : using base::MD5Update;
23 : using base::StringPiece;
24 :
25 E : void BlockHash::Hash(const BlockGraph::Block* block) {
26 E : DCHECK(block != NULL);
27 :
28 : MD5Context md5_context;
29 E : MD5Init(&md5_context);
30 :
31 : // Hash the block properties: type, size, data_size, reference count.
32 E : BlockGraph::BlockType type = block->type();
33 E : BlockGraph::Size size = block->size();
34 E : BlockGraph::Size data_size = block->data_size();
35 E : size_t reference_count = block->references().size();
36 : MD5Update(&md5_context,
37 E : StringPiece(reinterpret_cast<const char*>(&type), sizeof(type)));
38 : MD5Update(&md5_context,
39 E : StringPiece(reinterpret_cast<const char*>(&size), sizeof(size)));
40 : MD5Update(&md5_context,
41 : StringPiece(reinterpret_cast<const char*>(&data_size),
42 E : sizeof(data_size)));
43 : MD5Update(&md5_context,
44 : StringPiece(reinterpret_cast<const char*>(&reference_count),
45 E : sizeof(data_size)));
46 :
47 : // Hash the references in order of increasing source offset.
48 : BlockGraph::Block::ReferenceMap::const_iterator ref =
49 E : block->references().begin();
50 E : BlockGraph::Offset last_source_offset = -1;
51 E : for (; ref != block->references().end(); ++ref) {
52 E : CHECK_LT(last_source_offset, ref->first);
53 E : last_source_offset = ref->first;
54 :
55 : // Hash the reference: source offset, type, size.
56 E : BlockGraph::Offset offset = ref->first;
57 E : BlockGraph::ReferenceType type = ref->second.type();
58 E : BlockGraph::Size size = ref->second.size();
59 : MD5Update(&md5_context,
60 E : StringPiece(reinterpret_cast<const char*>(&offset), sizeof(offset)));
61 : MD5Update(&md5_context,
62 E : StringPiece(reinterpret_cast<const char*>(&type), sizeof(type)));
63 : MD5Update(&md5_context,
64 E : StringPiece(reinterpret_cast<const char*>(&size), sizeof(size)));
65 E : }
66 :
67 : // Hash the data, skipping locations of references.
68 E : size_t data_index = 0;
69 E : ref = block->references().begin();
70 E : for (; ref != block->references().end(); ++ref) {
71 E : DCHECK_LE(0, ref->first);
72 E : size_t ref_offset = static_cast<size_t>(ref->first);
73 :
74 : // Have data to hash before this reference?
75 E : if (data_index < block->data_size() && data_index < ref_offset) {
76 E : size_t data_end = block->data_size();
77 E : if (ref_offset < data_end)
78 E : data_end = ref_offset;
79 :
80 : MD5Update(&md5_context,
81 : StringPiece(reinterpret_cast<const char*>(
82 E : block->data() + data_index), data_end - data_index));
83 : }
84 :
85 : // Skip past this reference.
86 E : data_index = ref_offset + ref->second.size();
87 E : }
88 :
89 : // Hash any data after the last reference.
90 E : if (data_index < block->data_size()) {
91 : MD5Update(&md5_context,
92 : StringPiece(reinterpret_cast<const char*>(
93 E : block->data() + data_index), block->data_size() - data_index));
94 E : data_index = block->data_size();
95 : }
96 :
97 : // Hash any trailing zero bytes in the block. The zeros are implied if the
98 : // data size is less than the block size.
99 E : while (data_index < block->size()) {
100 : static const char kZeros[32] = { 0 };
101 E : size_t bytes = block->size() - data_index;
102 E : if (bytes > sizeof(kZeros))
103 i : bytes = sizeof(kZeros);
104 E : MD5Update(&md5_context, StringPiece(kZeros, bytes));
105 E : data_index += bytes;
106 E : }
107 :
108 : // Finalize the hash.
109 E : MD5Final(&md5_digest, &md5_context);
110 E : }
111 :
112 : } // namespace block_graph
|