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,722 @@
1
+ module LibMsPack
2
+ module MsCab
3
+ module Constants
4
+ # Offset from start of cabinet to the reserved header data (if present).
5
+ MSCAB_HDR_RESV_OFFSET = 0x28
6
+ # Cabinet header flag: cabinet has a predecessor.
7
+ MSCAB_HDR_PREVCAB = 0x01
8
+ # Cabinet header flag: cabinet has a successor.
9
+ MSCAB_HDR_NEXTCAB = 0x02
10
+ # Cabinet header flag: cabinet has reserved header space.
11
+ MSCAB_HDR_RESV = 0x04
12
+
13
+ # Compression mode: no compression.
14
+ MSCAB_COMP_NONE = 0
15
+ # Compression mode: MSZIP (deflate) compression.
16
+ MSCAB_COMP_MSZIP = 1
17
+ # Compression mode: Quantum compression.
18
+ MSCAB_COMP_QUANTUM = 2
19
+ # Compression mode: LZX compression.
20
+ MSCAB_COMP_LZX = 3
21
+
22
+ # attribute: file is read-only.
23
+ MSCAB_ATTRIB_RDONLY = 0x01
24
+ # attribute: file is hidden.
25
+ MSCAB_ATTRIB_HIDDEN = 0x02
26
+ # attribute: file is an operating system file.
27
+ MSCAB_ATTRIB_SYSTEM = 0x04
28
+ # attribute: file is "archived".
29
+ MSCAB_ATTRIB_ARCH = 0x20
30
+ # attribute: file is an executable program.
31
+ MSCAB_ATTRIB_EXEC = 0x40
32
+ # attribute: filename is UTF8, not ISO-8859-1.
33
+ MSCAB_ATTRIB_UTF_NAME = 0x80
34
+
35
+ # CabDecompressor#setParam parameter: search buffer size.
36
+ MSCABD_PARAM_SEARCHBUF = 0
37
+ # CabDecompressor#setParam parameter: repair MS-ZIP streams?
38
+ MSCABD_PARAM_FIXMSZIP = 1
39
+ # CabDecompressor#setParam parameter: size of decompression buffer
40
+ MSCABD_PARAM_DECOMPBUF = 2
41
+ end
42
+
43
+ # Returns the compression method used by a folder.
44
+ # @param [Fixnum] compType a MsCabdFolder.comp_type value
45
+ # @return [Fixnum] one of MSCAB_COMP_NONE, MSCAB_COMP_MSZIP, MSCAB_COMP_QUANTUM or MSCAB_COMP_LZX
46
+ def MsCabdCompMethod(compType)
47
+ compType & 0x0F
48
+ end
49
+
50
+ # Returns the compression level used by a folder.
51
+ # @param [Fixnum] compType a MsCabdFolder.comp_type value
52
+ # @return [Fixnum] the compression level. This is only defined by LZX and Quantum compression
53
+ def MsCabdCompLevel(compType)
54
+ ((comp_type) >> 8) & 0x1F
55
+ end
56
+
57
+ # A structure which represents a single folder in a cabinet or cabinet set.
58
+ #
59
+ # A folder is a single compressed stream of data. When uncompressed, it holds the data of one or more files. A folder may be split across more than one cabinet.
60
+ class MsCabdFolder < FFI::Struct
61
+ layout({
62
+ :next => MsCabdFolder.ptr,
63
+ :comp_type => :int,
64
+ :num_blocks => :uint
65
+ })
66
+
67
+ # A next folder in this cabinet or cabinet set, or nil if this is the final folder.
68
+ #
69
+ # @return [MsCabdFolder, nil]
70
+ def next
71
+ return nil if self[:next].pointer.address.zero?
72
+ self[:next]
73
+ end
74
+
75
+ # The compression format used by this folder.
76
+ #
77
+ # `#MsCabdCompMethod` should be used on this field to get the algorithm used. `#MsCabdCompLevel` should be used to get the "compression level".
78
+ #
79
+ # @return [Fixnum]
80
+ def comp_type
81
+ self[:comp_type]
82
+ end
83
+
84
+ # The total number of data blocks used by this folder.
85
+ #
86
+ # This includes data blocks present in other files, if this folder spans more than one cabinet.
87
+ #
88
+ # @return [Fixnum]
89
+ def num_blocks
90
+ self[:num_blocks]
91
+ end
92
+
93
+ # Returns the compression method used by a folder.
94
+ #
95
+ # @return [Fixnum] one of MSCAB_COMP_NONE, MSCAB_COMP_MSZIP, MSCAB_COMP_QUANTUM or MSCAB_COMP_LZX
96
+ def compressionMethod
97
+ MsCabdCompMethod(comp_type)
98
+ end
99
+
100
+ # Returns the compression level used by a folder.
101
+ #
102
+ # @return [Fixnum] the compression level. This is only defined by LZX and Quantum compression
103
+ def compressionLevel
104
+ MsCabdCompLevel(comp_type)
105
+ end
106
+ end
107
+
108
+ # A structure which represents a single file in a cabinet or cabinet set.
109
+ class MsCabdFile < FFI::Struct
110
+ layout({
111
+ :next => MsCabdFile.ptr,
112
+ :filename => :string,
113
+ :length => :uint,
114
+ :attribs => :int,
115
+ :time_h => :char,
116
+ :time_m => :char,
117
+ :time_s => :char,
118
+ :date_d => :char,
119
+ :date_m => :char,
120
+ :date_y => :int,
121
+ :folder => MsCabdFolder.ptr,
122
+ :offset => :uint
123
+ })
124
+
125
+ # The next file in the cabinet or cabinet set, or nil if this is the final file.
126
+ #
127
+ # @return [MsCabdFile, nil]
128
+ def next
129
+ return nil if self[:next].pointer.address.zero?
130
+ self[:next]
131
+ end
132
+
133
+ # The filename of the file.
134
+ #
135
+ # String of up to 255 bytes in length, it may be in either ISO-8859-1 or UTF8 format, depending on the file attributes.
136
+ #
137
+ # @return [String]
138
+ def filename
139
+ self[:filename]
140
+ end
141
+
142
+ # The uncompressed length of the file, in bytes.
143
+ #
144
+ # @return [Fixnum]
145
+ def length
146
+ self[:length]
147
+ end
148
+
149
+ # File attributes.
150
+ #
151
+ # The following attributes are defined:
152
+ #
153
+ # * MSCAB_ATTRIB_RDONLY indicates the file is write protected.
154
+ # * MSCAB_ATTRIB_HIDDEN indicates the file is hidden.
155
+ # * MSCAB_ATTRIB_SYSTEM indicates the file is a operating system file.
156
+ # * MSCAB_ATTRIB_ARCH indicates the file is "archived".
157
+ # * MSCAB_ATTRIB_EXEC indicates the file is an executable program.
158
+ # * MSCAB_ATTRIB_UTF_NAME indicates the filename is in UTF8 format rather than ISO-8859-1.
159
+ #
160
+ # @return [Fixnum]
161
+ def attribs
162
+ self[:attribs]
163
+ end
164
+
165
+ # File's last modified datetime.
166
+ #
167
+ # @return [Time]
168
+ def datetime
169
+ Time.gm(self[:date_y], self[:date_m], self[:date_d], self[:time_h], self[:time_m], self[:time_s])
170
+ end
171
+
172
+ # Folder that contains this file.
173
+ #
174
+ # @return [MsCabdFolder, nil]
175
+ def folder
176
+ return nil if self[:folder].pointer.address.zero?
177
+ self[:folder]
178
+ end
179
+
180
+ # The uncompressed offset of this file in its folder.
181
+ #
182
+ # @return [Fixnum]
183
+ def offset
184
+ self[:offset]
185
+ end
186
+ end
187
+
188
+ # A structure which represents a single cabinet file.
189
+ #
190
+ # If this cabinet is part of a merged cabinet set, the files and folders fields are common to all cabinets in the set, and will be identical.
191
+ class MsCabdCabinet < FFI::Struct
192
+ layout({
193
+ :next => MsCabdCabinet.ptr,
194
+ :filename => :string,
195
+ :base_offset => :off_t,
196
+ :length => :uint,
197
+ :prevcab => MsCabdCabinet.ptr,
198
+ :nextcab => MsCabdCabinet.ptr,
199
+ :prevname => :string,
200
+ :nextname => :string,
201
+ :previnfo => :string,
202
+ :nextinfo => :string,
203
+ :files => MsCabdFile.ptr,
204
+ :folders => MsCabdFolder.ptr,
205
+ :set_id => :ushort,
206
+ :set_index => :ushort,
207
+ :header_resv => :ushort,
208
+ :flags => :int
209
+ })
210
+
211
+ # The next cabinet in a chained list, if this cabinet was opened with MsCabDecompressor#search
212
+ #
213
+ # May be nil to mark the end of the list.
214
+ #
215
+ # @return [MsCabdCabinet, nil]
216
+ def next
217
+ return nil if self[:next].pointer.address.zero?
218
+ self[:next]
219
+ end
220
+
221
+ # The filename of the cabinet.
222
+ #
223
+ # More correctly, the filename of the physical file that the cabinet resides in. This is given by the library user and may be in any format.
224
+ #
225
+ # @return [String]
226
+ def filename
227
+ self[:filename]
228
+ end
229
+
230
+ # The file offset of cabinet within the physical file it resides in.
231
+ #
232
+ # @return [Fixnum]
233
+ def base_offset
234
+ self[:base_offset]
235
+ end
236
+
237
+ # The length of the cabinet file in bytes.
238
+ #
239
+ # @return [Fixnum]
240
+ def length
241
+ self[:length]
242
+ end
243
+
244
+ # The previous cabinet in a cabinet set, or nil.
245
+ #
246
+ # @return [MsCabdCabinet, nil]
247
+ def prevcab
248
+ return nil if self[:prevcab].pointer.address.zero?
249
+ self[:prevcab]
250
+ end
251
+
252
+ # The next cabinet in a cabinet set, or nil.
253
+ #
254
+ # @return [MsCabdCabinet, nil]
255
+ def nextcab
256
+ return nil if self[:nextcab].pointer.address.zero?
257
+ self[:nextcab]
258
+ end
259
+
260
+ # The filename of the previous cabinet in a cabinet set, or nil.
261
+ #
262
+ # @return [String]
263
+ def prevname
264
+ self[:prevname]
265
+ end
266
+
267
+ # The filename of the next cabinet in a cabinet set, or nil.
268
+ #
269
+ # @return [String]
270
+ def nextname
271
+ self[:nextname]
272
+ end
273
+
274
+ # The name of the disk containing the previous cabinet in a cabinet set, or nil.
275
+ #
276
+ # @return [String]
277
+ def previnfo
278
+ self[:previnfo]
279
+ end
280
+
281
+ # The name of the disk containing the next cabinet in a cabinet set, or nil.
282
+ #
283
+ # @return [String]
284
+ def nextinfo
285
+ self[:nextinfo]
286
+ end
287
+
288
+ # A list of all files in the cabinet or cabinet set.
289
+ #
290
+ # @return [MsCabdFile, nil]
291
+ def files
292
+ return nil if self[:files].pointer.address.zero?
293
+ self[:files]
294
+ end
295
+
296
+ # A list of all folders in the cabinet or cabinet set.
297
+ #
298
+ # @return [MsCabdFolder, nil]
299
+ def folders
300
+ return nil if self[:folders].pointer.address.zero?
301
+ self[:folders]
302
+ end
303
+
304
+ # The set ID of the cabinet.
305
+ #
306
+ # All cabinets in the same set should have the same set ID.
307
+ #
308
+ # @return [Fixnum]
309
+ def set_id
310
+ self[:set_id]
311
+ end
312
+
313
+ # The index number of the cabinet within the set.
314
+ #
315
+ # Numbering should start from 0 for the first cabinet in the set, and increment by 1 for each following cabinet.
316
+ #
317
+ # @return [Fixnum]
318
+ def set_index
319
+ self[:set_index]
320
+ end
321
+
322
+ # The number of bytes reserved in the header area of the cabinet.
323
+ #
324
+ # If this is non-zero and flags has MSCAB_HDR_RESV set, this data can be read by the calling application. It is of the given length, located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the cabinet file.
325
+ #
326
+ # @see #flags flags
327
+ # @return [Fixnum]
328
+ def header_resv
329
+ self[:header_resv]
330
+ end
331
+
332
+ # Header flags.
333
+ #
334
+ # * MSCAB_HDR_PREVCAB indicates the cabinet is part of a cabinet set, and has a predecessor cabinet.
335
+ # * MSCAB_HDR_NEXTCAB indicates the cabinet is part of a cabinet set, and has a successor cabinet.
336
+ # * MSCAB_HDR_RESV indicates the cabinet has reserved header space.
337
+ #
338
+ # @see #prevname prevname
339
+ # @see #previnfo previnfo
340
+ # @see #nextname nextname
341
+ # @see #nextinfo nextinfo
342
+ # @see #header_resv header_resv
343
+ # @return [Fixnum]
344
+ def flags
345
+ self[:flags]
346
+ end
347
+ end
348
+
349
+ # CAB compressor
350
+ class MsCabCompressor < FFI::Struct
351
+ layout({:dummy => :int})
352
+ end
353
+
354
+ # CAB decompressor
355
+ class MsCabDecompressor < FFI::Struct
356
+ layout({
357
+ :open => callback([ MsCabDecompressor.ptr, :string ], MsCabdCabinet.ptr),
358
+ :close => callback([ MsCabDecompressor.ptr, MsCabdCabinet.ptr ], :void),
359
+ :search => callback([ MsCabDecompressor.ptr, :string ], MsCabdCabinet.ptr),
360
+ :append => callback([ MsCabDecompressor.ptr, MsCabdCabinet.ptr, MsCabdCabinet.ptr ], :int),
361
+ :prepend => callback([ MsCabDecompressor.ptr, MsCabdCabinet.ptr, MsCabdCabinet.ptr ], :int),
362
+ :extract => callback([ MsCabDecompressor.ptr, MsCabdFile.ptr, :string ], :int),
363
+ :set_param => callback([ MsCabDecompressor.ptr, :int, :int ], :int),
364
+ :last_error => callback([ MsCabDecompressor.ptr ], :int)
365
+ })
366
+
367
+ # Opens a cabinet file and reads its contents.
368
+ #
369
+ # If the file opened is a valid cabinet file, all headers will be read and a MsCabdCabinet structure will be returned, with a full list of folders and files.
370
+ #
371
+ # In the case of an error occuring, nil is returned and the error code is available from #last_error
372
+ #
373
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
374
+ # @param [String] filename name of the cabinet file
375
+ # @return [MsCabdCabinet, nil]
376
+ # @see #close close
377
+ # @see #search search
378
+ # @see #last_error last_error
379
+ def open(decompressor, filename)
380
+ self[:open].call(decompressor, filename)
381
+ end
382
+
383
+ # Closes a previously opened cabinet or cabinet set.
384
+ #
385
+ # This closes a cabinet, all cabinets associated with it via the MsCabdCabinet#next, MsCabdCabinet#prevcab and MsCabdCabinet#nextcab, and all folders and files. All memory used by these entities is freed.
386
+ #
387
+ # The cabinet is now invalid and cannot be used again. All MsCabdFolder and MsCabdFile from that cabinet or cabinet set are also now invalid, and cannot be used again.
388
+ #
389
+ # If the cabinet given was created using #search, it MUST be the cabinet returned by #search and not one of the later cabinet pointers further along the MsCabdCabinet::next chain.
390
+ #
391
+ # If extra cabinets have been added using #append or #prepend, these will all be freed, even if the cabinet given is not the first cabinet in the set. Do NOT #close more than one cabinet in the set.
392
+ #
393
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
394
+ # @param [MsCabdCabinet] cabinet the cabinet to close
395
+ # @see #open open
396
+ # @see #search search
397
+ # @see #append append
398
+ # @see #prepend prepend
399
+ def close(decompressor, cabinet)
400
+ self[:close].call(decompressor, cabinet)
401
+ end
402
+
403
+ # Searches a regular file for embedded cabinets.
404
+ #
405
+ # This opens a normal file with the given filename and will search the entire file for embedded cabinet files
406
+ #
407
+ # If any cabinets are found, the equivalent of #open is called on each potential cabinet file at the offset it was found. All successfully #open'ed cabinets are kept in a list.
408
+ #
409
+ # The first cabinet found will be returned directly as the result of this method. Any further cabinets found will be chained in a list using the MsCabdCabinet#next field.
410
+ #
411
+ # In the case of an error occuring anywhere other than the simulated #open, nil is returned and the error code is available from #last_error
412
+ #
413
+ # If no error occurs, but no cabinets can be found in the file, nil is returned and #last_error returns MSPACK_ERR_OK
414
+ #
415
+ # `#close` should only be called on the result of #search, not on any subsequent cabinets in the MsCabdCabinet#next chain.
416
+ #
417
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
418
+ # @param [String] filename the filename of the file to search for cabinets
419
+ # @return [MsCabdCabinet, nil]
420
+ # @see #close close
421
+ # @see #open open
422
+ # @see #last_error last_error
423
+ def search(decompressor, filename)
424
+ self[:search].call(decompressor, filename)
425
+ end
426
+
427
+ # Appends one MsCabdCabinet to another, forming or extending a cabinet set.
428
+ #
429
+ # This will attempt to append one cabinet to another such that (cab.nextcab == nextcab) && (nextcab.prevcab == cab) and any folders split between the two cabinets are merged.
430
+ #
431
+ # The cabinets MUST be part of a cabinet set -- a cabinet set is a cabinet that spans more than one physical cabinet file on disk -- and must be appropriately matched.
432
+ #
433
+ # It can be determined if a cabinet has further parts to load by examining the MsCabdCabinet.flags field:
434
+ #
435
+ # * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to #open and #prepend. Its MS-DOS case-insensitive filename is MsCabdCabinet.prevname
436
+ # * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to #open and #append. Its MS-DOS case-insensitive filename is MsCabdCabinet.nextname
437
+ #
438
+ # If the cabinets do not match, an error code will be returned. Neither cabinet has been altered, and both should be closed seperately.
439
+ #
440
+ # Files and folders in a cabinet set are a single entity. All cabinets in a set use the same file list, which is updated as cabinets in the set are added.
441
+ #
442
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
443
+ # @param [MsCabdCabinet] cab the cabinet which will be appended to, predecessor of nextcab
444
+ # @param [MsCabdCabinet] nextcab the cabinet which will be appended, successor of cab
445
+ # @return [Fixnum] an error code, or MSPACK_ERR_OK if successful
446
+ # @see #prepend prepend
447
+ # @see #open open
448
+ # @see #close close
449
+ def append(decompressor, cab, nextcab)
450
+ self[:append].call(decompressor, cab, nextcab)
451
+ end
452
+
453
+ # Prepends one MsCabdCabinet to another, forming or extending a cabinet set.
454
+ #
455
+ # This will attempt to prepend one cabinet to another, such that (cab.prevcab == prevcab) && (prevcab.nextcab == cab).
456
+ # In all other respects, it is identical to #append.
457
+ #
458
+ # @see #append #append for the full documentation
459
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
460
+ # @param [MsCabdCabinet] cab the cabinet which will be prepended to, successor of prevcab
461
+ # @param [MsCabdCabinet] prevcab the cabinet which will be prepended, predecessor of cab
462
+ # @see #append append
463
+ # @see #open open
464
+ # @see #close close
465
+ def prepend(decompressor, cab, prevcab)
466
+ self[:prepend].call(decompressor, cab, prevcab)
467
+ end
468
+
469
+ # Extracts a file from a cabinet or cabinet set.
470
+ #
471
+ # This extracts a compressed file in a cabinet and writes it to the given filename.
472
+ #
473
+ # The MS-DOS filename of the file, MsCabdCabinet.filename, is NOT USED by #extract. The caller must examine this MS-DOS filename, copy and change it as necessary, create directories as necessary, and provide the correct filename as a parameter, which will be passed unchanged to the decompressor's MsPackSystem#open
474
+ #
475
+ # If the file belongs to a split folder in a multi-part cabinet set, and not enough parts of the cabinet set have been loaded and appended or prepended, an error will be returned immediately.
476
+ #
477
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
478
+ # @param [MsCabdFile] cabfile the file to be decompressed
479
+ # @param [String] filename the filename of the file being written to
480
+ # @return [Fixnum] an error code, or MSPACK_ERR_OK if successful
481
+ def extract(decompressor, cabfile, filename)
482
+ self[:extract].call(decompressor, cabfile, filename)
483
+ end
484
+
485
+ # Sets a CAB decompression engine parameter.
486
+ #
487
+ # The following parameters are defined:
488
+ #
489
+ # * MSCABD_PARAM_SEARCHBUF: How many bytes should be allocated as a buffer when using #search ? The minimum value is 4. The default value is 32768.
490
+ # * MSCABD_PARAM_FIXMSZIP: If non-zero, #extract will ignore bad checksums and recover from decompression errors in MS-ZIP compressed folders. The default value is 0 (don't recover).
491
+ # * MSCABD_PARAM_DECOMPBUF: How many bytes should be used as an input bit buffer by decompressors? The minimum value is 4. The default value is 4096.
492
+ #
493
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
494
+ # @param [Fixnum] param the parameter to set
495
+ # @param [Fixnum] value the value to set the parameter to
496
+ # @see #close close
497
+ # @see #open open
498
+ def set_param(decompressor, param, value)
499
+ self[:set_param].call(decompressor, param, value)
500
+ end
501
+
502
+ # Returns the error code set by the most recently called method
503
+ # @param [MsCabDecompressor] decompressor MsCabDecompressor instance being called
504
+ # @return [Fixnum] the most recent error code
505
+ # @see #open open
506
+ # @see #search search
507
+ def last_error(decompressor)
508
+ self[:last_error].call(decompressor)
509
+ end
510
+
511
+ end
512
+
513
+ # CAB Compressor
514
+ class CabCompressor
515
+ attr_reader :Compressor
516
+ # Creates a new CAB compressor.
517
+ #
518
+ # @param [MsPack::MsPackSystem, nil] system is a custom mspack system, or nil to use the default
519
+ def initialize(system = nil)
520
+ @Compressor = nil
521
+ init(system)
522
+ end
523
+
524
+ # @private
525
+ def init(system = MsPack::RubyPackSystem)
526
+ raise Exceptions::AlreadyInitializedError if @Compressor
527
+ @Compressor = LibMsPack.CreateCabCompressor(system)
528
+ end
529
+
530
+ # Destroys an existing CAB compressor
531
+ def destroy
532
+ raise Exceptions::NotInitializedError unless @Compressor
533
+ LibMsPack.DestroyCabCompressor(@Compressor)
534
+ @Compressor = nil
535
+ end
536
+ end
537
+
538
+ # CAB decompressor
539
+ class CabDecompressor
540
+ attr_reader :Decompressor
541
+ # Creates a new CAB decompressor.
542
+ #
543
+ # @param [MsPack::MsPackSystem, nil] system a custom mspack system, or nil to use the default
544
+ def initialize(system = nil)
545
+ @Decompressor = nil
546
+ init(system)
547
+ end
548
+
549
+ # @private
550
+ def init(system = MsPack::RubyPackSystem)
551
+ raise Exceptions::AlreadyInitializedError if @Decompressor
552
+ @Decompressor = LibMsPack.CreateCabDecompressor(system)
553
+ end
554
+
555
+ # Opens a cabinet file and reads its contents.
556
+ #
557
+ # If the file opened is a valid cabinet file, all headers will be read and a MsCabdCabinet structure will be returned, with a full list of folders and files.
558
+ #
559
+ # In the case of an error occuring, exception will be raised.
560
+ #
561
+ # @param [String] filename name of the cabinet file
562
+ # @return [MsCabdCabinet]
563
+ # @raise [Exceptions::LibMsPackError]
564
+ # @see #close close
565
+ # @see #search search
566
+ def open(filename)
567
+ raise Exceptions::NotInitializedError unless @Decompressor
568
+ cabinet = @Decompressor.open(@Decompressor, filename)
569
+ error = lastError
570
+ raise Exceptions::LibMsPackError.new(error) unless error == LibMsPack::MSPACK_ERR_OK
571
+ cabinet
572
+ end
573
+
574
+ # Closes a previously opened cabinet or cabinet set.
575
+ #
576
+ # This closes a cabinet, all cabinets associated with it via the MsCabdCabinet#next, MsCabdCabinet#prevcab and MsCabdCabinet#nextcab, and all folders and files. All memory used by these entities is freed.
577
+ #
578
+ # The cabinet is now invalid and cannot be used again. All MsCabdFolder and MsCabdFile from that cabinet or cabinet set are also now invalid, and cannot be used again.
579
+ #
580
+ # If the cabinet given was created using #search, it MUST be the cabinet returned by #search and not one of the later cabinet pointers further along the MsCabdCabinet::next chain.
581
+ #
582
+ # If extra cabinets have been added using #append or #prepend, these will all be freed, even if the cabinet given is not the first cabinet in the set. Do NOT #close more than one cabinet in the set.
583
+ #
584
+ # @param [MsCabdCabinet] cabinet the cabinet to close
585
+ # @see #open open
586
+ # @see #search search
587
+ # @see #append append
588
+ # @see #prepend prepend
589
+ def close(cabinet)
590
+ raise Exceptions::NotInitializedError unless @Decompressor
591
+ @Decompressor.close(@Decompressor, cabinet)
592
+ end
593
+
594
+ # Searches a regular file for embedded cabinets.
595
+ #
596
+ # This opens a normal file with the given filename and will search the entire file for embedded cabinet files
597
+ #
598
+ # If any cabinets are found, the equivalent of #open is called on each potential cabinet file at the offset it was found. All successfully #open'ed cabinets are kept in a list.
599
+ #
600
+ # The first cabinet found will be returned directly as the result of this method. Any further cabinets found will be chained in a list using the MsCabdCabinet#next field.
601
+ #
602
+ # In the case of an error occuring anywhere other than the simulated #open, exception will be raised.
603
+ #
604
+ # If no error occurs, but no cabinets can be found in the file, nil is returned.
605
+ #
606
+ # `#close` should only be called on the result of #search, not on any subsequent cabinets in the MsCabdCabinet#next chain.
607
+ #
608
+ # @param [String] filename the filename of the file to search for cabinets
609
+ # @return [MsCabdCabinet]
610
+ # @raise [Exceptions::LibMsPackError]
611
+ # @see #close close
612
+ # @see #open open
613
+ def search(filename)
614
+ raise Exceptions::NotInitializedError unless @Decompressor
615
+ cabinet = @Decompressor.search(@Decompressor, filename)
616
+ error = lastError
617
+ raise Exceptions::LibMsPackError.new(error) unless error == LibMsPack::MSPACK_ERR_OK
618
+ cabinet
619
+ end
620
+
621
+ # Appends one MsCabdCabinet to another, forming or extending a cabinet set.
622
+ #
623
+ # This will attempt to append one cabinet to another such that (cab.nextcab == nextcab) && (nextcab.prevcab == cab) and any folders split between the two cabinets are merged.
624
+ #
625
+ # The cabinets MUST be part of a cabinet set -- a cabinet set is a cabinet that spans more than one physical cabinet file on disk -- and must be appropriately matched.
626
+ #
627
+ # It can be determined if a cabinet has further parts to load by examining the MsCabdCabinet.flags field:
628
+ #
629
+ # * if (flags & MSCAB_HDR_PREVCAB) is non-zero, there is a predecessor cabinet to #open and #prepend. Its MS-DOS case-insensitive filename is MsCabdCabinet.prevname
630
+ # * if (flags & MSCAB_HDR_NEXTCAB) is non-zero, there is a successor cabinet to #open and #append. Its MS-DOS case-insensitive filename is MsCabdCabinet.nextname
631
+ #
632
+ # If the cabinets do not match, an exception will be raised. Neither cabinet has been altered, and both should be closed seperately.
633
+ #
634
+ # Files and folders in a cabinet set are a single entity. All cabinets in a set use the same file list, which is updated as cabinets in the set are added.
635
+ #
636
+ # @param [MsCabdCabinet] cab the cabinet which will be appended to, predecessor of nextcab
637
+ # @param [MsCabdCabinet] nextcab the cabinet which will be appended, successor of cab
638
+ # @raise [Exceptions::LibMsPackError]
639
+ # @see #prepend prepend
640
+ # @see #open open
641
+ # @see #close close
642
+ def append(cab, nextcab)
643
+ raise Exceptions::NotInitializedError unless @Decompressor
644
+ error = @Decompressor.append(@Decompressor, cab, nextcab)
645
+ raise Exceptions::LibMsPackError.new(error) unless error == LibMsPack::MSPACK_ERR_OK
646
+ error
647
+ end
648
+
649
+ # Prepends one MsCabdCabinet to another, forming or extending a cabinet set.
650
+ #
651
+ # This will attempt to prepend one cabinet to another, such that (cab.prevcab == prevcab) && (prevcab.nextcab == cab).
652
+ # In all other respects, it is identical to #append.
653
+ #
654
+ # @see #append #append for the full documentation
655
+ # @param [MsCabdCabinet] cab the cabinet which will be prepended to, successor of prevcab
656
+ # @param [MsCabdCabinet] prevcab the cabinet which will be prepended, predecessor of cab
657
+ # @raise [Exceptions::LibMsPackError]
658
+ # @see #append append
659
+ # @see #open open
660
+ # @see #close close
661
+ def prepend(cab, prevcab)
662
+ raise Exceptions::NotInitializedError unless @Decompressor
663
+ error = @Decompressor.prepend(@Decompressor, cab, prevcab)
664
+ raise Exceptions::LibMsPackError.new(error) unless error == LibMsPack::MSPACK_ERR_OK
665
+ error
666
+ end
667
+
668
+ # Extracts a file from a cabinet or cabinet set.
669
+ #
670
+ # This extracts a compressed file in a cabinet and writes it to the given filename.
671
+ #
672
+ # The MS-DOS filename of the file, MsCabdCabinet.filename, is NOT USED by #extract. The caller must examine this MS-DOS filename, copy and change it as necessary, create directories as necessary, and provide the correct filename as a parameter, which will be passed unchanged to the decompressor's MsPackSystem#open
673
+ #
674
+ # If the file belongs to a split folder in a multi-part cabinet set, and not enough parts of the cabinet set have been loaded and appended or prepended, an exception will be raised immediately.
675
+ #
676
+ # @param [MsCabdFile] cabfile the file to be decompressed
677
+ # @param [String] filename the filename of the file being written to
678
+ # @raise [Exceptions::LibMsPackError]
679
+ def extract(cabfile, filename)
680
+ raise Exceptions::NotInitializedError unless @Decompressor
681
+ error = @Decompressor.extract(@Decompressor, cabfile, filename)
682
+ raise Exceptions::LibMsPackError.new(error) unless error == LibMsPack::MSPACK_ERR_OK
683
+ error
684
+ end
685
+
686
+ # Sets a CAB decompression engine parameter.
687
+ #
688
+ # The following parameters are defined:
689
+ #
690
+ # * MSCABD_PARAM_SEARCHBUF: How many bytes should be allocated as a buffer when using #search ? The minimum value is 4. The default value is 32768.
691
+ # * MSCABD_PARAM_FIXMSZIP: If non-zero, #extract will ignore bad checksums and recover from decompression errors in MS-ZIP compressed folders. The default value is 0 (don't recover).
692
+ # * MSCABD_PARAM_DECOMPBUF: How many bytes should be used as an input bit buffer by decompressors? The minimum value is 4. The default value is 4096.
693
+ #
694
+ # @param [Fixnum] param the parameter to set
695
+ # @param [Fixnum] value the value to set the parameter to
696
+ # @raise [Exceptions::LibMsPackError]
697
+ # @see #close close
698
+ # @see #open open
699
+ def setParam(param, value)
700
+ raise Exceptions::NotInitializedError unless @Decompressor
701
+ error = @Decompressor.set_param(@Decompressor, param, value)
702
+ raise Exceptions::LibMsPackError.new(error) unless error == LibMsPack::MSPACK_ERR_OK
703
+ error
704
+ end
705
+
706
+ # Returns the error code set by the most recently called method
707
+ # @return [Fixnum] the most recent error code
708
+ def lastError
709
+ raise Exceptions::NotInitializedError unless @Decompressor
710
+ @Decompressor.last_error(@Decompressor)
711
+ end
712
+
713
+ # Destroys an existing CAB decompressor
714
+ def destroy
715
+ raise Exceptions::NotInitializedError unless @Decompressor
716
+ LibMsPack.DestroyCabDecompressor(@Decompressor)
717
+ @Decompressor = nil
718
+ end
719
+ end
720
+
721
+ end
722
+ end