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_graph_serializer.h"
16 :
17 : #include "base/strings/stringprintf.h"
18 :
19 : namespace block_graph {
20 :
21 : namespace {
22 :
23 : using core::InArchive;
24 : using core::OutArchive;
25 :
26 : // This needs to be incremented any time a non-backwards compatible change
27 : // is made to the serialization format.
28 : // TODO(chrisha): Enforce this via a unittest. Check in a version of a
29 : // simple block-graph, and ensure it deserializes to the same in-memory
30 : // representation.
31 : // Version 3: Added image_format_ block-graph property.
32 : // Version 4: Deprecated old decomposer attributes.
33 : // Version 5: Added new Block attributes: padding_before and alignment_offset.
34 : static const uint32 kSerializedBlockGraphVersion = 5;
35 :
36 : // Some constants for use in dealing with backwards compatibility.
37 : static const uint32 kMinSupportedSerializedBlockGraphVersion = 2;
38 : static const uint32 kImageFormatPropertyBlockGraphVersion = 3;
39 : static const uint32 kPaddingBeforePropertyBlockGraphVersion = 5;
40 :
41 : // Potentially saves a string, depending on whether or not OMIT_STRINGS is
42 : // enabled.
43 : bool MaybeSaveString(const BlockGraphSerializer& bgs,
44 : const std::string& value,
45 E : OutArchive* out_archive) {
46 E : DCHECK(out_archive != NULL);
47 :
48 E : if (bgs.has_attributes(BlockGraphSerializer::OMIT_STRINGS))
49 E : return true;
50 :
51 E : if (!out_archive->Save(value)) {
52 i : LOG(ERROR) << "Unable to save string \"" << value << "\".";
53 i : return false;
54 : }
55 :
56 E : return true;
57 E : }
58 :
59 : // Potentially loads a string, depending on whether or not OMIT_STRINGS is
60 : // enabled.
61 : bool MaybeLoadString(const BlockGraphSerializer& bgs,
62 : std::string* value,
63 E : InArchive* in_archive) {
64 E : DCHECK(value != NULL);
65 E : DCHECK(in_archive != NULL);
66 :
67 E : if (bgs.has_attributes(BlockGraphSerializer::OMIT_STRINGS))
68 E : return true;
69 :
70 E : if (!in_archive->Load(value)) {
71 i : LOG(ERROR) << "Unable to load string.";
72 i : return false;
73 : }
74 :
75 E : return true;
76 E : }
77 :
78 E : bool ValidAttributes(uint32 attributes, uint32 attributes_max) {
79 E : return (attributes & ~(attributes_max - 1)) == 0;
80 E : }
81 :
82 : } // namespace
83 :
84 : bool BlockGraphSerializer::Save(const BlockGraph& block_graph,
85 E : core::OutArchive* out_archive) const {
86 E : CHECK(out_archive != NULL);
87 :
88 : // Save the serialization attributes so we can read this block-graph without
89 : // having to be told how it was saved.
90 : if (!out_archive->Save(kSerializedBlockGraphVersion) ||
91 : !out_archive->Save(static_cast<uint32>(data_mode_)) ||
92 E : !out_archive->Save(attributes_)) {
93 i : LOG(ERROR) << "Unable to save serialized block-graph properties.";
94 i : return false;
95 : }
96 :
97 : // TODO(etienneb): We should serialize the string table in the block graph,
98 : // and encode string ids instead of the raw strings.
99 :
100 : // This function takes care of outputting a meaningful log message on
101 : // failure.
102 E : if (!SaveBlockGraphProperties(block_graph, out_archive))
103 i : return false;
104 :
105 : // Save the blocks, except for their references. We do that in a second pass
106 : // so that when loading the referenced blocks will exist.
107 E : if (!SaveBlocks(block_graph, out_archive)) {
108 i : LOG(ERROR) << "Unable to save blocks.";
109 i : return false;
110 : }
111 :
112 : // Save all of the references. The referrers are implicitly saved by this.
113 E : if (!SaveBlockGraphReferences(block_graph, out_archive)) {
114 i : LOG(ERROR) << "Unable to save block graph references.";
115 i : return false;
116 : }
117 :
118 E : return true;
119 E : }
120 :
121 : bool BlockGraphSerializer::Load(BlockGraph* block_graph,
122 E : core::InArchive* in_archive) {
123 E : CHECK(block_graph != NULL);
124 E : CHECK(in_archive != NULL);
125 :
126 E : uint32 version = 0;
127 E : if (!in_archive->Load(&version)) {
128 i : LOG(ERROR) << "Unable to load serialized block graph version.";
129 i : return false;
130 : }
131 :
132 : // We are backwards compatible back to version 2, for now.
133 : if (version < kMinSupportedSerializedBlockGraphVersion ||
134 E : version > kSerializedBlockGraphVersion) {
135 E : LOG(ERROR) << "Unable to load block graph with version " << version << ".";
136 E : return false;
137 : }
138 :
139 : // Read the serialization attributes and mode information so that we know how
140 : // to load the block-graph.
141 E : uint32 data_mode = 0;
142 E : if (!in_archive->Load(&data_mode) || !in_archive->Load(&attributes_)) {
143 i : LOG(ERROR) << "Unable to load serialized block-graph properties.";
144 i : return false;
145 : }
146 E : data_mode_ = static_cast<DataMode>(data_mode);
147 :
148 : // Ensure that the data mode and the attributes are valid.
149 : if (data_mode_ >= DATA_MODE_MAX ||
150 E : !ValidAttributes(attributes_, ATTRIBUTES_MAX)) {
151 i : LOG(ERROR) << "Invalid data mode and/or attributes.";
152 i : return false;
153 : }
154 :
155 : // This function takes care of outputting a meaningful log message on
156 : // failure.
157 E : if (!LoadBlockGraphProperties(version, block_graph, in_archive))
158 i : return false;
159 :
160 : // Load the blocks, except for their references.
161 E : if (!LoadBlocks(version, block_graph, in_archive)) {
162 i : LOG(ERROR) << "Unable to load blocks.";
163 i : return false;
164 : }
165 :
166 : // Now load the references and wire them up.
167 E : if (!LoadBlockGraphReferences(block_graph, in_archive)) {
168 i : LOG(ERROR) << "Unable to load block graph references.";
169 i : return false;
170 : }
171 :
172 E : return true;
173 E : }
174 :
175 : bool BlockGraphSerializer::SaveBlockGraphProperties(
176 : const BlockGraph& block_graph,
177 E : OutArchive* out_archive) const {
178 E : DCHECK(out_archive != NULL);
179 :
180 : if (!out_archive->Save(block_graph.next_section_id_) ||
181 : !out_archive->Save(block_graph.sections_) ||
182 : !out_archive->Save(block_graph.next_block_id_) ||
183 E : !out_archive->Save(static_cast<uint8>(block_graph.image_format_))) {
184 i : LOG(ERROR) << "Unable to save block graph properties.";
185 i : return false;
186 : }
187 :
188 E : return true;
189 E : }
190 :
191 : bool BlockGraphSerializer::LoadBlockGraphProperties(
192 E : uint32 version, BlockGraph* block_graph, InArchive* in_archive) const {
193 E : DCHECK(block_graph != NULL);
194 E : DCHECK(in_archive != NULL);
195 :
196 : // The block graph properties should be empty.
197 E : DCHECK_EQ(0u, block_graph->next_section_id_);
198 E : DCHECK_EQ(0u, block_graph->sections_.size());
199 E : DCHECK_EQ(0u, block_graph->next_block_id_);
200 :
201 : if (!in_archive->Load(&block_graph->next_section_id_) ||
202 : !in_archive->Load(&block_graph->sections_) ||
203 E : !in_archive->Load(&block_graph->next_block_id_)) {
204 i : LOG(ERROR) << "Unable to load block graph properties.";
205 i : return false;
206 : }
207 :
208 : // Read the image format property. This is not present in all versions of the
209 : // block-graph.
210 E : uint8 image_format = 0;
211 E : if (version >= kImageFormatPropertyBlockGraphVersion) {
212 E : if (!in_archive->Load(&image_format)) {
213 i : LOG(ERROR) << "Unable to load block graph image format.";
214 i : return false;
215 : }
216 E : } else {
217 : // We default to the PE format, as COFF images were not previously
218 : // supported.
219 E : image_format = BlockGraph::PE_IMAGE;
220 : }
221 : block_graph->image_format_ = static_cast<BlockGraph::ImageFormat>(
222 E : image_format);
223 :
224 E : return true;
225 E : }
226 :
227 : bool BlockGraphSerializer::SaveBlocks(const BlockGraph& block_graph,
228 E : OutArchive* out_archive) const {
229 E : DCHECK(out_archive != NULL);
230 :
231 E : if (!out_archive->Save(block_graph.blocks().size())) {
232 i : LOG(ERROR) << "Unable to save block count.";
233 i : return false;
234 : }
235 :
236 : // Output the basic block properties first.
237 E : BlockGraph::BlockMap::const_iterator it = block_graph.blocks_.begin();
238 E : for (; it != block_graph.blocks_.end(); ++it) {
239 E : BlockGraph::BlockId block_id = it->first;
240 E : const BlockGraph::Block& block = it->second;
241 : if (!out_archive->Save(block_id) ||
242 : !SaveBlockProperties(block, out_archive) ||
243 : !SaveBlockLabels(block, out_archive) ||
244 E : !SaveBlockData(block, out_archive)) {
245 i : LOG(ERROR) << "Unable to save block with id " << block_id << ".";
246 i : return false;
247 : }
248 E : }
249 :
250 E : return true;
251 E : }
252 :
253 : bool BlockGraphSerializer::LoadBlocks(uint32 version,
254 : BlockGraph* block_graph,
255 E : InArchive* in_archive) const {
256 E : DCHECK(block_graph != NULL);
257 E : DCHECK(in_archive != NULL);
258 :
259 E : DCHECK_EQ(0u, block_graph->blocks_.size());
260 :
261 E : size_t count = 0;
262 E : if (!in_archive->Load(&count)) {
263 i : LOG(ERROR) << "Unable to load block count.";
264 i : return false;
265 : }
266 :
267 E : for (size_t i = 0; i < count; ++i) {
268 E : BlockGraph::BlockId id = 0;
269 E : if (!in_archive->Load(&id)) {
270 i : LOG(ERROR) << "Unable to load id for block " << i << " of " << count
271 : << ".";
272 i : return false;
273 : }
274 :
275 : std::pair<BlockGraph::BlockMap::iterator, bool> result =
276 : block_graph->blocks_.insert(
277 E : std::make_pair(id, BlockGraph::Block(block_graph)));
278 E : if (!result.second) {
279 i : LOG(ERROR) << "Unable to insert block with id " << id << ".";
280 i : return false;
281 : }
282 E : BlockGraph::Block* block = &result.first->second;
283 E : block->id_ = id;
284 :
285 : if (!LoadBlockProperties(version, block, in_archive) ||
286 : !LoadBlockLabels(block, in_archive) ||
287 E : !LoadBlockData(block, in_archive)) {
288 i : LOG(ERROR) << "Unable to load block " << i << " of " << count
289 : << " with id " << id << ".";
290 i : return false;
291 : }
292 E : }
293 E : DCHECK_EQ(count, block_graph->blocks_.size());
294 :
295 E : return true;
296 E : }
297 :
298 : bool BlockGraphSerializer::SaveBlockGraphReferences(
299 E : const BlockGraph& block_graph, OutArchive* out_archive) const {
300 E : DCHECK(out_archive != NULL);
301 :
302 E : BlockGraph::BlockMap::const_iterator it = block_graph.blocks().begin();
303 E : for (; it != block_graph.blocks().end(); ++it) {
304 E : if (!SaveBlockReferences(it->second, out_archive)) {
305 i : LOG(ERROR) << "Unable to save references for block with id "
306 : << it->second.id() << ".";
307 i : return false;
308 : }
309 E : }
310 :
311 E : return true;
312 E : }
313 :
314 : bool BlockGraphSerializer::LoadBlockGraphReferences(
315 E : BlockGraph* block_graph, InArchive* in_archive) const {
316 E : DCHECK(block_graph != NULL);
317 E : DCHECK(in_archive != NULL);
318 :
319 E : BlockGraph::BlockMap::iterator it = block_graph->blocks_mutable().begin();
320 E : for (; it != block_graph->blocks_mutable().end(); ++it) {
321 E : if (!LoadBlockReferences(block_graph, &it->second, in_archive)) {
322 i : LOG(ERROR) << "Unable to load references for block with id "
323 : << it->second.id() << ".";
324 i : return false;
325 : }
326 E : }
327 :
328 E : return true;
329 E : }
330 :
331 : bool BlockGraphSerializer::SaveBlockProperties(const BlockGraph::Block& block,
332 E : OutArchive* out_archive) const {
333 E : DCHECK(out_archive != NULL);
334 :
335 E : uint8 type = static_cast<uint8>(block.type());
336 :
337 : // We use a signed integer for saving the section ID, as -1 is used to
338 : // indicate 'no section'.
339 : if (!out_archive->Save(type) ||
340 : !SaveUint32(block.size(), out_archive) ||
341 : !SaveUint32(block.alignment(), out_archive) ||
342 : !SaveInt32(block.alignment_offset(), out_archive) ||
343 : !SaveUint32(block.padding_before(), out_archive) ||
344 : !out_archive->Save(block.source_ranges()) ||
345 : !out_archive->Save(block.addr()) ||
346 : !SaveInt32(static_cast<uint32>(block.section()), out_archive) ||
347 : !out_archive->Save(block.attributes()) ||
348 : !MaybeSaveString(*this, block.name(), out_archive) ||
349 E : !MaybeSaveString(*this, block.compiland_name(), out_archive)) {
350 i : LOG(ERROR) << "Unable to save properties for block with id "
351 : << block.id() << ".";
352 i : return false;
353 : }
354 :
355 E : return true;
356 E : }
357 :
358 : bool BlockGraphSerializer::LoadBlockPropertiesImpl(uint32 version,
359 : BlockGraph::Block* block,
360 : InArchive* in_archive)
361 E : const {
362 E : DCHECK(block != NULL);
363 E : DCHECK(in_archive != NULL);
364 :
365 : // Make sure the block is freshly initialized.
366 E : DCHECK_EQ(BlockGraph::CODE_BLOCK, block->type_);
367 E : DCHECK_EQ(0u, block->size_);
368 E : DCHECK_EQ(1u, block->alignment_);
369 E : DCHECK_EQ(0u, block->source_ranges_.size());
370 E : DCHECK_EQ(RelativeAddress::kInvalidAddress, block->addr_);
371 E : DCHECK_EQ(BlockGraph::kInvalidSectionId, block->section_);
372 E : DCHECK_EQ(0u, block->attributes_);
373 :
374 E : uint8 type = 0;
375 E : uint32 size = 0;
376 E : uint32 alignment = 0;
377 E : int32 alignment_offset = 0;
378 E : uint32 padding_before = 0;
379 E : uint32 section = 0;
380 E : uint32 attributes = 0;
381 E : std::string name;
382 E : std::string compiland_name;
383 : if (!in_archive->Load(&type) ||
384 : !LoadUint32(&size, in_archive) ||
385 E : !LoadUint32(&alignment, in_archive)) {
386 i : return false;
387 : }
388 E : if (version >= kPaddingBeforePropertyBlockGraphVersion) {
389 : if (!LoadInt32(&alignment_offset, in_archive) ||
390 E : !LoadUint32(&padding_before, in_archive)) {
391 i : return false;
392 : }
393 : }
394 : if (!in_archive->Load(&block->source_ranges_) ||
395 : !in_archive->Load(&block->addr_) ||
396 : !LoadInt32(reinterpret_cast<int32*>(§ion), in_archive) ||
397 : !in_archive->Load(&attributes) ||
398 : !MaybeLoadString(*this, &name, in_archive) ||
399 E : !MaybeLoadString(*this, &compiland_name, in_archive)) {
400 i : return false;
401 : }
402 :
403 : if (type > BlockGraph::BLOCK_TYPE_MAX ||
404 E : !ValidAttributes(attributes, BlockGraph::BLOCK_ATTRIBUTES_MAX)) {
405 i : LOG(ERROR) << "Invalid block type (" << static_cast<uint32>(type)
406 : << ") and/or attributes ("
407 : << base::StringPrintf("%04X", attributes)
408 : << ") for block with id " << block->id() << ".";
409 i : return false;
410 : }
411 :
412 E : block->type_ = static_cast<BlockGraph::BlockType>(type);
413 E : block->size_ = size;
414 E : block->alignment_ = alignment;
415 E : block->alignment_offset_ = alignment_offset;
416 E : block->padding_before_ = padding_before;
417 E : block->section_ = section;
418 E : block->attributes_ = attributes;
419 E : block->set_name(name);
420 E : block->set_compiland_name(compiland_name);
421 E : return true;
422 E : }
423 :
424 : bool BlockGraphSerializer::LoadBlockProperties(uint32 version,
425 : BlockGraph::Block* block,
426 E : InArchive* in_archive) const {
427 E : DCHECK(block != NULL);
428 E : DCHECK(in_archive != NULL);
429 :
430 E : if (!LoadBlockPropertiesImpl(version, block, in_archive)) {
431 i : LOG(ERROR) << "Unable to load properties for block with id "
432 : << block->id() << ".";
433 i : return false;
434 : }
435 :
436 E : return true;
437 E : }
438 :
439 : bool BlockGraphSerializer::SaveBlockLabels(const BlockGraph::Block& block,
440 E : OutArchive* out_archive) const {
441 E : DCHECK(out_archive != NULL);
442 :
443 E : if (has_attributes(BlockGraphSerializer::OMIT_LABELS))
444 i : return true;
445 :
446 E : uint32 count = block.labels().size();
447 E : if (!SaveUint32(count, out_archive)) {
448 i : LOG(ERROR) << "Unable to save label count.";
449 i : return false;
450 : }
451 :
452 : BlockGraph::Block::LabelMap::const_iterator label_iter =
453 E : block.labels().begin();
454 E : for (; label_iter != block.labels().end(); ++label_iter) {
455 : static_assert(BlockGraph::LABEL_ATTRIBUTES_MAX <= (1 << 16),
456 : "Label attributes requires more than 16 bits.");
457 :
458 E : int32 offset = label_iter->first;
459 E : const BlockGraph::Label& label = label_iter->second;
460 E : uint16 attributes = static_cast<uint16>(label.attributes());
461 :
462 : if (!SaveInt32(offset, out_archive) || !out_archive->Save(attributes) ||
463 E : !MaybeSaveString(*this, label.name(), out_archive)) {
464 i : LOG(ERROR) << "Unable to save label at offset "
465 : << label_iter->first << " of block with id "
466 : << block.id() << ".";
467 i : return false;
468 : }
469 E : }
470 :
471 E : return true;
472 E : }
473 :
474 : bool BlockGraphSerializer::LoadBlockLabels(BlockGraph::Block* block,
475 E : InArchive* in_archive) const {
476 E : DCHECK(block != NULL);
477 E : DCHECK(in_archive != NULL);
478 :
479 : // The block shouldn't have any labels yet.
480 E : DCHECK_EQ(0u, block->labels().size());
481 :
482 E : if (has_attributes(BlockGraphSerializer::OMIT_LABELS))
483 i : return true;
484 :
485 E : uint32 label_count = 0;
486 E : if (!LoadUint32(&label_count, in_archive)) {
487 i : LOG(ERROR) << "Unable to load label count.";
488 i : return false;
489 : }
490 :
491 E : for (size_t i = 0; i < label_count; ++i) {
492 E : int32 offset = 0;
493 E : uint16 attributes = 0;
494 E : std::string name;
495 :
496 : if (!LoadInt32(&offset, in_archive) || !(in_archive->Load(&attributes)) ||
497 E : !MaybeLoadString(*this, &name, in_archive)) {
498 i : LOG(ERROR) << "Unable to load label " << i << " of " << label_count
499 : << " for block with id " << block->id() << ".";
500 i : return false;
501 : }
502 :
503 : // Ensure the attributes are valid.
504 E : if (!ValidAttributes(attributes, BlockGraph::LABEL_ATTRIBUTES_MAX)) {
505 i : LOG(ERROR) << "Invalid attributes ("
506 : << base::StringPrintf("%04X", attributes) << ") for block "
507 : << "with id " << block->id() << ".";
508 i : return false;
509 : }
510 :
511 E : BlockGraph::Label label(name, attributes);
512 E : CHECK(block->SetLabel(offset, label));
513 E : }
514 E : DCHECK_EQ(label_count, block->labels().size());
515 :
516 E : return true;
517 E : }
518 :
519 : bool BlockGraphSerializer::SaveBlockData(const BlockGraph::Block& block,
520 E : OutArchive* out_archive) const {
521 E : DCHECK(out_archive != NULL);
522 :
523 : // We always output the data size.
524 E : uint32 data_size = block.data_size();
525 E : if (!SaveUint32(data_size, out_archive)) {
526 i : LOG(ERROR) << "Unable to save block data size for block with id "
527 : << block.id() << ".";
528 i : return false;
529 : }
530 :
531 E : bool output_data = false;
532 :
533 E : if (block.data_size() > 0) {
534 E : switch (data_mode_) {
535 : default:
536 i : NOTREACHED();
537 :
538 : case OUTPUT_NO_DATA: {
539 E : output_data = false;
540 E : break;
541 : }
542 :
543 : case OUTPUT_OWNED_DATA: {
544 E : uint8 owns_data = block.owns_data();
545 E : if (!out_archive->Save(owns_data)) {
546 i : LOG(ERROR) << "Unable to save 'owns_data' field of block with id "
547 : << block.id() << ".";
548 i : return false;
549 : }
550 :
551 E : output_data = block.owns_data();
552 E : break;
553 : }
554 :
555 : case OUTPUT_ALL_DATA: {
556 E : output_data = true;
557 : break;
558 : }
559 : }
560 : }
561 :
562 : // Save the data if we need to.
563 E : if (output_data) {
564 E : DCHECK_LT(0u, block.data_size());
565 E : if (!out_archive->out_stream()->Write(block.data_size(), block.data())) {
566 i : LOG(ERROR) << "Unable to save data for block with id "
567 : << block.id() << ".";
568 i : return false;
569 : }
570 : }
571 :
572 : // No callback? Then do nothing!
573 E : if (save_block_data_callback_.get() == NULL)
574 E : return true;
575 :
576 : // Invoke the callback.
577 E : bool data_already_saved = output_data || block.data_size() == 0;
578 : if (!save_block_data_callback_->Run(data_already_saved,
579 E : block, out_archive)) {
580 i : return false;
581 : }
582 :
583 E : return true;
584 E : }
585 :
586 : bool BlockGraphSerializer::LoadBlockData(BlockGraph::Block* block,
587 E : InArchive* in_archive) const {
588 E : DCHECK(block != NULL);
589 E : DCHECK(in_archive != NULL);
590 E : DCHECK_EQ(0u, block->data_size());
591 E : DCHECK(block->data() == NULL);
592 E : DCHECK(!block->owns_data());
593 :
594 E : uint32 data_size = 0;
595 E : if (!LoadUint32(&data_size, in_archive)) {
596 i : LOG(ERROR) << "Unable to load data size for block with id "
597 : << block->id() << ".";
598 i : return false;
599 : }
600 :
601 : // This indicates whether or not we need to explicitly load the data directly
602 : // from the serialized stream.
603 E : bool data_in_stream = false;
604 :
605 E : if (data_size > 0) {
606 E : switch (data_mode_) {
607 : default:
608 i : NOTREACHED();
609 :
610 : case OUTPUT_NO_DATA: {
611 E : data_in_stream = false;
612 E : break;
613 : }
614 :
615 : case OUTPUT_OWNED_DATA: {
616 E : uint8 owns_data = 0;
617 E : if (!in_archive->Load(&owns_data)) {
618 i : LOG(ERROR) << "Unable to load 'owns_data' field of block with id "
619 : << block->id() << ".";
620 i : return false;
621 : }
622 :
623 : // If we own the data then it must have been serialized to the stream.
624 E : data_in_stream = owns_data != 0;
625 E : break;
626 : }
627 :
628 : case OUTPUT_ALL_DATA: {
629 E : data_in_stream = true;
630 : break;
631 : }
632 : }
633 : }
634 :
635 E : bool callback_needs_to_set_data = !data_in_stream && data_size > 0;
636 :
637 E : if (data_in_stream) {
638 E : DCHECK_LT(0u, data_size);
639 :
640 : // Read the data from the stream.
641 E : block->AllocateData(data_size);
642 E : DCHECK_EQ(data_size, block->data_size());
643 E : DCHECK(block->data() != NULL);
644 E : if (!in_archive->in_stream()->Read(data_size, block->GetMutableData())) {
645 i : LOG(ERROR) << "Unable to read data for block with id "
646 : << block->id() << ".";
647 i : return false;
648 : }
649 : }
650 :
651 E : if (callback_needs_to_set_data) {
652 : // If we didn't explicitly load the data, then we expect the callback to
653 : // do it. We make sure there is one.
654 E : if (load_block_data_callback_.get() == NULL) {
655 i : LOG(ERROR) << "No load block data callback specified.";
656 i : return false;
657 : }
658 : }
659 :
660 : // If there's a callback, invoke it.
661 E : if (load_block_data_callback_.get()) {
662 : if (!load_block_data_callback_->Run(callback_needs_to_set_data,
663 : data_size,
664 : block,
665 E : in_archive)) {
666 i : LOG(ERROR) << "Block data callback failed.";
667 i : return false;
668 : }
669 : }
670 :
671 E : if (data_size > 0 && block->data() == NULL) {
672 i : LOG(ERROR) << "Load block data callback failed to set block data.";
673 i : return false;
674 : }
675 :
676 E : if (block->data_size() != data_size) {
677 i : LOG(ERROR) << "Load block data callback set incorrect data size.";
678 i : return false;
679 : }
680 :
681 E : return true;
682 E : }
683 :
684 : bool BlockGraphSerializer::SaveBlockReferences(const BlockGraph::Block& block,
685 E : OutArchive* out_archive) const {
686 : // Output the number of references for this block.
687 E : if (!out_archive->Save(block.references().size())) {
688 i : LOG(ERROR) << "Unable to save reference count for block with id "
689 : << block.id() << ".";
690 i : return false;
691 : }
692 :
693 : // Output the references as (offset, reference) pairs.
694 : BlockGraph::Block::ReferenceMap::const_iterator it =
695 E : block.references().begin();
696 E : for (; it != block.references().end(); ++it) {
697 E : int32 offset = it->first;
698 : if (!SaveInt32(offset, out_archive) ||
699 E : !SaveReference(it->second, out_archive)) {
700 i : LOG(ERROR) << "Unable to save (offset, reference) pair at offset "
701 : << offset << " of block with id " << block.id() << ".";
702 i : return false;
703 : }
704 E : }
705 :
706 E : return true;
707 E : }
708 :
709 : bool BlockGraphSerializer::LoadBlockReferences(BlockGraph* block_graph,
710 : BlockGraph::Block* block,
711 E : InArchive* in_archive) const {
712 E : DCHECK(block_graph != NULL);
713 E : DCHECK(block != NULL);
714 E : DCHECK(in_archive != NULL);
715 :
716 : // This block should not have any references yet.
717 E : DCHECK_EQ(0u, block->references().size());
718 :
719 E : size_t count = 0;
720 E : if (!in_archive->Load(&count)) {
721 i : LOG(ERROR) << "Unable to load reference count for block with id "
722 : << block->id() << ".";
723 i : return false;
724 : }
725 :
726 E : for (size_t i = 0; i < count; ++i) {
727 E : int32 offset = 0;
728 E : BlockGraph::Reference ref;
729 : if (!LoadInt32(&offset, in_archive) ||
730 E : !LoadReference(block_graph, &ref, in_archive)) {
731 i : LOG(ERROR) << "Unable to load (offset, reference) pair " << i << " of "
732 : << count << " for block with id " << block->id() << ".";
733 i : return false;
734 : }
735 E : DCHECK(ref.referenced() != NULL);
736 :
737 E : if (!block->SetReference(offset, ref)) {
738 i : LOG(ERROR) << "Unable to create block reference at offset " << offset
739 : << " of block with id " << block->id() << ".";
740 i : return false;
741 : }
742 E : }
743 :
744 E : return true;
745 E : }
746 :
747 : bool BlockGraphSerializer::SaveReference(const BlockGraph::Reference& ref,
748 E : OutArchive* out_archive) const {
749 E : DCHECK(ref.referenced() != NULL);
750 E : DCHECK(out_archive != NULL);
751 :
752 : static_assert(BlockGraph::REFERENCE_TYPE_MAX < 16,
753 : "Reference type requires more than one nibble.");
754 : static_assert(BlockGraph::Reference::kMaximumSize < 16,
755 : "Reference size requires more than one nibble.");
756 :
757 : // The type and size are each stored as a nibble of one byte.
758 : uint8 type_size = (static_cast<uint8>(ref.type()) << 4) |
759 E : static_cast<uint8>(ref.size());
760 E : int32 offset = ref.offset();
761 : // Most often the offset and the base are identical, so we actually save
762 : // the base as a difference from the offset to encourage smaller values.
763 E : int32 base_delta = ref.base() - ref.offset();
764 :
765 : if (!out_archive->Save(type_size) ||
766 : !out_archive->Save(ref.referenced()->id()) ||
767 E : !SaveInt32(offset, out_archive) || !SaveInt32(base_delta, out_archive)) {
768 i : LOG(ERROR) << "Unable to write reference properties.";
769 i : return false;
770 : }
771 :
772 E : return true;
773 E : }
774 :
775 : bool BlockGraphSerializer::LoadReference(BlockGraph* block_graph,
776 : BlockGraph::Reference* ref,
777 E : InArchive* in_archive) const {
778 E : DCHECK(block_graph != NULL);
779 E : DCHECK(ref != NULL);
780 E : DCHECK(in_archive != NULL);
781 :
782 E : uint8 type_size = 0;
783 E : BlockGraph::BlockId id = 0;
784 E : int32 offset = 0;
785 E : int32 base_delta = 0;
786 :
787 : if (!in_archive->Load(&type_size) || !in_archive->Load(&id) ||
788 E : !LoadInt32(&offset, in_archive) || !LoadInt32(&base_delta, in_archive)) {
789 i : LOG(ERROR) << "Unable to load reference properties.";
790 i : return false;
791 : }
792 :
793 : // The type and size are each stored as a nibble of one byte.
794 E : uint8 type = (type_size >> 4) & 0xF;
795 E : uint8 size = type_size & 0xF;
796 :
797 : if (type >= BlockGraph::REFERENCE_TYPE_MAX ||
798 E : size > BlockGraph::Reference::kMaximumSize) {
799 i : LOG(ERROR) << "Invalid reference type (" << static_cast<uint32>(type)
800 : << ") and/or size (" << static_cast<uint32>(size) << ").";
801 i : return false;
802 : }
803 :
804 E : BlockGraph::Block* referenced = block_graph->GetBlockById(id);
805 E : if (referenced == NULL) {
806 i : LOG(ERROR) << "Unable to find referenced block with id " << id << ".";
807 i : return false;
808 : }
809 :
810 : *ref = BlockGraph::Reference(static_cast<BlockGraph::ReferenceType>(type),
811 E : size, referenced, offset, offset + base_delta);
812 :
813 E : return true;
814 E : }
815 :
816 : // Saves an unsigned 32 bit value. This uses a variable length encoding where
817 : // the first three bits are reserved to indicate the number of bytes required to
818 : // store the value.
819 : bool BlockGraphSerializer::SaveUint32(uint32 value,
820 E : OutArchive* out_archive) const {
821 E : DCHECK(out_archive != NULL);
822 :
823 : // Determine the number of bytes needed in the representation.
824 E : uint32 bytes = 1;
825 E : if (value >= (1 << 29)) {
826 E : bytes = 5;
827 E : } else if (value >= (1 << 21)) {
828 E : bytes = 4;
829 E : } else if (value >= (1 << 13)) {
830 E : bytes = 3;
831 E : } else if (value >= (1 << 5)) {
832 E : bytes = 2;
833 : }
834 :
835 : // Output the value, LSB first. We actually only output 5 bits of the LSB.
836 E : uint8 byte = (value & ((1 << 5) - 1));
837 E : byte |= ((bytes - 1) << 5);
838 E : value >>= 5;
839 E : while (true) {
840 E : if (!out_archive->Save(byte)) {
841 i : LOG(ERROR) << "Unable to write variable-length 32-bit unsigned integer.";
842 i : return false;
843 : }
844 :
845 E : if (--bytes == 0)
846 E : break;
847 :
848 E : byte = value & 0xFF;
849 E : value >>= 8;
850 E : }
851 :
852 E : return true;
853 E : }
854 :
855 : // Loads an unsigned 32-bit value using the encoding discussed in SaveUint32.
856 : bool BlockGraphSerializer::LoadUint32(uint32* value,
857 E : InArchive* in_archive) const {
858 E : DCHECK(value != NULL);
859 E : DCHECK(in_archive != NULL);
860 :
861 E : uint32 temp_value = 0;
862 E : uint32 bytes = 0;
863 E : uint32 position = 0;
864 E : uint8 byte = 0;
865 :
866 E : while (true) {
867 E : if (!in_archive->Load(&byte)) {
868 i : LOG(ERROR) << "Unable to read variable-length 32-bit unsigned integer.";
869 i : return false;
870 : }
871 :
872 : // If we're reading the first byte, we need to read the number of bytes
873 : // remaining from its 3 leading bits.
874 E : if (position == 0) {
875 E : bytes = (byte >> 5) & 0x7;
876 E : temp_value = byte & ((1 << 5) - 1);
877 E : position += 5;
878 E : } else {
879 E : temp_value |= byte << position;
880 E : position += 8;
881 : }
882 :
883 E : if (bytes == 0)
884 E : break;
885 :
886 E : --bytes;
887 E : }
888 :
889 E : *value = temp_value;
890 E : return true;
891 E : }
892 :
893 : // Saves a signed 32-bit value using a variable length encoding. This can
894 : // represent signed values where the magnitude is at most 31-bits. We use a
895 : // simple sign-bit encoding, so there are 2 encodings for 0.
896 : bool BlockGraphSerializer::SaveInt32(int32 value,
897 E : OutArchive* out_archive) const {
898 E : DCHECK(out_archive != NULL);
899 :
900 E : uint32 uvalue = static_cast<uint32>(value < 0 ? -value : value);
901 E : CHECK_GT((1u << 31), uvalue);
902 :
903 : // Add the sign bit as the least significant bit. This allows values near 0
904 : // (positive or negative) to be encoded in as little space as possible.
905 E : uvalue <<= 1;
906 E : if (value < 0)
907 E : uvalue |= 1;
908 :
909 E : if (!SaveUint32(uvalue, out_archive))
910 i : return false;
911 :
912 E : return true;
913 E : }
914 :
915 : bool BlockGraphSerializer::LoadInt32(int32* value,
916 E : InArchive* in_archive) const {
917 E : DCHECK(value != NULL);
918 E : DCHECK(in_archive != NULL);
919 :
920 E : uint32 uvalue = 0;
921 E : if (!LoadUint32(&uvalue, in_archive))
922 i : return false;
923 :
924 E : *value = static_cast<int32>(uvalue >> 1);
925 E : if ((uvalue & 1) != 0)
926 E : *value = -(*value);
927 :
928 E : return true;
929 E : }
930 :
931 : } // namespace block_graph
|