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"
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.
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
);
26 // Recursive function for enumerating entries in an image's resource segment.
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
) {
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.";
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.";
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.";
73 upgrade_test::EntryId(std::wstring(&dir_string
->NameString
[0],
74 dir_string
->Length
)));
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
,
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.
92 reinterpret_cast<uint8
*>(image
.RVAToAddr(data_entry
->OffsetToData
)),
93 data_entry
->Size
, data_entry
->CodePage
, context
);
95 LOG(DFATAL
) << "Insufficient room in resource segment for data entry.";
107 namespace upgrade_test
{
110 bool EnumResources(const base::win::PEImage
& image
, EnumResource_Fn callback
,
112 DWORD resources_size
=
113 image
.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_RESOURCE
);
114 if (resources_size
!= 0) {
115 EntryPath path_storage
;
116 return EnumResourcesWorker(
118 reinterpret_cast<uint8
*>(
119 image
.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_RESOURCE
)),
120 resources_size
, 0, &path_storage
, callback
, context
);
125 } // namespace upgrade_test