-
Notifications
You must be signed in to change notification settings - Fork 34
/
gimgextract.c
93 lines (81 loc) · 2.94 KB
/
gimgextract.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util_indep.h"
int main (int argc, char *argv[])
{
FILE *infp;
int block_size, fatstart, fatend, fatcount;
if (argc != 2) {
printf("usage: %s file.img\n", argv[0]);
return 1;
}
infp = fopen(argv[1], "rb");
if (infp == NULL)
errexit("can't open %s\n", argv[1]);
if ((read_byte_at(infp, 0) ^ read_byte_at(infp, 0x10)) != 'D' ||
(read_byte_at(infp, 0) ^ read_byte_at(infp, 0x15)) != 'G')
errexit("Not a garmin img file.\n");
if (read_byte_at(infp, 0))
errexit("XOR is not 0. Fix it first.\n");
block_size = 1 << (read_byte_at(infp, 0x61) + read_byte_at(infp, 0x62));
fatstart = read_byte_at(infp, 0x40) == 0 ? 3 : read_byte_at(infp, 0x40);
if (read_4byte_at(infp, 0x40c) == 0) { // use root dir. assume it's the first file
off_t offset = fatstart * 512;
if (read_byte_at(infp, offset) != 1 ||
read_byte_at(infp, offset + 0x1) != ' ' ||
read_byte_at(infp, offset + 0x9) != ' ')
errexit("imgheader.data_offset = 0 but the first file is not root dir!\n");
fatstart ++;
if (read_4byte_at(infp, offset + 0xc) % 512 != 0 ||
read_4byte_at(infp, offset + 0xc) <= fatstart * 512)
errexit("rootdir.size = %x which is bad\n", read_4byte_at(infp, offset + 0xc));
fatend = read_4byte_at(infp, offset + 0xc) / 512;
} else {
fatend = read_4byte_at(infp, 0x40c) / 512;
}
for (fatcount = fatstart; fatcount < fatend; fatcount ++) {
off_t offset = fatcount * 512, sf_offset;
int sf_size;
char sf_name[16];
FILE *outfp;
if (read_byte_at(infp, offset) != 1)
continue;
if (read_byte_at(infp, offset + 0x1) == ' ') /* rootdir */
continue;
if (read_2byte_at(infp, offset + 0x10) != 0) /* part != 0 */
continue;
memset(sf_name, 0, sizeof(sf_name));
read_bytes_at(infp, offset + 0x1, (unsigned char *)sf_name, 8);
while (strrchr(sf_name, ' ') != NULL)
strrchr(sf_name, ' ')[0] = '\0';
sf_name[strlen(sf_name)] = '.';
read_bytes_at(infp, offset + 0x9, (unsigned char *)sf_name + strlen(sf_name), 3);
while (strrchr(sf_name, ' ') != NULL)
strrchr(sf_name, ' ')[0] = '\0';
/* a simple security check */
if (strchr(sf_name, '/') != NULL || strchr(sf_name, '\\') != NULL)
errexit("invalid subfile name %s\n", sf_name);
sf_offset = read_2byte_at(infp, offset + 0x20) * block_size;
sf_size = read_4byte_at(infp, offset + 0xc);
if (sf_offset == 0 || sf_size == 0)
errexit("subfile %s has 0 offset or size: 0x%lx 0x%x\n",
sf_name, (unsigned long)sf_offset, (unsigned int)sf_size);
outfp = fopen(sf_name, "wb");
if (outfp == NULL)
errexit("can't open %s for writing\n", sf_name);
while (sf_size != 0) {
unsigned char buff[4096];
int len = sf_size < sizeof(buff) ? sf_size : sizeof(buff);
read_bytes_at(infp, sf_offset, buff, len);
if (fwrite(buff, len, 1, outfp) != 1)
errexit("can't write to %s\n", sf_name);
sf_offset += len;
sf_size -= len;
}
fclose(outfp);
}
fclose(infp);
return 0;
}