1a6bdf751SEric Beckmann //===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
2a6bdf751SEric Beckmann //
3a6bdf751SEric Beckmann //                     The LLVM Compiler Infrastructure
4a6bdf751SEric Beckmann //
5a6bdf751SEric Beckmann // This file is distributed under the University of Illinois Open Source
6a6bdf751SEric Beckmann // License. See LICENSE.TXT for details.
7a6bdf751SEric Beckmann //
8a6bdf751SEric Beckmann //===----------------------------------------------------------------------===//
9a6bdf751SEric Beckmann //
10a6bdf751SEric Beckmann // This file implements the .res file class.
11a6bdf751SEric Beckmann //
12a6bdf751SEric Beckmann //===----------------------------------------------------------------------===//
13a6bdf751SEric Beckmann 
14a6bdf751SEric Beckmann #include "llvm/Object/WindowsResource.h"
15a6bdf751SEric Beckmann #include "llvm/Object/Error.h"
16a6bdf751SEric Beckmann #include <system_error>
17a6bdf751SEric Beckmann 
18a6bdf751SEric Beckmann namespace llvm {
19a6bdf751SEric Beckmann namespace object {
20a6bdf751SEric Beckmann 
21*f1c3beecSDavid Blaikie static const size_t ResourceMagicSize = 16;
22a6bdf751SEric Beckmann 
23*f1c3beecSDavid Blaikie static const size_t NullEntrySize = 16;
24a6bdf751SEric Beckmann 
25a6bdf751SEric Beckmann #define RETURN_IF_ERROR(X)                                                     \
26a6bdf751SEric Beckmann   if (auto EC = X)                                                             \
27a6bdf751SEric Beckmann     return EC;
28a6bdf751SEric Beckmann 
29a6bdf751SEric Beckmann WindowsResource::WindowsResource(MemoryBufferRef Source)
30a6bdf751SEric Beckmann     : Binary(Binary::ID_WinRes, Source) {
31*f1c3beecSDavid Blaikie   size_t LeadingSize = ResourceMagicSize + NullEntrySize;
32a6bdf751SEric Beckmann   BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
33a6bdf751SEric Beckmann                          support::little);
34a6bdf751SEric Beckmann }
35a6bdf751SEric Beckmann 
36a6bdf751SEric Beckmann WindowsResource::~WindowsResource() = default;
37a6bdf751SEric Beckmann 
38a6bdf751SEric Beckmann Expected<std::unique_ptr<WindowsResource>>
39a6bdf751SEric Beckmann WindowsResource::createWindowsResource(MemoryBufferRef Source) {
40*f1c3beecSDavid Blaikie   if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize)
41a6bdf751SEric Beckmann     return make_error<GenericBinaryError>(
42a6bdf751SEric Beckmann         "File too small to be a resource file",
43a6bdf751SEric Beckmann         object_error::invalid_file_type);
44a6bdf751SEric Beckmann   std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
45a6bdf751SEric Beckmann   return std::move(Ret);
46a6bdf751SEric Beckmann }
47a6bdf751SEric Beckmann 
48a6bdf751SEric Beckmann Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
49a6bdf751SEric Beckmann   Error Err = Error::success();
50a6bdf751SEric Beckmann   auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err);
51a6bdf751SEric Beckmann   if (Err)
52a6bdf751SEric Beckmann     return std::move(Err);
53a6bdf751SEric Beckmann   return Ref;
54a6bdf751SEric Beckmann }
55a6bdf751SEric Beckmann 
56a6bdf751SEric Beckmann ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
57a6bdf751SEric Beckmann                                    const WindowsResource *Owner, Error &Err)
58a6bdf751SEric Beckmann     : Reader(Ref), OwningRes(Owner) {
59a6bdf751SEric Beckmann   if (loadNext())
60a6bdf751SEric Beckmann     Err = make_error<GenericBinaryError>("Could not read first entry.",
61a6bdf751SEric Beckmann                                          object_error::unexpected_eof);
62a6bdf751SEric Beckmann }
63a6bdf751SEric Beckmann 
64a6bdf751SEric Beckmann Error ResourceEntryRef::moveNext(bool &End) {
65a6bdf751SEric Beckmann   // Reached end of all the entries.
66a6bdf751SEric Beckmann   if (Reader.bytesRemaining() == 0) {
67a6bdf751SEric Beckmann     End = true;
68a6bdf751SEric Beckmann     return Error::success();
69a6bdf751SEric Beckmann   }
70a6bdf751SEric Beckmann   RETURN_IF_ERROR(loadNext());
71a6bdf751SEric Beckmann 
72a6bdf751SEric Beckmann   return Error::success();
73a6bdf751SEric Beckmann }
74a6bdf751SEric Beckmann 
75a6bdf751SEric Beckmann Error ResourceEntryRef::loadNext() {
76a6bdf751SEric Beckmann   uint32_t DataSize;
77a6bdf751SEric Beckmann   RETURN_IF_ERROR(Reader.readInteger(DataSize));
78a6bdf751SEric Beckmann   uint32_t HeaderSize;
79a6bdf751SEric Beckmann   RETURN_IF_ERROR(Reader.readInteger(HeaderSize));
80a6bdf751SEric Beckmann   // The data and header size ints are themselves part of the header, so we must
81a6bdf751SEric Beckmann   // subtract them from the size.
82a6bdf751SEric Beckmann   RETURN_IF_ERROR(
83a6bdf751SEric Beckmann       Reader.readStreamRef(HeaderBytes, HeaderSize - 2 * sizeof(uint32_t)));
84a6bdf751SEric Beckmann   RETURN_IF_ERROR(Reader.readStreamRef(DataBytes, DataSize));
85a6bdf751SEric Beckmann   RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t)));
86a6bdf751SEric Beckmann   return Error::success();
87a6bdf751SEric Beckmann }
88a6bdf751SEric Beckmann 
89a6bdf751SEric Beckmann } // namespace object
90a6bdf751SEric Beckmann } // namespace llvm
91