Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / installer / test / pe_image_resources.cc
blob365e9669e7fd115bac94151b225990ea958e4890
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains the implementation for an iterator over a portable
6 // executable file's resources.
8 #include "chrome/installer/test/pe_image_resources.h"
10 #include "base/logging.h"
11 #include "base/win/pe_image.h"
13 namespace {
15 // Performs a cast to type |T| of |data| iff |data_size| is sufficient to hold
16 // an instance of type |T|. Returns true on success.
17 template<class T>
18 bool StructureAt(const uint8* data, size_t data_size, const T** structure) {
19 if (sizeof(T) <= data_size) {
20 *structure = reinterpret_cast<const T*>(data);
21 return true;
23 return false;
26 // Recursive function for enumerating entries in an image's resource segment.
27 // static
28 bool EnumResourcesWorker(
29 const base::win::PEImage& image, const uint8* tree_base, DWORD tree_size,
30 DWORD directory_offset, upgrade_test::EntryPath* path,
31 upgrade_test::EnumResource_Fn callback, uintptr_t context) {
32 bool success = true;
33 const IMAGE_RESOURCE_DIRECTORY* resource_directory;
35 if (!StructureAt(tree_base + directory_offset, tree_size - directory_offset,
36 &resource_directory) ||
37 directory_offset + sizeof(IMAGE_RESOURCE_DIRECTORY) +
38 (resource_directory->NumberOfNamedEntries +
39 resource_directory->NumberOfIdEntries) *
40 sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) > tree_size) {
41 LOG(DFATAL) << "Insufficient room in resource segment for directory entry.";
42 return false;
45 const IMAGE_RESOURCE_DIRECTORY_ENTRY* scan =
46 reinterpret_cast<const IMAGE_RESOURCE_DIRECTORY_ENTRY*>(
47 tree_base + directory_offset +
48 sizeof(IMAGE_RESOURCE_DIRECTORY));
49 const IMAGE_RESOURCE_DIRECTORY_ENTRY* end = scan +
50 resource_directory->NumberOfNamedEntries +
51 resource_directory->NumberOfIdEntries;
52 for (; success && scan != end; ++scan) {
53 if ((scan->NameIsString != 0) !=
54 (scan - reinterpret_cast<const IMAGE_RESOURCE_DIRECTORY_ENTRY*>(
55 tree_base + directory_offset +
56 sizeof(IMAGE_RESOURCE_DIRECTORY)) <
57 resource_directory->NumberOfNamedEntries)) {
58 LOG(DFATAL) << "Inconsistent number of named or numbered entries.";
59 success = false;
60 break;
62 if (scan->NameIsString) {
63 const IMAGE_RESOURCE_DIR_STRING_U* dir_string;
64 if (!StructureAt(tree_base + scan->NameOffset,
65 tree_size - scan->NameOffset, &dir_string) ||
66 scan->NameOffset + sizeof(WORD) +
67 dir_string->Length * sizeof(wchar_t) > tree_size) {
68 LOG(DFATAL) << "Insufficient room in resource segment for entry name.";
69 success = false;
70 break;
72 path->push_back(
73 upgrade_test::EntryId(std::wstring(&dir_string->NameString[0],
74 dir_string->Length)));
75 } else {
76 path->push_back(upgrade_test::EntryId(scan->Id));
78 if (scan->DataIsDirectory) {
79 success = EnumResourcesWorker(image, tree_base, tree_size,
80 scan->OffsetToDirectory, path, callback,
81 context);
82 } else {
83 const IMAGE_RESOURCE_DATA_ENTRY* data_entry;
84 if (StructureAt(tree_base + scan->OffsetToData,
85 tree_size - scan->OffsetToData, &data_entry) &&
86 reinterpret_cast<uint8*>(
87 image.RVAToAddr(data_entry->OffsetToData)) + data_entry->Size <=
88 tree_base + tree_size) {
89 // Despite what winnt.h says, OffsetToData is an RVA.
90 callback(
91 *path,
92 reinterpret_cast<uint8*>(image.RVAToAddr(data_entry->OffsetToData)),
93 data_entry->Size, data_entry->CodePage, context);
94 } else {
95 LOG(DFATAL) << "Insufficient room in resource segment for data entry.";
96 success = false;
99 path->pop_back();
102 return success;
105 } // namespace
107 namespace upgrade_test {
109 // static
110 bool EnumResources(const base::win::PEImage& image, EnumResource_Fn callback,
111 uintptr_t context) {
112 DWORD resources_size =
113 image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_RESOURCE);
114 if (resources_size != 0) {
115 EntryPath path_storage;
116 return EnumResourcesWorker(
117 image,
118 reinterpret_cast<uint8*>(
119 image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_RESOURCE)),
120 resources_size, 0, &path_storage, callback, context);
122 return true;
125 } // namespace upgrade_test