diff options
Diffstat (limited to 'xulrunner/tools/redit/redit.cpp')
-rw-r--r-- | xulrunner/tools/redit/redit.cpp | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/xulrunner/tools/redit/redit.cpp b/xulrunner/tools/redit/redit.cpp new file mode 100644 index 000000000..8a96358b2 --- /dev/null +++ b/xulrunner/tools/redit/redit.cpp @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// System headers (alphabetical) +#include <fcntl.h> +#include <io.h> +#include <share.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <windows.h> + +// Mozilla headers (alphabetical) +#include "mozilla/FileUtils.h" // ScopedClose +#include "mozilla/UniquePtrExtensions.h" + +/* +Icon files are made up of: + +IconHeader +IconDirEntry1 +IconDirEntry2 +... +IconDirEntryN +IconData1 +IconData2 +... +IconDataN + +Each IconData must be added as a new RT_ICON resource to the exe. Then +an RT_GROUP_ICON resource must be added that contains an equivalent +header: + +IconHeader +IconResEntry1 +IconResEntry2 +... +IconResEntryN +*/ + +#pragma pack(push, 2) +typedef struct +{ + WORD Reserved; + WORD ResourceType; + WORD ImageCount; +} IconHeader; + +typedef struct +{ + BYTE Width; + BYTE Height; + BYTE Colors; + BYTE Reserved; + WORD Planes; + WORD BitsPerPixel; + DWORD ImageSize; + DWORD ImageOffset; +} IconDirEntry; + +typedef struct +{ + BYTE Width; + BYTE Height; + BYTE Colors; + BYTE Reserved; + WORD Planes; + WORD BitsPerPixel; + DWORD ImageSize; + WORD ResourceID; // This field is the one difference to above +} IconResEntry; +#pragma pack(pop) + +namespace { + /** + * ScopedResourceUpdate is a RAII wrapper for Windows resource updating + * + * Instances |EndUpdateResourceW()| their handles when they go out of scope. + * They pass |TRUE| as the second argument to |EndUpdateResourceW()|, which + * causes the resource update to be aborted (changes are discarded). + */ + struct ScopedResourceUpdateTraits + { + typedef HANDLE type; + static type empty() { return nullptr; } + static void release(type handle) { + if(nullptr != handle) { + EndUpdateResourceW(handle, TRUE); // Discard changes + } + } + }; + + typedef mozilla::Scoped<ScopedResourceUpdateTraits> ScopedResourceUpdate; +}; + +#ifdef __MINGW32__ +extern "C" +#endif +int +wmain(int argc, wchar_t** argv) +{ + if (argc != 3) { + printf("Usage: redit <exe file> <icon file>\n"); + return 1; + } + + mozilla::ScopedClose file; + if (0 != _wsopen_s(&file.rwget(), + argv[2], + _O_BINARY | _O_RDONLY, + _SH_DENYWR, + _S_IREAD) + || (-1 == file)) { + fprintf(stderr, "Unable to open icon file.\n"); + return 1; + } + + // Load all the data from the icon file + long filesize = _filelength(file); + auto data = MakeUniqueFallible<BYTE[]>(filesize); + if(!data) { + fprintf(stderr, "Failed to allocate memory for icon file.\n"); + return 1; + } + _read(file, data.get(), filesize); + + IconHeader* header = reinterpret_cast<IconHeader*>(data.get()); + + // Open the target library for updating + ScopedResourceUpdate updateRes(BeginUpdateResourceW(argv[1], FALSE)); + if (nullptr == updateRes) { + fprintf(stderr, "Unable to open library for modification.\n"); + return 1; + } + + // Allocate the group resource entry + long groupSize = sizeof(IconHeader) + + header->ImageCount * sizeof(IconResEntry); + auto group = MakeUniqueFallible<BYTE[]>(groupSize); + if(!group) { + fprintf(stderr, "Failed to allocate memory for new images.\n"); + return 1; + } + memcpy(group.get(), data.get(), sizeof(IconHeader)); + + IconDirEntry* sourceIcon = + reinterpret_cast<IconDirEntry*>(data.get() + + sizeof(IconHeader)); + IconResEntry* targetIcon = + reinterpret_cast<IconResEntry*>(group.get() + + sizeof(IconHeader)); + + for (int id = 1; id <= header->ImageCount; id++) { + // Add the individual icon + if (!UpdateResourceW(updateRes, RT_ICON, MAKEINTRESOURCE(id), + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + data + sourceIcon->ImageOffset, + sourceIcon->ImageSize)) { + fprintf(stderr, "Unable to update resource (RT_ICON).\n"); + return 1; + } + // Copy the data for this icon + // (note that the structs have different sizes) + memcpy(targetIcon, sourceIcon, sizeof(IconResEntry)); + targetIcon->ResourceID = id; + sourceIcon++; + targetIcon++; + } + + if (!UpdateResourceW(updateRes, RT_GROUP_ICON, L"MAINICON", + MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), + group, groupSize)) { + fprintf(stderr, "Unable to update resource (RT_GROUP_ICON).\n"); + return 1; + } + + // Save the modifications + if(!EndUpdateResourceW(updateRes.forget(), FALSE)) { + fprintf(stderr, "Unable to write changes to library.\n"); + return 1; + } + + return 0; +} |