1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <algorithm>
  27 #include <fstream>
  28 #include "ResourceEditor.h"
  29 #include "WinErrorHandling.h"
  30 #include "Log.h"
  31 
  32 
  33 ResourceEditor::FileLock::FileLock(const std::wstring& binaryPath) {
  34     h = BeginUpdateResource(binaryPath.c_str(), FALSE);
  35     if (NULL == h) {
  36         JP_THROW(SysError(tstrings::any() << "BeginUpdateResource("
  37                     << binaryPath << ") failed", BeginUpdateResource));
  38     }
  39 
  40     discard(false);
  41 }
  42 
  43 
  44 ResourceEditor::FileLock::~FileLock() {
  45     if (!EndUpdateResource(h, theDiscard)) {
  46         JP_NO_THROW(JP_THROW(SysError(tstrings::any()
  47             << "EndUpdateResource(" << h << ") failed.", EndUpdateResource)));
  48     }
  49 }
  50 
  51 
  52 ResourceEditor::ResourceEditor() {
  53     language(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)).type(unsigned(0)).id(unsigned(0));
  54 }
  55 
  56 
  57 ResourceEditor& ResourceEditor::type(unsigned v) {
  58     return type(MAKEINTRESOURCE(v));
  59 }
  60 
  61 
  62 ResourceEditor& ResourceEditor::type(LPCWSTR v) {
  63     if (IS_INTRESOURCE(v)) {
  64         std::wostringstream printer;
  65         printer << L"#" << reinterpret_cast<size_t>(v);
  66         theType = printer.str();
  67         theTypePtr = MAKEINTRESOURCE(static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(v)));
  68     } else {
  69         theType = v;
  70         theTypePtr = theType.c_str();
  71     }
  72     return *this;
  73 }
  74 
  75 
  76 ResourceEditor& ResourceEditor::id(unsigned v) {
  77     return id(MAKEINTRESOURCE(v));
  78 }
  79 
  80 
  81 ResourceEditor& ResourceEditor::id(LPCWSTR v) {
  82     if (IS_INTRESOURCE(v)) {
  83         std::wostringstream printer;
  84         printer << L"#" << reinterpret_cast<size_t>(v);
  85         theId = printer.str();
  86     } else {
  87         theId = v;
  88         theIdPtr = theId.c_str();
  89     }
  90     return *this;
  91 }
  92 
  93 
  94 ResourceEditor& ResourceEditor::apply(const FileLock& dstBinary,
  95                             std::istream& srcStream, std::streamsize size) {
  96 
  97     typedef std::vector<BYTE> ByteArray;
  98     ByteArray buf;
  99     if (size <= 0) {
 100         // Read the entire stream.
 101         buf = ByteArray((std::istreambuf_iterator<char>(srcStream)),
 102                                             std::istreambuf_iterator<char>());
 103     } else {
 104         buf.resize(size_t(size));
 105         srcStream.read(reinterpret_cast<char*>(buf.data()), size);
 106     }
 107 
 108     auto reply = UpdateResource(dstBinary.get(), theTypePtr, theIdPtr, lang,
 109                                 buf.data(), static_cast<DWORD>(buf.size()));
 110     if (reply == FALSE) {
 111         JP_THROW(SysError("UpdateResource() failed", UpdateResource));
 112     }
 113 
 114     return *this;
 115 }
 116 
 117 
 118 ResourceEditor& ResourceEditor::apply(const FileLock& dstBinary,
 119                                                 const std::wstring& srcFile) {
 120     std::ifstream input(srcFile, std::ios_base::binary);
 121     input.exceptions(std::ios::failbit | std::ios::badbit);
 122     return apply(dstBinary, input);
 123 }