1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9
10 #include <mspack.h>
11 #include "system.h"
12
13 #define FILENAME ".chminfo-temp"
14
load_sys_data(struct mschm_decompressor * chmd,struct mschmd_header * chm,const char * filename,off_t * length_ptr)15 unsigned char *load_sys_data(struct mschm_decompressor *chmd,
16 struct mschmd_header *chm,
17 const char *filename,
18 off_t *length_ptr)
19 {
20 struct mschmd_file *file;
21 unsigned char *data;
22 FILE *fh;
23
24 for (file = chm->sysfiles; file; file = file->next) {
25 if (strcmp(file->filename, filename) == 0) break;
26 }
27 if (!file || file->section->id != 0) return NULL;
28 if (chmd->extract(chmd, file, FILENAME)) return NULL;
29 if (length_ptr) *length_ptr = file->length;
30 if (!(data = (unsigned char *) malloc((size_t) file->length))) return NULL;
31 if ((fh = fopen(FILENAME, "rb"))) {
32 fread(data, (size_t) file->length, 1, fh);
33 fclose(fh);
34 }
35 else {
36 free(data);
37 data = NULL;
38 }
39 unlink(FILENAME);
40 return data;
41 }
42
guid(unsigned char * data)43 char *guid(unsigned char *data) {
44 static char result[43];
45 snprintf(result, sizeof(result),
46 "{%08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X}",
47 EndGetI32(&data[0]),
48 data[4] | (data[5] << 8),
49 data[6] | (data[7] << 8),
50 data[8] | (data[9] << 8),
51 data[10], data[11], data[12], data[13],
52 data[14], data[15], data[16], data[17]);
53 return result;
54 }
55
56 #define READ_ENCINT(var, label) do { \
57 (var) = 0; \
58 do { \
59 if (p > &chunk[chm->chunk_size-2]) goto label; \
60 (var) = ((var) << 7) | (*p & 0x7F); \
61 } while (*p++ & 0x80); \
62 } while (0)
63
print_dir(struct mschmd_header * chm,char * filename)64 void print_dir(struct mschmd_header *chm, char *filename) {
65 unsigned char dir[0x54], *chunk;
66 unsigned int i;
67 FILE *fh;
68
69 if (!(chunk = (unsigned char *) malloc(chm->chunk_size))) return;
70
71 if ((fh = fopen(filename, "rb"))) {
72 #if HAVE_FSEEKO
73 fseeko(fh, chm->dir_offset - 84, SEEK_SET);
74 #else
75 fseek(fh, chm->dir_offset - 84, SEEK_SET);
76 #endif
77 fread(&dir[0], 84, 1, fh);
78 printf(" chmhs1_Signature = %4.4s\n", &dir[0]);
79 printf(" chmhs1_Version = %d\n", EndGetI32(&dir[4]));
80 printf(" chmhs1_HeaderLen = %d\n", EndGetI32(&dir[8]));
81 printf(" chmhs1_Unknown1 = %d\n", EndGetI32(&dir[12]));
82 printf(" chmhs1_ChunkSize = %d\n", EndGetI32(&dir[16]));
83 printf(" chmhs1_Density = %d\n", EndGetI32(&dir[20]));
84 printf(" chmhs1_Depth = %d\n", EndGetI32(&dir[24]));
85 printf(" chmhs1_IndexRoot = %d\n", EndGetI32(&dir[28]));
86 printf(" chmhs1_FirstPMGL = %d\n", EndGetI32(&dir[32]));
87 printf(" chmhs1_LastPMGL = %d\n", EndGetI32(&dir[36]));
88 printf(" chmhs1_Unknown2 = %d\n", EndGetI32(&dir[40]));
89 printf(" chmhs1_NumChunks = %d\n", EndGetI32(&dir[44]));
90 printf(" chmhs1_LanguageID = %d\n", EndGetI32(&dir[48]));
91 printf(" chmhs1_GUID = %s\n", guid(&dir[52]));
92 printf(" chmhs1_Unknown3 = %d\n", EndGetI32(&dir[68]));
93 printf(" chmhs1_Unknown4 = %d\n", EndGetI32(&dir[72]));
94 printf(" chmhs1_Unknown5 = %d\n", EndGetI32(&dir[76]));
95 printf(" chmhs1_Unknown6 = %d\n", EndGetI32(&dir[80]));
96
97 for (i = 0; i < chm->num_chunks; i++) {
98 unsigned int num_entries, quickref_size, j, k;
99 unsigned char *p, *name;
100 printf(" CHUNK %u:\n", i);
101 fread(chunk, chm->chunk_size, 1, fh);
102
103 if ((chunk[0] == 'P') && (chunk[1] == 'M') &&
104 (chunk[2] == 'G') && (chunk[3] == 'L'))
105 {
106 k = chm->chunk_size - 2;
107 num_entries = chunk[k] | (chunk[k+1] << 8);
108 quickref_size = EndGetI32(&chunk[4]);
109 if (quickref_size > (chm->chunk_size - 20)) {
110 printf(" QR size of %d too large (max is %d)\n",
111 quickref_size, chm->chunk_size - 20);
112 quickref_size = chm->chunk_size - 20;
113 }
114 printf(" PMGL entries=%u qrsize=%u zero=%u prev=%d next=%d\n",
115 num_entries, quickref_size, EndGetI32(&chunk[8]),
116 EndGetI32(&chunk[12]), EndGetI32(&chunk[16]));
117
118 printf(" QR: entry %4u = offset %u\n", 0, 20);
119 j = (1 << chm->density) + 1;
120 while (j < num_entries) {
121 k -= 2;
122 if (k < (chm->chunk_size - quickref_size)) break;
123 printf(" QR: entry %4u = offset %u\n",
124 j, (chunk[k] | (chunk[k+1] << 8)) + 20);
125 j += (1 << chm->density) + 1;
126 }
127
128 p = &chunk[20];
129 for (j = 0; j < num_entries; j++) {
130 unsigned int name_len = 0, section = 0, offset = 0, length = 0;
131 printf(" %4d: ", (int) (p - &chunk[0]));
132 READ_ENCINT(name_len, PMGL_end); name = p; p += name_len;
133 READ_ENCINT(section, PMGL_end);
134 READ_ENCINT(offset, PMGL_end);
135 READ_ENCINT(length, PMGL_end);
136 printf("sec=%u off=%-10u len=%-10u name=\"",section,offset,length);
137 if (name_len) fwrite(name, 1, name_len, stdout);
138 printf("\"\n");
139 }
140 PMGL_end:
141 if (j != num_entries) printf("premature end of chunk\n");
142
143 }
144 else if ((chunk[0] == 'P') && (chunk[1] == 'M') &&
145 (chunk[2] == 'G') && (chunk[3] == 'I'))
146 {
147 k = chm->chunk_size - 2;
148 num_entries = chunk[k] | (chunk[k+1] << 8);
149 quickref_size = EndGetI32(&chunk[4]);
150 printf(" PMGI entries=%u free=%u\n", num_entries, quickref_size);
151
152 printf(" QR: entry %4u = offset %u\n", 0, 8);
153 j = (1 << chm->density) + 1;
154 while (j < num_entries) {
155 k -= 2;
156 printf(" QR: entry %4u = offset %u\n",
157 j, (chunk[k] | (chunk[k+1] << 8)) + 8);
158 j += (1 << chm->density) + 1;
159 }
160
161 p = &chunk[8];
162 for (j = 0; j < num_entries; j++) {
163 unsigned int name_len, section;
164 printf(" %4d: ", (int) (p - &chunk[0]));
165 READ_ENCINT(name_len, PMGI_end); name = p; p += name_len;
166 READ_ENCINT(section, PMGI_end);
167 printf("chunk=%-4u name=\"",section);
168 if (name_len) fwrite(name, 1, name_len, stdout);
169 printf("\"\n");
170 }
171 PMGI_end:
172 if (j != num_entries) printf("premature end of chunk\n");
173 }
174 else {
175 printf(" unknown format\n");
176 }
177 }
178
179 fclose(fh);
180 }
181 }
182
183
main(int argc,char * argv[])184 int main(int argc, char *argv[]) {
185 struct mschm_decompressor *chmd;
186 struct mschmd_header *chm;
187 struct mschmd_file *file;
188 unsigned int numf, i;
189 unsigned char *data;
190 off_t pos, len;
191
192 setbuf(stdout, NULL);
193 setbuf(stderr, NULL);
194
195 MSPACK_SYS_SELFTEST(i);
196 if (i) return 0;
197
198 if ((chmd = mspack_create_chm_decompressor(NULL))) {
199 for (argv++; *argv; argv++) {
200 printf("%s\n", *argv);
201 if ((chm = chmd->open(chmd, *argv))) {
202 printf(" chmhead_Version %u\n", chm->version);
203 printf(" chmhead_Timestamp %u\n", chm->timestamp);
204 printf(" chmhead_LanguageID %u\n", chm->language);
205 printf(" chmhs0_FileLen %" LD "\n", chm->length);
206 printf(" chmhst_OffsetHS1 %" LD "\n", chm->dir_offset);
207 printf(" chmhst3_OffsetCS0 %" LD "\n", chm->sec0.offset);
208
209 print_dir(chm, *argv);
210
211 if ((data = load_sys_data(chmd, chm,
212 "::DataSpace/Storage/MSCompressed/ControlData", &len)))
213 {
214 printf(" lzxcd_Length %u\n", EndGetI32(&data[0]));
215 printf(" lzxcd_Signature %4.4s\n", &data[4]);
216 printf(" lzxcd_Version %u\n", EndGetI32(&data[8]));
217 printf(" lzxcd_ResetInterval %u\n", EndGetI32(&data[12]));
218 printf(" lzxcd_WindowSize %u\n", EndGetI32(&data[16]));
219 printf(" lzxcd_CacheSize %u\n", EndGetI32(&data[20]));
220 printf(" lzxcd_Unknown1 %u\n", EndGetI32(&data[24]));
221 free(data);
222 }
223
224 if ((data = load_sys_data(chmd, chm,
225 "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-"
226 "9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable", &len)))
227 {
228 off_t contents = chm->sec0.offset;
229 printf(" lzxrt_Unknown1 %u\n", EndGetI32(&data[0]));
230 printf(" lzxrt_NumEntries %u\n", EndGetI32(&data[4]));
231 printf(" lzxrt_EntrySize %u\n", EndGetI32(&data[8]));
232 printf(" lzxrt_TableOffset %u\n", EndGetI32(&data[12]));
233 printf(" lzxrt_UncompLen %llu\n", EndGetI64(&data[16]));
234 printf(" lzxrt_CompLen %llu\n", EndGetI64(&data[24]));
235 printf(" lzxrt_FrameLen %u\n", EndGetI32(&data[32]));
236
237 for (file = chm->sysfiles; file; file = file->next) {
238 if (strcmp(file->filename,
239 "::DataSpace/Storage/MSCompressed/Content") == 0)
240 {
241 contents += file->offset;
242 break;
243 }
244 }
245
246 printf(" - reset table (uncomp offset -> stream offset "
247 "[real offset, length in file]\n");
248
249 numf = EndGetI32(&data[4]);
250 pos = ((unsigned int) EndGetI32(&data[12]));
251 switch (EndGetI32(&data[8])) {
252 case 4:
253 for (i = 0; i < numf && pos < len; i++, pos += 4) {
254 unsigned int rtdata = EndGetI32(&data[pos]);
255 printf(" %-10u -> %-10u [ %" LU " %u ]\n",
256 i * EndGetI32(&data[32]),
257 rtdata,
258 contents + rtdata,
259 (i == (numf-1))
260 ? (EndGetI32(&data[24]) - rtdata)
261 : (EndGetI32(&data[pos + 4]) - rtdata)
262 );
263 }
264 break;
265 case 8:
266 for (i = 0; i < numf && pos < len; i++, pos += 8) {
267 unsigned long long int rtdata = EndGetI64(&data[pos]);
268 printf(" %-10llu -> %-10llu [ %llu %llu ]\n",
269 i * EndGetI64(&data[32]), rtdata, contents + rtdata,
270 (i == (numf-1))
271 ? (EndGetI64(&data[24]) - rtdata)
272 : (EndGetI64(&data[pos + 8]) - rtdata)
273 );
274 }
275 break;
276 }
277 free(data);
278 }
279 chmd->close(chmd, chm);
280 }
281 }
282 mspack_destroy_chm_decompressor(chmd);
283 }
284 return 0;
285 }
286