Skip to content

Commit 35e219d

Browse files
committed
git-wrapper: allow the edit-res.exe copy to change icons, too
As we already allow changing text resources, it is a very small step to allow changing the `.exe` icon, too. So let's just do it. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 304d297 commit 35e219d

File tree

1 file changed

+129
-3
lines changed

1 file changed

+129
-3
lines changed

compat/win32/git-wrapper.c

Lines changed: 129 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,100 @@ static LPWSTR fixup_commandline(LPWSTR exepath, LPWSTR *exep, int *wait,
175175

176176
#ifdef MAGIC_RESOURCE
177177

178+
#include <stdint.h>
179+
180+
#pragma pack(2)
181+
struct resource_directory
182+
{
183+
int8_t width;
184+
int8_t height;
185+
int8_t color_count;
186+
int8_t reserved;
187+
int16_t planes;
188+
int16_t bit_count;
189+
int32_t bytes_in_resource;
190+
int16_t id;
191+
};
192+
193+
struct header
194+
{
195+
int16_t reserved;
196+
int16_t type;
197+
int16_t count;
198+
};
199+
200+
struct icon_header
201+
{
202+
int8_t width;
203+
int8_t height;
204+
int8_t color_count;
205+
int8_t reserved;
206+
int16_t planes;
207+
int16_t bit_count;
208+
int32_t bytes_in_resource;
209+
int32_t image_offset;
210+
};
211+
212+
struct icon_image
213+
{
214+
BITMAPINFOHEADER header;
215+
RGBQUAD colors;
216+
int8_t xors[1];
217+
int8_t ands[1];
218+
};
219+
220+
struct icon
221+
{
222+
int count;
223+
struct header *header;
224+
struct resource_directory *items;
225+
struct icon_image **images;
226+
};
227+
228+
static int parse_ico_file(LPWSTR ico_path, struct icon *result)
229+
{
230+
struct header file_header;
231+
FILE *file = _wfopen(ico_path, L"rb");
232+
int i;
233+
234+
if (!file) {
235+
fwprintf(stderr, L"could not open icon file '%s'", ico_path);
236+
return 1;
237+
}
238+
239+
fread(&file_header, sizeof(struct header), 1, file);
240+
result->count = file_header.count;
241+
242+
result->header = malloc(sizeof(struct header) + result->count
243+
* sizeof(struct resource_directory));
244+
result->header->reserved = 0;
245+
result->header->type = 1;
246+
result->header->count = result->count;
247+
result->items = (struct resource_directory *)(result->header + 1);
248+
struct icon_header *icon_headers = malloc(result->count
249+
* sizeof(struct icon_header));
250+
fread(icon_headers, result->count * sizeof(struct icon_header),
251+
1, file);
252+
result->images = malloc(result->count * sizeof(struct icon_image *));
253+
254+
for (i = 0; i < result->count; i++) {
255+
struct icon_image** image = result->images + i;
256+
struct icon_header* icon_header = icon_headers + i;
257+
struct resource_directory *item = result->items + i;
258+
259+
*image = malloc(icon_header->bytes_in_resource);
260+
fseek(file, icon_header->image_offset, SEEK_SET);
261+
fread(*image, icon_header->bytes_in_resource, 1, file);
262+
263+
memcpy(item, icon_header, sizeof(struct resource_directory));
264+
item->id = (int16_t)(i + 1);
265+
}
266+
267+
fclose(file);
268+
269+
return 0;
270+
}
271+
178272
static int wsuffixcmp(LPWSTR text, LPWSTR suffix)
179273
{
180274
int text_len = wcslen(text), suffix_len = wcslen(suffix);
@@ -186,9 +280,10 @@ static int wsuffixcmp(LPWSTR text, LPWSTR suffix)
186280
}
187281

188282
static int edit_resources(LPWSTR exe_path,
189-
LPWSTR *commands, int command_count)
283+
LPWSTR ico_path, LPWSTR *commands, int command_count)
190284
{
191285
WORD language = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
286+
struct icon icon;
192287
HANDLE handle;
193288
int i;
194289

@@ -206,13 +301,41 @@ static int edit_resources(LPWSTR exe_path,
206301
return -1;
207302
}
208303

304+
if (ico_path) {
305+
if (wsuffixcmp(ico_path, L".ico")) {
306+
fwprintf(stderr, L"Not an .ico file: '%s'", ico_path);
307+
return -1;
308+
}
309+
if (_waccess(ico_path, 0) == -1) {
310+
fwprintf(stderr, L"File not found: '%s'", ico_path);
311+
return -1;
312+
}
313+
314+
if (parse_ico_file(ico_path, &icon))
315+
return -1;
316+
}
317+
209318
handle = BeginUpdateResource(exe_path, FALSE);
210319
if (!handle) {
211320
fwprintf(stderr,
212321
L"Could not update resources of '%s'", exe_path);
213322
return -1;
214323
}
215324

325+
if (ico_path) {
326+
int id = 1;
327+
UpdateResource(handle, RT_GROUP_ICON,
328+
L"MAINICON", language,
329+
icon.header, sizeof(struct header) + icon.count
330+
* sizeof(struct resource_directory));
331+
for (i = 0; i < icon.count; i++) {
332+
UpdateResource(handle, RT_ICON,
333+
MAKEINTRESOURCE(id++), language,
334+
icon.images[i],
335+
icon.items[i].bytes_in_resource);
336+
}
337+
}
338+
216339
if (command_count >= 0) {
217340
LPWSTR buffer, p;
218341
int alloc = 16; /* 16 words with string lengths, for sure... */
@@ -262,12 +385,15 @@ static int configure_via_resource(LPWSTR basename, LPWSTR exepath, LPWSTR exep,
262385
wargv = CommandLineToArgvW(cmdline, &wargc);
263386

264387
if (wargv[1]) {
388+
if (wargc == 4 && !wcscmp(wargv[1], L"icon"))
389+
exit(edit_resources(wargv[2], wargv[3],
390+
NULL, -1));
265391
if (wargc > 1 && !wcscmp(wargv[1], L"command"))
266-
exit(edit_resources(wargv[2],
392+
exit(edit_resources(wargv[2], NULL,
267393
wargv + 3, wargc - 3));
268394
}
269395
fwprintf(stderr,
270-
L"Usage: %s command <exe> <args>...\n",
396+
L"Usage: %s (icon | command) <exe> <args>...\n",
271397
basename);
272398
exit(1);
273399
}

0 commit comments

Comments
 (0)