libmspack 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +5 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +4 -0
  6. data/README.md +75 -0
  7. data/Rakefile +22 -0
  8. data/UNLICENSE +24 -0
  9. data/ext/Rakefile +16 -0
  10. data/ext/i386-windows/libmspack.dll +0 -0
  11. data/ext/libmspack/AUTHORS +12 -0
  12. data/ext/libmspack/COPYING.LIB +504 -0
  13. data/ext/libmspack/ChangeLog +491 -0
  14. data/ext/libmspack/Makefile.am +100 -0
  15. data/ext/libmspack/NEWS +0 -0
  16. data/ext/libmspack/README +130 -0
  17. data/ext/libmspack/TODO +8 -0
  18. data/ext/libmspack/cleanup.sh +9 -0
  19. data/ext/libmspack/configure.ac +50 -0
  20. data/ext/libmspack/debian/changelog +6 -0
  21. data/ext/libmspack/debian/control +14 -0
  22. data/ext/libmspack/debian/rules +101 -0
  23. data/ext/libmspack/doc/Doxyfile.in +22 -0
  24. data/ext/libmspack/doc/Makefile.in +14 -0
  25. data/ext/libmspack/doc/szdd_kwaj_format.html +331 -0
  26. data/ext/libmspack/libmspack.pc.in +10 -0
  27. data/ext/libmspack/mspack/cab.h +127 -0
  28. data/ext/libmspack/mspack/cabc.c +24 -0
  29. data/ext/libmspack/mspack/cabd.c +1444 -0
  30. data/ext/libmspack/mspack/chm.h +122 -0
  31. data/ext/libmspack/mspack/chmc.c +24 -0
  32. data/ext/libmspack/mspack/chmd.c +1392 -0
  33. data/ext/libmspack/mspack/crc32.c +95 -0
  34. data/ext/libmspack/mspack/crc32.h +17 -0
  35. data/ext/libmspack/mspack/des.h +15 -0
  36. data/ext/libmspack/mspack/hlp.h +33 -0
  37. data/ext/libmspack/mspack/hlpc.c +24 -0
  38. data/ext/libmspack/mspack/hlpd.c +24 -0
  39. data/ext/libmspack/mspack/kwaj.h +118 -0
  40. data/ext/libmspack/mspack/kwajc.c +24 -0
  41. data/ext/libmspack/mspack/kwajd.c +561 -0
  42. data/ext/libmspack/mspack/lit.h +35 -0
  43. data/ext/libmspack/mspack/litc.c +24 -0
  44. data/ext/libmspack/mspack/litd.c +24 -0
  45. data/ext/libmspack/mspack/lzss.h +66 -0
  46. data/ext/libmspack/mspack/lzssd.c +93 -0
  47. data/ext/libmspack/mspack/lzx.h +221 -0
  48. data/ext/libmspack/mspack/lzxc.c +18 -0
  49. data/ext/libmspack/mspack/lzxd.c +895 -0
  50. data/ext/libmspack/mspack/mspack.def +28 -0
  51. data/ext/libmspack/mspack/mspack.h +2353 -0
  52. data/ext/libmspack/mspack/mszip.h +126 -0
  53. data/ext/libmspack/mspack/mszipc.c +18 -0
  54. data/ext/libmspack/mspack/mszipd.c +514 -0
  55. data/ext/libmspack/mspack/oab.h +60 -0
  56. data/ext/libmspack/mspack/oabc.c +24 -0
  57. data/ext/libmspack/mspack/oabd.c +408 -0
  58. data/ext/libmspack/mspack/qtm.h +128 -0
  59. data/ext/libmspack/mspack/qtmc.c +18 -0
  60. data/ext/libmspack/mspack/qtmd.c +489 -0
  61. data/ext/libmspack/mspack/readbits.h +207 -0
  62. data/ext/libmspack/mspack/readhuff.h +173 -0
  63. data/ext/libmspack/mspack/sha.h +15 -0
  64. data/ext/libmspack/mspack/system.c +239 -0
  65. data/ext/libmspack/mspack/system.h +124 -0
  66. data/ext/libmspack/mspack/szdd.h +39 -0
  67. data/ext/libmspack/mspack/szddc.c +24 -0
  68. data/ext/libmspack/mspack/szddd.c +247 -0
  69. data/ext/libmspack/rebuild.sh +8 -0
  70. data/ext/libmspack/test/cabd_c10 +19 -0
  71. data/ext/libmspack/test/cabd_compare +34 -0
  72. data/ext/libmspack/test/cabd_md5.c +161 -0
  73. data/ext/libmspack/test/cabd_memory.c +179 -0
  74. data/ext/libmspack/test/cabd_test.c +386 -0
  75. data/ext/libmspack/test/cabrip.c +81 -0
  76. data/ext/libmspack/test/chmd_compare +38 -0
  77. data/ext/libmspack/test/chmd_find.c +95 -0
  78. data/ext/libmspack/test/chmd_md5.c +67 -0
  79. data/ext/libmspack/test/chmd_order.c +144 -0
  80. data/ext/libmspack/test/chminfo.c +284 -0
  81. data/ext/libmspack/test/chmx.c +216 -0
  82. data/ext/libmspack/test/error.h +22 -0
  83. data/ext/libmspack/test/expand.c +79 -0
  84. data/ext/libmspack/test/md5.c +457 -0
  85. data/ext/libmspack/test/md5.h +165 -0
  86. data/ext/libmspack/test/md5_fh.h +123 -0
  87. data/ext/libmspack/test/msdecompile_md5 +24 -0
  88. data/ext/libmspack/test/msexpand_md5 +39 -0
  89. data/ext/libmspack/test/multifh.c +435 -0
  90. data/ext/libmspack/test/oabx.c +41 -0
  91. data/ext/libmspack/test/test_files/cabd/1.pl +84 -0
  92. data/ext/libmspack/test/test_files/cabd/2.pl +75 -0
  93. data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
  94. data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
  95. data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
  96. data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
  97. data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
  98. data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
  99. data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
  100. data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
  101. data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
  102. data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
  103. data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
  104. data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
  105. data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
  106. data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
  107. data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
  108. data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
  109. data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
  110. data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
  111. data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
  112. data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
  113. data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
  114. data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
  115. data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
  116. data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
  117. data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
  118. data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
  119. data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
  120. data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
  121. data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
  122. data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
  123. data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
  124. data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
  125. data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
  126. data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
  127. data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
  128. data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
  129. data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
  130. data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
  131. data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
  132. data/ext/libmspack/winbuild.sh +26 -0
  133. data/ext/x86_64-windows/libmspack.dll +0 -0
  134. data/lib/libmspack/constants.rb +9 -0
  135. data/lib/libmspack/exceptions.rb +12 -0
  136. data/lib/libmspack/mscab.rb +722 -0
  137. data/lib/libmspack/mschm.rb +301 -0
  138. data/lib/libmspack/mshlp.rb +15 -0
  139. data/lib/libmspack/mskwaj.rb +124 -0
  140. data/lib/libmspack/mslit.rb +18 -0
  141. data/lib/libmspack/msoab.rb +36 -0
  142. data/lib/libmspack/mspack.rb +208 -0
  143. data/lib/libmspack/msszdd.rb +81 -0
  144. data/lib/libmspack/system.rb +84 -0
  145. data/lib/libmspack/version.rb +4 -0
  146. data/lib/libmspack.rb +121 -0
  147. data/libmspack.gemspec +33 -0
  148. data/spec/libmspack_spec.rb +26 -0
  149. data/spec/spec_helper.rb +5 -0
  150. metadata +309 -0
@@ -0,0 +1,144 @@
1
+ /* chmd_order: test that extracting a CHM file in different ways works
2
+ * and all give the same results:
3
+ * - extracting files in the order they're listed (generally alphabetical)
4
+ * - extracting files ordered by their content section offset
5
+ * - extracting files using fast_find() to find them
6
+ * - extracting files from two chms at the same time with one decompressor
7
+ */
8
+ #ifdef HAVE_CONFIG_H
9
+ #include <config.h>
10
+ #endif
11
+
12
+ #include <stdio.h>
13
+ #include <stdlib.h>
14
+ #include <string.h>
15
+ #include <mspack.h>
16
+
17
+ #include <md5_fh.h>
18
+ #include <error.h>
19
+
20
+ struct my_file {
21
+ struct mschmd_file *file;
22
+ struct mschmd_file result;
23
+ char ordered[32], sorted[32], fast_find[32], mixed[32];
24
+ };
25
+
26
+ static int sortfunc(const void *a, const void *b) {
27
+ off_t diff =
28
+ ((struct my_file *) a)->file->offset -
29
+ ((struct my_file *) b)->file->offset;
30
+ return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
31
+ }
32
+
33
+ int main(int argc, char *argv[]) {
34
+ struct mschm_decompressor *chmd;
35
+ struct mschmd_header *chm, *chm2;
36
+ struct mschmd_file *file;
37
+ struct my_file *f;
38
+ unsigned int N, i;
39
+
40
+ MSPACK_SYS_SELFTEST(i);
41
+ if (i) return 0;
42
+
43
+ if ((chmd = mspack_create_chm_decompressor(&read_files_write_md5))) {
44
+ for (argv++; *argv; argv++) {
45
+ printf("%s\n", *argv);
46
+
47
+ if ((chm = chmd->open(chmd, *argv))) {
48
+ if ((chm2 = chmd->fast_open(chmd, *argv))) {
49
+
50
+ /* count the number of files, allocate a results structure */
51
+ for (N=0, file = chm->files; file; file = file->next) N++;
52
+ if ((f = (struct my_file *) calloc(N, sizeof(struct my_file)))) {
53
+
54
+ /* fill out results structure while doing ordered extraction */
55
+ for (i = 0, file = chm->files; file; file = file->next, i++) {
56
+ printf("OX %s\n", file->filename);
57
+ f[i].file = file;
58
+ if (chmd->extract(chmd, file, NULL)) {
59
+ fprintf(stderr, "%s: O extract error on \"%s\": %s\n",
60
+ *argv, file->filename, ERROR(chmd));
61
+ continue;
62
+ }
63
+ memcpy(&f[i].ordered[0], md5_string, 32);
64
+ }
65
+
66
+ /* sort the list into offset order */
67
+ qsort(f, N, sizeof(struct my_file), &sortfunc);
68
+
69
+ /* extract in offset order */
70
+ for (i = 0; i < N; i++) {
71
+ printf("SX %s\n", f[i].file->filename);
72
+ if (chmd->extract(chmd, f[i].file, NULL)) {
73
+ fprintf(stderr, "%s: S extract error on \"%s\": %s\n",
74
+ *argv, f[i].file->filename, ERROR(chmd));
75
+ continue;
76
+ }
77
+ memcpy(&f[i].sorted[0], md5_string, 32);
78
+ }
79
+
80
+ /* extract using fast_find */
81
+ for (i = 0; i < N; i++) {
82
+ printf("FX %s\n", f[i].file->filename);
83
+
84
+ if (chmd->fast_find(chmd, chm2,
85
+ f[i].file->filename,
86
+ &f[i].result, sizeof(struct mschmd_file)))
87
+ {
88
+ fprintf(stderr, "%s: find error on \"%s\": %s\n",
89
+ *argv, f[i].file->filename, ERROR(chmd));
90
+ continue;
91
+ }
92
+ if (!f[i].result.section) {
93
+ fprintf(stderr, "%s: can't find file \"%s\"\n",
94
+ *argv, f[i].file->filename);
95
+ continue;
96
+ }
97
+ if (chmd->extract(chmd, &f[i].result, NULL)) {
98
+ fprintf(stderr, "%s: F extract error on \"%s\": %s\n",
99
+ *argv, f[i].file->filename, ERROR(chmd));
100
+ continue;
101
+ }
102
+ memcpy(&f[i].fast_find[0], md5_string, 32);
103
+ }
104
+
105
+ /* extract two chms at once */
106
+ for (i = 0; i < N; i++) {
107
+ printf("MX %s\n", f[i].file->filename);
108
+ chmd->extract(chmd, f[i].file, NULL);
109
+ if (chmd->extract(chmd, &f[i].result, NULL)) {
110
+ fprintf(stderr, "%s: M extract error on \"%s\": %s\n",
111
+ *argv, f[i].file->filename, ERROR(chmd));
112
+ continue;
113
+ }
114
+ memcpy(&f[i].mixed[0], md5_string, 32);
115
+ }
116
+
117
+ /* check all the MD5 sums match */
118
+ for (i = 0; i < N; i++) {
119
+ if (memcmp(&f[i].ordered, &f[i].sorted, 32) ||
120
+ memcmp(&f[i].ordered, &f[i].fast_find, 32) ||
121
+ memcmp(&f[i].ordered, &f[i].mixed, 32))
122
+ {
123
+ fprintf(stderr, "%s: sums mismatch on %s "
124
+ "(O=%32.32s,S=%32.32s,F=%32.32s,M=%32.32s)\n",
125
+ *argv, f[i].file->filename,
126
+ &f[i].ordered[0], &f[i].sorted[0],
127
+ &f[i].fast_find[0], &f[i].mixed[0]);
128
+ }
129
+ }
130
+
131
+ free(f);
132
+ }
133
+ chmd->close(chmd, chm2);
134
+ }
135
+ chmd->close(chmd, chm);
136
+ }
137
+ else {
138
+ printf("%s: can't open -- %s\n", *argv, ERROR(chmd));
139
+ }
140
+ }
141
+ mspack_destroy_chm_decompressor(chmd);
142
+ }
143
+ return 0;
144
+ }
@@ -0,0 +1,284 @@
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
+ #include <mspack.h>
10
+ #include <system.h>
11
+
12
+ #define FILENAME ".chminfo-temp"
13
+
14
+ unsigned char *load_sys_data(struct mschm_decompressor *chmd,
15
+ struct mschmd_header *chm,
16
+ const char *filename,
17
+ off_t *length_ptr)
18
+ {
19
+ struct mschmd_file *file;
20
+ unsigned char *data;
21
+ FILE *fh;
22
+
23
+ for (file = chm->sysfiles; file; file = file->next) {
24
+ if (strcmp(file->filename, filename) == 0) break;
25
+ }
26
+ if (!file || file->section->id != 0) return NULL;
27
+ if (chmd->extract(chmd, file, FILENAME)) return NULL;
28
+ if (length_ptr) *length_ptr = file->length;
29
+ if (!(data = (unsigned char *) malloc((size_t) file->length))) return NULL;
30
+ if ((fh = fopen(FILENAME, "rb"))) {
31
+ fread(data, (size_t) file->length, 1, fh);
32
+ fclose(fh);
33
+ }
34
+ else {
35
+ free(data);
36
+ data = NULL;
37
+ }
38
+ unlink(FILENAME);
39
+ return data;
40
+ }
41
+
42
+ char *guid(unsigned char *data) {
43
+ static char result[43];
44
+ snprintf(result, sizeof(result),
45
+ "{%08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X%02X%02X}",
46
+ EndGetI32(&data[0]),
47
+ data[4] | (data[5] << 8),
48
+ data[6] | (data[7] << 8),
49
+ data[8] | (data[9] << 8),
50
+ data[10], data[11], data[12], data[13],
51
+ data[14], data[15], data[16], data[17]);
52
+ return result;
53
+ }
54
+
55
+ #define READ_ENCINT(var, label) do { \
56
+ (var) = 0; \
57
+ do { \
58
+ if (p > &chunk[chm->chunk_size-2]) goto label; \
59
+ (var) = ((var) << 7) | (*p & 0x7F); \
60
+ } while (*p++ & 0x80); \
61
+ } while (0)
62
+
63
+ void print_dir(struct mschmd_header *chm, char *filename) {
64
+ unsigned char dir[0x54], *chunk;
65
+ unsigned int i;
66
+ FILE *fh;
67
+
68
+ if (!(chunk = (unsigned char *) malloc(chm->chunk_size))) return;
69
+
70
+ if ((fh = fopen(filename, "rb"))) {
71
+ #ifdef HAVE_FSEEKO
72
+ fseeko(fh, chm->dir_offset - 84, SEEK_SET);
73
+ #else
74
+ fseek(fh, chm->dir_offset - 84, SEEK_SET);
75
+ #endif
76
+ fread(&dir[0], 84, 1, fh);
77
+ printf(" chmhs1_Signature = %4.4s\n", &dir[0]);
78
+ printf(" chmhs1_Version = %d\n", EndGetI32(&dir[4]));
79
+ printf(" chmhs1_HeaderLen = %d\n", EndGetI32(&dir[8]));
80
+ printf(" chmhs1_Unknown1 = %d\n", EndGetI32(&dir[12]));
81
+ printf(" chmhs1_ChunkSize = %d\n", EndGetI32(&dir[16]));
82
+ printf(" chmhs1_Density = %d\n", EndGetI32(&dir[20]));
83
+ printf(" chmhs1_Depth = %d\n", EndGetI32(&dir[24]));
84
+ printf(" chmhs1_IndexRoot = %d\n", EndGetI32(&dir[28]));
85
+ printf(" chmhs1_FirstPMGL = %d\n", EndGetI32(&dir[32]));
86
+ printf(" chmhs1_LastPMGL = %d\n", EndGetI32(&dir[36]));
87
+ printf(" chmhs1_Unknown2 = %d\n", EndGetI32(&dir[40]));
88
+ printf(" chmhs1_NumChunks = %d\n", EndGetI32(&dir[44]));
89
+ printf(" chmhs1_LanguageID = %d\n", EndGetI32(&dir[48]));
90
+ printf(" chmhs1_GUID = %s\n", guid(&dir[52]));
91
+ printf(" chmhs1_Unknown3 = %d\n", EndGetI32(&dir[68]));
92
+ printf(" chmhs1_Unknown4 = %d\n", EndGetI32(&dir[72]));
93
+ printf(" chmhs1_Unknown5 = %d\n", EndGetI32(&dir[76]));
94
+ printf(" chmhs1_Unknown6 = %d\n", EndGetI32(&dir[80]));
95
+
96
+ for (i = 0; i < chm->num_chunks; i++) {
97
+ unsigned int num_entries, quickref_size, j, k;
98
+ unsigned char *p, *name;
99
+ printf(" CHUNK %u:\n", i);
100
+ fread(chunk, chm->chunk_size, 1, fh);
101
+
102
+ if ((chunk[0] == 'P') && (chunk[1] == 'M') &&
103
+ (chunk[2] == 'G') && (chunk[3] == 'L'))
104
+ {
105
+ k = chm->chunk_size - 2;
106
+ num_entries = chunk[k] | (chunk[k+1] << 8);
107
+ quickref_size = EndGetI32(&chunk[4]);
108
+ if (quickref_size > (chm->chunk_size - 20)) {
109
+ printf(" QR size of %d too large (max is %d)\n",
110
+ quickref_size, chm->chunk_size - 20);
111
+ quickref_size = chm->chunk_size - 20;
112
+ }
113
+ printf(" PMGL entries=%u qrsize=%u zero=%u prev=%d next=%d\n",
114
+ num_entries, quickref_size, EndGetI32(&chunk[8]),
115
+ EndGetI32(&chunk[12]), EndGetI32(&chunk[16]));
116
+
117
+ printf(" QR: entry %4u = offset %u\n", 0, 20);
118
+ j = (1 << chm->density) + 1;
119
+ while (j < num_entries) {
120
+ k -= 2;
121
+ if (k < (chm->chunk_size - quickref_size)) break;
122
+ printf(" QR: entry %4u = offset %u\n",
123
+ j, (chunk[k] | (chunk[k+1] << 8)) + 20);
124
+ j += (1 << chm->density) + 1;
125
+ }
126
+
127
+ p = &chunk[20];
128
+ for (j = 0; j < num_entries; j++) {
129
+ unsigned int name_len = 0, section = 0, offset = 0, length = 0;
130
+ printf(" %4d: ", (int) (p - &chunk[0]));
131
+ READ_ENCINT(name_len, PMGL_end); name = p; p += name_len;
132
+ READ_ENCINT(section, PMGL_end);
133
+ READ_ENCINT(offset, PMGL_end);
134
+ READ_ENCINT(length, PMGL_end);
135
+ printf("sec=%u off=%-10u len=%-10u name=\"",section,offset,length);
136
+ if (name_len) fwrite(name, 1, name_len, stdout);
137
+ printf("\"\n");
138
+ }
139
+ PMGL_end:
140
+ if (j != num_entries) printf("premature end of chunk\n");
141
+
142
+ }
143
+ else if ((chunk[0] == 'P') && (chunk[1] == 'M') &&
144
+ (chunk[2] == 'G') && (chunk[3] == 'I'))
145
+ {
146
+ k = chm->chunk_size - 2;
147
+ num_entries = chunk[k] | (chunk[k+1] << 8);
148
+ quickref_size = EndGetI32(&chunk[4]);
149
+ printf(" PMGI entries=%u free=%u\n", num_entries, quickref_size);
150
+
151
+ printf(" QR: entry %4u = offset %u\n", 0, 8);
152
+ j = (1 << chm->density) + 1;
153
+ while (j < num_entries) {
154
+ k -= 2;
155
+ printf(" QR: entry %4u = offset %u\n",
156
+ j, (chunk[k] | (chunk[k+1] << 8)) + 8);
157
+ j += (1 << chm->density) + 1;
158
+ }
159
+
160
+ p = &chunk[8];
161
+ for (j = 0; j < num_entries; j++) {
162
+ unsigned int name_len, section;
163
+ printf(" %4d: ", (int) (p - &chunk[0]));
164
+ READ_ENCINT(name_len, PMGI_end); name = p; p += name_len;
165
+ READ_ENCINT(section, PMGI_end);
166
+ printf("chunk=%-4u name=\"",section);
167
+ if (name_len) fwrite(name, 1, name_len, stdout);
168
+ printf("\"\n");
169
+ }
170
+ PMGI_end:
171
+ if (j != num_entries) printf("premature end of chunk\n");
172
+ }
173
+ else {
174
+ printf(" unknown format\n");
175
+ }
176
+ }
177
+
178
+ fclose(fh);
179
+ }
180
+ }
181
+
182
+
183
+ int main(int argc, char *argv[]) {
184
+ struct mschm_decompressor *chmd;
185
+ struct mschmd_header *chm;
186
+ struct mschmd_file *file;
187
+ unsigned int numf, i;
188
+ unsigned char *data;
189
+ off_t pos, len;
190
+
191
+ setbuf(stdout, NULL);
192
+ setbuf(stderr, NULL);
193
+
194
+ MSPACK_SYS_SELFTEST(i);
195
+ if (i) return 0;
196
+
197
+ if ((chmd = mspack_create_chm_decompressor(NULL))) {
198
+ for (argv++; *argv; argv++) {
199
+ printf("%s\n", *argv);
200
+ if ((chm = chmd->open(chmd, *argv))) {
201
+ printf(" chmhead_Version %u\n", chm->version);
202
+ printf(" chmhead_Timestamp %u\n", chm->timestamp);
203
+ printf(" chmhead_LanguageID %u\n", chm->language);
204
+ printf(" chmhs0_FileLen %" LD "\n", chm->length);
205
+ printf(" chmhst_OffsetHS1 %" LD "\n", chm->dir_offset);
206
+ printf(" chmhst3_OffsetCS0 %" LD "\n", chm->sec0.offset);
207
+
208
+ print_dir(chm, *argv);
209
+
210
+ if ((data = load_sys_data(chmd, chm,
211
+ "::DataSpace/Storage/MSCompressed/ControlData", &len)))
212
+ {
213
+ printf(" lzxcd_Length %u\n", EndGetI32(&data[0]));
214
+ printf(" lzxcd_Signature %4.4s\n", &data[4]);
215
+ printf(" lzxcd_Version %u\n", EndGetI32(&data[8]));
216
+ printf(" lzxcd_ResetInterval %u\n", EndGetI32(&data[12]));
217
+ printf(" lzxcd_WindowSize %u\n", EndGetI32(&data[16]));
218
+ printf(" lzxcd_CacheSize %u\n", EndGetI32(&data[20]));
219
+ printf(" lzxcd_Unknown1 %u\n", EndGetI32(&data[24]));
220
+ free(data);
221
+ }
222
+
223
+ if ((data = load_sys_data(chmd, chm,
224
+ "::DataSpace/Storage/MSCompressed/Transform/{7FC28940-"
225
+ "9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable", &len)))
226
+ {
227
+ off_t contents = chm->sec0.offset;
228
+ printf(" lzxrt_Unknown1 %u\n", EndGetI32(&data[0]));
229
+ printf(" lzxrt_NumEntries %u\n", EndGetI32(&data[4]));
230
+ printf(" lzxrt_EntrySize %u\n", EndGetI32(&data[8]));
231
+ printf(" lzxrt_TableOffset %u\n", EndGetI32(&data[12]));
232
+ printf(" lzxrt_UncompLen %" LU "\n", EndGetI64(&data[16]));
233
+ printf(" lzxrt_CompLen %" LU "\n", EndGetI64(&data[24]));
234
+ printf(" lzxrt_FrameLen %u\n", EndGetI32(&data[32]));
235
+
236
+ for (file = chm->sysfiles; file; file = file->next) {
237
+ if (strcmp(file->filename,
238
+ "::DataSpace/Storage/MSCompressed/Content") == 0)
239
+ {
240
+ contents += file->offset;
241
+ break;
242
+ }
243
+ }
244
+
245
+ printf(" - reset table (uncomp offset -> stream offset "
246
+ "[real offset, length in file]\n");
247
+
248
+ numf = EndGetI32(&data[4]);
249
+ pos = ((unsigned int) EndGetI32(&data[12]));
250
+ switch (EndGetI32(&data[8])) {
251
+ case 4:
252
+ for (i = 0; i < numf && pos < len; i++, pos += 4) {
253
+ unsigned int rtdata = EndGetI32(&data[pos]);
254
+ printf(" %-10u -> %-10u [ %" LU " %u ]\n",
255
+ i * EndGetI32(&data[32]),
256
+ rtdata,
257
+ contents + rtdata,
258
+ (i == (numf-1))
259
+ ? (EndGetI32(&data[24]) - rtdata)
260
+ : (EndGetI32(&data[pos + 4]) - rtdata)
261
+ );
262
+ }
263
+ break;
264
+ case 8:
265
+ for (i = 0; i < numf && pos < len; i++, pos += 8) {
266
+ unsigned long long int rtdata = EndGetI64(&data[pos]);
267
+ printf(" %-10" LU " -> %-10" LU " [ %" LU " %" LU " ]\n",
268
+ i * EndGetI64(&data[32]), rtdata, contents + rtdata,
269
+ (i == (numf-1))
270
+ ? (EndGetI64(&data[24]) - rtdata)
271
+ : (EndGetI64(&data[pos + 8]) - rtdata)
272
+ );
273
+ }
274
+ break;
275
+ }
276
+ free(data);
277
+ }
278
+ chmd->close(chmd, chm);
279
+ }
280
+ }
281
+ mspack_destroy_chm_decompressor(chmd);
282
+ }
283
+ return 0;
284
+ }
@@ -0,0 +1,216 @@
1
+ #ifdef HAVE_CONFIG_H
2
+ #include <config.h>
3
+ #endif
4
+
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <mspack.h>
9
+ #include <ctype.h>
10
+ #include <sys/stat.h>
11
+
12
+ #include <error.h>
13
+
14
+ mode_t user_umask;
15
+
16
+ #define FILENAME ".test.chmx"
17
+
18
+ /**
19
+ * Ensures that all directory components in a filepath exist. New directory
20
+ * components are created, if necessary.
21
+ *
22
+ * @param path the filepath to check
23
+ * @return non-zero if all directory components in a filepath exist, zero
24
+ * if components do not exist and cannot be created
25
+ */
26
+ static int ensure_filepath(char *path) {
27
+ struct stat st_buf;
28
+ char *p;
29
+ int ok;
30
+
31
+ for (p = &path[1]; *p; p++) {
32
+ if (*p != '/') continue;
33
+ *p = '\0';
34
+ ok = (stat(path, &st_buf) == 0) && S_ISDIR(st_buf.st_mode);
35
+ if (!ok) ok = (mkdir(path, 0777 & ~user_umask) == 0);
36
+ *p = '/';
37
+ if (!ok) return 0;
38
+ }
39
+ return 1;
40
+ }
41
+
42
+ /**
43
+ * Creates a UNIX filename from the internal CAB filename and the given
44
+ * parameters.
45
+ *
46
+ * @param fname the internal CAB filename.
47
+ * @param dir a directory path to prepend to the output filename.
48
+ * @param lower if non-zero, filename should be made lower-case.
49
+ * @param isunix if zero, MS-DOS path seperators are used in the internal
50
+ * CAB filename. If non-zero, UNIX path seperators are used.
51
+ * @param utf8 if non-zero, the internal CAB filename is encoded in UTF8.
52
+ * @return a freshly allocated and created filename, or NULL if there was
53
+ * not enough memory.
54
+ * @see unix_path_seperators()
55
+ */
56
+ static char *create_output_name(unsigned char *fname, unsigned char *dir,
57
+ int lower, int isunix, int utf8)
58
+ {
59
+ unsigned char *p, *name, c, *fe, sep, slash;
60
+ unsigned int x;
61
+
62
+ sep = (isunix) ? '/' : '\\'; /* the path-seperator */
63
+ slash = (isunix) ? '\\' : '/'; /* the other slash */
64
+
65
+ /* length of filename */
66
+ x = strlen((char *) fname);
67
+ /* UTF8 worst case scenario: tolower() expands all chars from 1 to 3 bytes */
68
+ if (utf8) x *= 3;
69
+ /* length of output directory */
70
+ if (dir) x += strlen((char *) dir);
71
+
72
+ if (!(name = (unsigned char *) malloc(x + 2))) {
73
+ fprintf(stderr, "out of memory!\n");
74
+ return NULL;
75
+ }
76
+
77
+ /* start with blank name */
78
+ *name = '\0';
79
+
80
+ /* add output directory if needed */
81
+ if (dir) {
82
+ strcpy((char *) name, (char *) dir);
83
+ strcat((char *) name, "/");
84
+ }
85
+
86
+ /* remove leading slashes */
87
+ while (*fname == sep) fname++;
88
+
89
+ /* copy from fi->filename to new name, converting MS-DOS slashes to UNIX
90
+ * slashes as we go. Also lowercases characters if needed.
91
+ */
92
+ p = &name[strlen((char *)name)];
93
+ fe = &fname[strlen((char *)fname)];
94
+
95
+ if (utf8) {
96
+ /* UTF8 translates two-byte unicode characters into 1, 2 or 3 bytes.
97
+ * %000000000xxxxxxx -> %0xxxxxxx
98
+ * %00000xxxxxyyyyyy -> %110xxxxx %10yyyyyy
99
+ * %xxxxyyyyyyzzzzzz -> %1110xxxx %10yyyyyy %10zzzzzz
100
+ *
101
+ * Therefore, the inverse is as follows:
102
+ * First char:
103
+ * 0x00 - 0x7F = one byte char
104
+ * 0x80 - 0xBF = invalid
105
+ * 0xC0 - 0xDF = 2 byte char (next char only 0x80-0xBF is valid)
106
+ * 0xE0 - 0xEF = 3 byte char (next 2 chars only 0x80-0xBF is valid)
107
+ * 0xF0 - 0xFF = invalid
108
+ */
109
+ do {
110
+ if (fname >= fe) {
111
+ free(name);
112
+ return NULL;
113
+ }
114
+
115
+ /* get next UTF8 char */
116
+ if ((c = *fname++) < 0x80) x = c;
117
+ else {
118
+ if ((c >= 0xC0) && (c < 0xE0)) {
119
+ x = (c & 0x1F) << 6;
120
+ x |= *fname++ & 0x3F;
121
+ }
122
+ else if ((c >= 0xE0) && (c < 0xF0)) {
123
+ x = (c & 0xF) << 12;
124
+ x |= (*fname++ & 0x3F) << 6;
125
+ x |= *fname++ & 0x3F;
126
+ }
127
+ else x = '?';
128
+ }
129
+
130
+ /* whatever is the path seperator -> '/'
131
+ * whatever is the other slash -> '\\'
132
+ * otherwise, if lower is set, the lowercase version */
133
+ if (x == sep) x = '/';
134
+ else if (x == slash) x = '\\';
135
+ else if (lower) x = (unsigned int) tolower((int) x);
136
+
137
+ /* integer back to UTF8 */
138
+ if (x < 0x80) {
139
+ *p++ = (unsigned char) x;
140
+ }
141
+ else if (x < 0x800) {
142
+ *p++ = 0xC0 | (x >> 6);
143
+ *p++ = 0x80 | (x & 0x3F);
144
+ }
145
+ else {
146
+ *p++ = 0xE0 | (x >> 12);
147
+ *p++ = 0x80 | ((x >> 6) & 0x3F);
148
+ *p++ = 0x80 | (x & 0x3F);
149
+ }
150
+ } while (x);
151
+ }
152
+ else {
153
+ /* regular non-utf8 version */
154
+ do {
155
+ c = *fname++;
156
+ if (c == sep) c = '/';
157
+ else if (c == slash) c = '\\';
158
+ else if (lower) c = (unsigned char) tolower((int) c);
159
+ } while ((*p++ = c));
160
+ }
161
+ return (char *) name;
162
+ }
163
+
164
+ static int sortfunc(const void *a, const void *b) {
165
+ off_t diff =
166
+ ((* ((struct mschmd_file **) a))->offset) -
167
+ ((* ((struct mschmd_file **) b))->offset);
168
+ return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
169
+ }
170
+
171
+ int main(int argc, char *argv[]) {
172
+ struct mschm_decompressor *chmd;
173
+ struct mschmd_header *chm;
174
+ struct mschmd_file *file, **f;
175
+ unsigned int numf, i;
176
+
177
+ setbuf(stdout, NULL);
178
+ setbuf(stderr, NULL);
179
+ user_umask = umask(0); umask(user_umask);
180
+
181
+ MSPACK_SYS_SELFTEST(i);
182
+ if (i) return 0;
183
+
184
+ if ((chmd = mspack_create_chm_decompressor(NULL))) {
185
+ for (argv++; *argv; argv++) {
186
+ printf("%s\n", *argv);
187
+ if ((chm = chmd->open(chmd, *argv))) {
188
+
189
+ /* build an ordered list of files for maximum extraction speed */
190
+ for (numf=0, file=chm->files; file; file = file->next) numf++;
191
+ if ((f = (struct mschmd_file **) calloc(numf, sizeof(struct mschmd_file *)))) {
192
+ for (i=0, file=chm->files; file; file = file->next) f[i++] = file;
193
+ qsort(f, numf, sizeof(struct mschmd_file *), &sortfunc);
194
+
195
+ for (i = 0; i < numf; i++) {
196
+ char *outname = create_output_name((unsigned char *)f[i]->filename,NULL,0,1,0);
197
+ printf("Extracting %s\n", outname);
198
+ ensure_filepath(outname);
199
+ if (chmd->extract(chmd, f[i], outname)) {
200
+ printf("%s: extract error on \"%s\": %s\n",
201
+ *argv, f[i]->filename, ERROR(chmd));
202
+ }
203
+ free(outname);
204
+ }
205
+ free(f);
206
+ }
207
+ chmd->close(chmd, chm);
208
+ }
209
+ else {
210
+ printf("%s: can't open -- %s\n", *argv, ERROR(chmd));
211
+ }
212
+ }
213
+ mspack_destroy_chm_decompressor(chmd);
214
+ }
215
+ return 0;
216
+ }
@@ -0,0 +1,22 @@
1
+ #define ERROR(base) error_msg(base->last_error(base))
2
+
3
+ const char *error_msg(int error) {
4
+ static char buf[32];
5
+ switch (error) {
6
+ case MSPACK_ERR_OK: return "no error";
7
+ case MSPACK_ERR_ARGS: return "bad arguments to library function";
8
+ case MSPACK_ERR_OPEN: return "error opening file";
9
+ case MSPACK_ERR_READ: return "read error";
10
+ case MSPACK_ERR_WRITE: return "write error";
11
+ case MSPACK_ERR_SEEK: return "seek error";
12
+ case MSPACK_ERR_NOMEMORY: return "out of memory";
13
+ case MSPACK_ERR_SIGNATURE: return "bad signature";
14
+ case MSPACK_ERR_DATAFORMAT: return "error in data format";
15
+ case MSPACK_ERR_CHECKSUM: return "checksum error";
16
+ case MSPACK_ERR_CRUNCH: return "compression error";
17
+ case MSPACK_ERR_DECRUNCH: return "decompression error";
18
+ }
19
+
20
+ snprintf(buf, sizeof(buf), "unknown error %d", error);
21
+ return buf;
22
+ }