libmspack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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