cabriolet 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/README.adoc +703 -38
- data/lib/cabriolet/algorithm_factory.rb +250 -0
- data/lib/cabriolet/base_compressor.rb +206 -0
- data/lib/cabriolet/binary/bitstream.rb +167 -16
- data/lib/cabriolet/binary/bitstream_writer.rb +150 -21
- data/lib/cabriolet/binary/chm_structures.rb +2 -2
- data/lib/cabriolet/binary/hlp_structures.rb +258 -37
- data/lib/cabriolet/binary/lit_structures.rb +231 -65
- data/lib/cabriolet/binary/oab_structures.rb +17 -1
- data/lib/cabriolet/cab/command_handler.rb +226 -0
- data/lib/cabriolet/cab/compressor.rb +108 -84
- data/lib/cabriolet/cab/decompressor.rb +16 -20
- data/lib/cabriolet/cab/extractor.rb +142 -66
- data/lib/cabriolet/cab/file_compression_work.rb +52 -0
- data/lib/cabriolet/cab/file_compression_worker.rb +89 -0
- data/lib/cabriolet/checksum.rb +49 -0
- data/lib/cabriolet/chm/command_handler.rb +227 -0
- data/lib/cabriolet/chm/compressor.rb +7 -3
- data/lib/cabriolet/chm/decompressor.rb +39 -21
- data/lib/cabriolet/chm/parser.rb +5 -2
- data/lib/cabriolet/cli/base_command_handler.rb +127 -0
- data/lib/cabriolet/cli/command_dispatcher.rb +140 -0
- data/lib/cabriolet/cli/command_registry.rb +83 -0
- data/lib/cabriolet/cli.rb +356 -607
- data/lib/cabriolet/collections/file_collection.rb +175 -0
- data/lib/cabriolet/compressors/base.rb +1 -1
- data/lib/cabriolet/compressors/lzx.rb +241 -54
- data/lib/cabriolet/compressors/mszip.rb +35 -3
- data/lib/cabriolet/compressors/quantum.rb +36 -95
- data/lib/cabriolet/decompressors/base.rb +1 -1
- data/lib/cabriolet/decompressors/lzss.rb +13 -3
- data/lib/cabriolet/decompressors/lzx.rb +70 -33
- data/lib/cabriolet/decompressors/mszip.rb +126 -39
- data/lib/cabriolet/decompressors/quantum.rb +83 -53
- data/lib/cabriolet/errors.rb +3 -0
- data/lib/cabriolet/extraction/base_extractor.rb +88 -0
- data/lib/cabriolet/extraction/extractor.rb +171 -0
- data/lib/cabriolet/extraction/file_extraction_work.rb +60 -0
- data/lib/cabriolet/extraction/file_extraction_worker.rb +106 -0
- data/lib/cabriolet/file_entry.rb +156 -0
- data/lib/cabriolet/file_manager.rb +144 -0
- data/lib/cabriolet/format_base.rb +79 -0
- data/lib/cabriolet/hlp/command_handler.rb +282 -0
- data/lib/cabriolet/hlp/compressor.rb +28 -238
- data/lib/cabriolet/hlp/decompressor.rb +107 -147
- data/lib/cabriolet/hlp/parser.rb +52 -101
- data/lib/cabriolet/hlp/quickhelp/compression_stream.rb +138 -0
- data/lib/cabriolet/hlp/quickhelp/compressor.rb +151 -0
- data/lib/cabriolet/hlp/quickhelp/decompressor.rb +558 -0
- data/lib/cabriolet/hlp/quickhelp/file_writer.rb +125 -0
- data/lib/cabriolet/hlp/quickhelp/huffman_stream.rb +74 -0
- data/lib/cabriolet/hlp/quickhelp/huffman_tree.rb +167 -0
- data/lib/cabriolet/hlp/quickhelp/offset_calculator.rb +61 -0
- data/lib/cabriolet/hlp/quickhelp/parser.rb +274 -0
- data/lib/cabriolet/hlp/quickhelp/structure_builder.rb +93 -0
- data/lib/cabriolet/hlp/quickhelp/topic_builder.rb +52 -0
- data/lib/cabriolet/hlp/quickhelp/topic_compressor.rb +83 -0
- data/lib/cabriolet/hlp/winhelp/btree_builder.rb +289 -0
- data/lib/cabriolet/hlp/winhelp/compressor.rb +400 -0
- data/lib/cabriolet/hlp/winhelp/decompressor.rb +192 -0
- data/lib/cabriolet/hlp/winhelp/parser.rb +484 -0
- data/lib/cabriolet/hlp/winhelp/zeck_lz77.rb +271 -0
- data/lib/cabriolet/huffman/encoder.rb +15 -12
- data/lib/cabriolet/huffman/tree.rb +85 -1
- data/lib/cabriolet/kwaj/command_handler.rb +213 -0
- data/lib/cabriolet/kwaj/compressor.rb +7 -3
- data/lib/cabriolet/kwaj/decompressor.rb +18 -12
- data/lib/cabriolet/lit/command_handler.rb +221 -0
- data/lib/cabriolet/lit/compressor.rb +119 -168
- data/lib/cabriolet/lit/content_encoder.rb +76 -0
- data/lib/cabriolet/lit/content_type_detector.rb +50 -0
- data/lib/cabriolet/lit/decompressor.rb +518 -152
- data/lib/cabriolet/lit/directory_builder.rb +153 -0
- data/lib/cabriolet/lit/guid_generator.rb +16 -0
- data/lib/cabriolet/lit/header_writer.rb +124 -0
- data/lib/cabriolet/lit/parser.rb +670 -0
- data/lib/cabriolet/lit/piece_builder.rb +74 -0
- data/lib/cabriolet/lit/structure_builder.rb +252 -0
- data/lib/cabriolet/models/hlp_file.rb +130 -29
- data/lib/cabriolet/models/hlp_header.rb +105 -17
- data/lib/cabriolet/models/lit_header.rb +212 -25
- data/lib/cabriolet/models/szdd_header.rb +10 -2
- data/lib/cabriolet/models/winhelp_header.rb +127 -0
- data/lib/cabriolet/oab/command_handler.rb +257 -0
- data/lib/cabriolet/oab/compressor.rb +17 -8
- data/lib/cabriolet/oab/decompressor.rb +41 -10
- data/lib/cabriolet/offset_calculator.rb +81 -0
- data/lib/cabriolet/plugin.rb +233 -0
- data/lib/cabriolet/plugin_manager.rb +453 -0
- data/lib/cabriolet/plugin_validator.rb +422 -0
- data/lib/cabriolet/quantum_shared.rb +105 -0
- data/lib/cabriolet/system/io_system.rb +3 -0
- data/lib/cabriolet/system/memory_handle.rb +17 -4
- data/lib/cabriolet/szdd/command_handler.rb +217 -0
- data/lib/cabriolet/szdd/compressor.rb +15 -11
- data/lib/cabriolet/szdd/decompressor.rb +18 -9
- data/lib/cabriolet/version.rb +1 -1
- data/lib/cabriolet.rb +181 -20
- metadata +69 -4
- data/lib/cabriolet/auto.rb +0 -173
- data/lib/cabriolet/parallel.rb +0 -333
data/README.adoc
CHANGED
|
@@ -1,24 +1,98 @@
|
|
|
1
|
-
= Cabriolet
|
|
2
|
-
:toc: left
|
|
3
|
-
:toclevels: 3
|
|
1
|
+
= Cabriolet: Working with Microsoft Compression Formats in Pure Ruby
|
|
4
2
|
|
|
5
3
|
image:https://img.shields.io/gem/v/cabriolet.svg[RubyGems Version, link=https://rubygems.org/gems/cabriolet]
|
|
6
4
|
image:https://img.shields.io/github/license/omnizip/cabriolet.svg[License]
|
|
7
5
|
|
|
6
|
+
image:https://img.shields.io/badge/Website-Cabriolet_documentation-blue.svg["Documentation site", link="https://omnizip.github.io/cabriolet"]
|
|
7
|
+
|
|
8
|
+
|
|
8
9
|
Pure Ruby implementation for extracting and creating Microsoft compression
|
|
9
10
|
format files.
|
|
10
11
|
|
|
11
12
|
== Introduction
|
|
12
13
|
|
|
13
|
-
Cabriolet extracts and creates Microsoft
|
|
14
|
+
Cabriolet extracts and creates Microsoft compression files and related
|
|
14
15
|
compression formats using pure Ruby.
|
|
15
16
|
|
|
16
|
-
This gem
|
|
17
|
-
Microsoft compression formats for both extraction (decompression) and
|
|
18
|
-
(compression).
|
|
17
|
+
This gem aims to cover the features of libmspack and cabextract, implementing
|
|
18
|
+
all Microsoft compression formats for both extraction (decompression) and
|
|
19
|
+
creation (compression).
|
|
19
20
|
|
|
20
21
|
NOTE: No C extensions required, works on any platform where Ruby runs.
|
|
21
22
|
|
|
23
|
+
== Supported formats
|
|
24
|
+
|
|
25
|
+
Cabriolet provides complete bidirectional support (compression and
|
|
26
|
+
decompression) for seven Microsoft compression formats:
|
|
27
|
+
|
|
28
|
+
CAB (Microsoft Cabinet)::
|
|
29
|
+
Microsoft Cabinet files (.CAB) are archive files used extensively in Windows
|
|
30
|
+
software distribution, updates, and installations. They support multiple
|
|
31
|
+
compression algorithms (None, LZSS, MSZIP, LZX, Quantum), multi-part spanning,
|
|
32
|
+
and can store multiple files with full metadata preservation including
|
|
33
|
+
timestamps and attributes. Cabriolet provides complete CAB support including
|
|
34
|
+
multi-part cabinet sets, embedded cabinet search, and salvage mode for corrupted
|
|
35
|
+
files.
|
|
36
|
+
|
|
37
|
+
CHM (Compiled HTML Help)::
|
|
38
|
+
Compiled HTML Help files (.CHM) are Microsoft's compressed help file format used
|
|
39
|
+
in Windows applications since Windows 98. CHM files use an internal file system
|
|
40
|
+
to store HTML pages, images, stylesheets, and a full-text search index, all
|
|
41
|
+
compressed with LZX. Cabriolet can extract CHM contents to recreate the original
|
|
42
|
+
HTML documentation, and create new CHM files from HTML sources with proper
|
|
43
|
+
compression and indexing.
|
|
44
|
+
|
|
45
|
+
SZDD (Single-File LZSS)::
|
|
46
|
+
SZDD is Microsoft's single-file compression format used primarily in Windows
|
|
47
|
+
installation media and DOS utilities. Files compressed with SZDD typically have
|
|
48
|
+
the last character of their extension replaced with an underscore (e.g., .TX_
|
|
49
|
+
for .TXT). SZDD uses LZSS MODE_EXPAND compression with a 4KB sliding window.
|
|
50
|
+
Cabriolet supports both normal SZDD format and the QBasic variant, with
|
|
51
|
+
automatic filename reconstruction during extraction.
|
|
52
|
+
|
|
53
|
+
KWAJ (Installation File)::
|
|
54
|
+
KWAJ format (.KWJ) is used in Microsoft installation packages to compress
|
|
55
|
+
individual files. It supports multiple compression methods including
|
|
56
|
+
uncompressed storage, XOR encryption (0xFF), SZDD (LZSS), and MSZIP. KWAJ files
|
|
57
|
+
can embed the original filename and uncompressed size in the header. Cabriolet
|
|
58
|
+
provides full KWAJ support for all compression methods and can preserve or
|
|
59
|
+
reconstruct original filenames.
|
|
60
|
+
|
|
61
|
+
DOS Help (QuickHelp)::
|
|
62
|
+
QuickHelp (.HLP) is the DOS-based help file format used in Microsoft development
|
|
63
|
+
tools like QuickC, QuickBASIC, and early Visual C++. Identified by the signature
|
|
64
|
+
0x4C 0x4E ("LN"), QuickHelp files contain help topics compressed with optional
|
|
65
|
+
Huffman coding and LZSS MODE_MSHELP compression. Topics are organized with
|
|
66
|
+
context strings for navigation. Cabriolet fully supports creating and extracting
|
|
67
|
+
QuickHelp files with all compression options.
|
|
68
|
+
|
|
69
|
+
Windows Help (WinHelp)::
|
|
70
|
+
Windows Help (.HLP) is the help file format used in Windows 3.x through Windows
|
|
71
|
+
XP, distinct from DOS Help/QuickHelp. WinHelp files are identified by magic
|
|
72
|
+
numbers 0x35F3 (version 3.x) or 0x3F5F (version 4.x) and use an internal file
|
|
73
|
+
system containing |SYSTEM (metadata), |TOPIC (compressed help text), and
|
|
74
|
+
optionally B-tree indexes. Topics are compressed with Zeck LZ77, a custom LZ77
|
|
75
|
+
variant with 4KB sliding window and variable-length matches (3-271 bytes).
|
|
76
|
+
Cabriolet provides complete support for both WinHelp 3.x and 4.x formats with
|
|
77
|
+
bidirectional Zeck LZ77 compression.
|
|
78
|
+
|
|
79
|
+
LIT (Microsoft Reader eBooks)::
|
|
80
|
+
LIT is Microsoft's proprietary eBook format for the Microsoft Reader
|
|
81
|
+
application. LIT files use a complex internal structure with directory systems
|
|
82
|
+
(IFCM/AOLL), manifest with content type mappings, and NameList with UTF-16LE
|
|
83
|
+
encoding. Content is typically compressed with LZX. Cabriolet supports reading
|
|
84
|
+
and creating non-encrypted LIT files; DRM-protected (DES-encrypted) LIT files
|
|
85
|
+
are intentionally not supported as DRM circumvention is not a goal of this
|
|
86
|
+
project.
|
|
87
|
+
|
|
88
|
+
OAB (Offline Address Book)::
|
|
89
|
+
Offline Address Book files (.OAB) are used by Microsoft Outlook and Exchange
|
|
90
|
+
Server to provide offline access to address book data. OAB files are compressed
|
|
91
|
+
with LZX and support incremental updates through patch files that contain only
|
|
92
|
+
changes from a base version. Cabriolet can extract full OAB files, apply
|
|
93
|
+
incremental patches, create new OAB files, and generate incremental patches
|
|
94
|
+
between versions.
|
|
95
|
+
|
|
22
96
|
|
|
23
97
|
=== Features
|
|
24
98
|
|
|
@@ -49,7 +123,7 @@ NOTE: No C extensions required, works on any platform where Ruby runs.
|
|
|
49
123
|
** Metadata preservation (timestamps, attributes)
|
|
50
124
|
|
|
51
125
|
* **Pure Ruby** - No compilation needed, works everywhere
|
|
52
|
-
* **Comprehensive testing** -
|
|
126
|
+
* **Comprehensive testing** - 1,225 test examples, 0 failures
|
|
53
127
|
* **Complete CLI** - 30+ commands for all operations
|
|
54
128
|
|
|
55
129
|
=== Architecture
|
|
@@ -70,6 +144,190 @@ Application Layer (CLI/API)
|
|
|
70
144
|
|
|
71
145
|
For complete architecture, see link:ARCHITECTURE.md[Architecture Documentation].
|
|
72
146
|
|
|
147
|
+
== Comparison with libmspack
|
|
148
|
+
|
|
149
|
+
Cabriolet is a pure Ruby alternative to https://www.cabextract.org.uk/libmspack/[libmspack], the reference C implementation for Microsoft compression formats. This comparison helps you choose the right tool for your needs.
|
|
150
|
+
|
|
151
|
+
=== Feature Comparison
|
|
152
|
+
|
|
153
|
+
[cols="2,1,1,2"]
|
|
154
|
+
|===
|
|
155
|
+
|Feature |Cabriolet |libmspack |Notes
|
|
156
|
+
|
|
157
|
+
4+h|**Formats**
|
|
158
|
+
|
|
159
|
+
|CAB (Microsoft Cabinet)
|
|
160
|
+
|✅
|
|
161
|
+
|✅
|
|
162
|
+
|Both support all compression types
|
|
163
|
+
|
|
164
|
+
|CHM (Compiled HTML Help)
|
|
165
|
+
|✅
|
|
166
|
+
|✅
|
|
167
|
+
|Full bidirectional support
|
|
168
|
+
|
|
169
|
+
|SZDD (Single-file LZSS)
|
|
170
|
+
|✅
|
|
171
|
+
|✅
|
|
172
|
+
|Including QBasic variant
|
|
173
|
+
|
|
174
|
+
|KWAJ (Installation files)
|
|
175
|
+
|✅
|
|
176
|
+
|✅
|
|
177
|
+
|All compression methods
|
|
178
|
+
|
|
179
|
+
|HLP (Windows Help)
|
|
180
|
+
|✅
|
|
181
|
+
|❌
|
|
182
|
+
|Cabriolet-only: QuickHelp + WinHelp 3.x/4.x
|
|
183
|
+
|
|
184
|
+
|LIT (Microsoft Reader)
|
|
185
|
+
|✅
|
|
186
|
+
|✅
|
|
187
|
+
|Non-DRM files only
|
|
188
|
+
|
|
189
|
+
|OAB (Offline Address Book)
|
|
190
|
+
|✅
|
|
191
|
+
|✅
|
|
192
|
+
|Including incremental patches
|
|
193
|
+
|
|
194
|
+
4+h|**Compression Algorithms**
|
|
195
|
+
|
|
196
|
+
|None (uncompressed)
|
|
197
|
+
|✅
|
|
198
|
+
|✅
|
|
199
|
+
|
|
|
200
|
+
|
|
201
|
+
|LZSS (4KB window)
|
|
202
|
+
|✅
|
|
203
|
+
|✅
|
|
204
|
+
|3 modes: EXPAND, MSHELP, QBASIC
|
|
205
|
+
|
|
206
|
+
|MSZIP (DEFLATE)
|
|
207
|
+
|✅
|
|
208
|
+
|✅
|
|
209
|
+
|RFC 1951 compatible
|
|
210
|
+
|
|
211
|
+
|LZX (advanced)
|
|
212
|
+
|✅
|
|
213
|
+
|✅
|
|
214
|
+
|Intel E8 preprocessing, 32KB-2MB windows
|
|
215
|
+
|
|
216
|
+
|Quantum (arithmetic)
|
|
217
|
+
|✅
|
|
218
|
+
|✅
|
|
219
|
+
|Decompression production-ready
|
|
220
|
+
|
|
221
|
+
4+h|**Operations**
|
|
222
|
+
|
|
223
|
+
|Decompression
|
|
224
|
+
|✅
|
|
225
|
+
|✅
|
|
226
|
+
|
|
|
227
|
+
|
|
228
|
+
|Compression
|
|
229
|
+
|✅
|
|
230
|
+
|⚠️
|
|
231
|
+
|libmspack has limited compression support
|
|
232
|
+
|
|
233
|
+
|Multi-part cabinets
|
|
234
|
+
|✅
|
|
235
|
+
|✅
|
|
236
|
+
|Spanning and merging
|
|
237
|
+
|
|
238
|
+
|Embedded cabinet search
|
|
239
|
+
|✅
|
|
240
|
+
|✅
|
|
241
|
+
|
|
|
242
|
+
|
|
243
|
+
|Salvage mode
|
|
244
|
+
|✅
|
|
245
|
+
|✅
|
|
246
|
+
|Corrupted file recovery
|
|
247
|
+
|
|
248
|
+
|Checksum verification
|
|
249
|
+
|✅
|
|
250
|
+
|✅
|
|
251
|
+
|
|
|
252
|
+
|
|
253
|
+
4+h|**Platform & Integration**
|
|
254
|
+
|
|
255
|
+
|Pure Ruby / No compilation
|
|
256
|
+
|✅
|
|
257
|
+
|❌
|
|
258
|
+
|Cabriolet works everywhere Ruby runs
|
|
259
|
+
|
|
260
|
+
|C library performance
|
|
261
|
+
|❌
|
|
262
|
+
|✅
|
|
263
|
+
|libmspack is faster for large files
|
|
264
|
+
|
|
265
|
+
|Ruby native integration
|
|
266
|
+
|✅
|
|
267
|
+
|⚠️
|
|
268
|
+
|libmspack requires FFI bindings
|
|
269
|
+
|
|
270
|
+
|JRuby / TruffleRuby
|
|
271
|
+
|✅
|
|
272
|
+
|❌
|
|
273
|
+
|Cabriolet works on all Ruby implementations
|
|
274
|
+
|
|
275
|
+
|Windows native
|
|
276
|
+
|✅
|
|
277
|
+
|⚠️
|
|
278
|
+
|libmspack needs compilation on Windows
|
|
279
|
+
|===
|
|
280
|
+
|
|
281
|
+
=== When to Use Cabriolet
|
|
282
|
+
|
|
283
|
+
* **Pure Ruby environment** - No compilation or native dependencies needed
|
|
284
|
+
* **Cross-platform deployment** - Works identically on Linux, macOS, Windows
|
|
285
|
+
* **Alternative Ruby implementations** - JRuby, TruffleRuby, etc.
|
|
286
|
+
* **HLP file support** - Only Cabriolet supports Windows Help files
|
|
287
|
+
* **Compression support** - Full bidirectional support for all formats
|
|
288
|
+
* **Simplicity** - Single gem install, no system dependencies
|
|
289
|
+
|
|
290
|
+
=== When to Use libmspack
|
|
291
|
+
|
|
292
|
+
* **Maximum performance** - C implementation is faster for large files
|
|
293
|
+
* **Existing C/C++ codebase** - Native integration without Ruby
|
|
294
|
+
* **Memory-constrained environments** - Lower memory overhead
|
|
295
|
+
* **Battle-tested stability** - 20+ years of production use
|
|
296
|
+
|
|
297
|
+
=== Performance Comparison
|
|
298
|
+
|
|
299
|
+
[cols="1,1,1"]
|
|
300
|
+
|===
|
|
301
|
+
|Operation |Cabriolet |libmspack
|
|
302
|
+
|
|
303
|
+
|Small CAB (<1MB)
|
|
304
|
+
|~50ms
|
|
305
|
+
|~10ms
|
|
306
|
+
|
|
307
|
+
|Large CAB (100MB)
|
|
308
|
+
|~5s
|
|
309
|
+
|~1s
|
|
310
|
+
|
|
311
|
+
|CHM extraction
|
|
312
|
+
|~100ms
|
|
313
|
+
|~20ms
|
|
314
|
+
|
|
315
|
+
|Memory usage
|
|
316
|
+
|Higher
|
|
317
|
+
|Lower
|
|
318
|
+
|===
|
|
319
|
+
|
|
320
|
+
NOTE: Performance varies by file content and compression type. For most applications, Cabriolet's performance is adequate. Use libmspack via https://github.com/davispuh/ruby-libmspack[FFI bindings] if raw speed is critical.
|
|
321
|
+
|
|
322
|
+
=== libmspack Compatibility
|
|
323
|
+
|
|
324
|
+
Cabriolet maintains **100% compatibility** with libmspack's behavior through extensive parity testing:
|
|
325
|
+
|
|
326
|
+
* **73 libmspack parity tests** - All passing
|
|
327
|
+
* **Identical output** - MD5-verified extraction results
|
|
328
|
+
* **Same error handling** - Compatible error conditions
|
|
329
|
+
* **CVE coverage** - Tests for known vulnerabilities (CVE-2014-9732, CVE-2015-4467, etc.)
|
|
330
|
+
|
|
73
331
|
== Installation
|
|
74
332
|
|
|
75
333
|
Add to your Gemfile:
|
|
@@ -321,20 +579,33 @@ cabriolet kwaj-info setup.kwj
|
|
|
321
579
|
|
|
322
580
|
==== HLP (Windows Help) operations
|
|
323
581
|
|
|
324
|
-
|
|
582
|
+
Cabriolet supports both HLP format variants:
|
|
583
|
+
|
|
584
|
+
* **QuickHelp** - DOS-based format (0x4C 0x4E signature)
|
|
585
|
+
* **Windows Help** - Windows 3.x/4.x format (0x35F3/0x3F5F signatures)
|
|
586
|
+
|
|
587
|
+
===== Extract HLP file (auto-detects format)
|
|
325
588
|
|
|
326
589
|
[source,shell]
|
|
327
590
|
----
|
|
328
591
|
cabriolet hlp-extract help.hlp output/
|
|
329
592
|
----
|
|
330
593
|
|
|
331
|
-
===== Create
|
|
594
|
+
===== Create QuickHelp file
|
|
332
595
|
|
|
333
596
|
[source,shell]
|
|
334
597
|
----
|
|
335
598
|
cabriolet hlp-create output.hlp topic1.txt topic2.txt
|
|
336
599
|
----
|
|
337
600
|
|
|
601
|
+
===== Create Windows Help file (3.x or 4.x)
|
|
602
|
+
|
|
603
|
+
[source,shell]
|
|
604
|
+
----
|
|
605
|
+
cabriolet hlp-create output.hlp topic1.txt topic2.txt --format winhelp3
|
|
606
|
+
cabriolet hlp-create output.hlp topic1.txt topic2.txt --format winhelp4
|
|
607
|
+
----
|
|
608
|
+
|
|
338
609
|
===== Show HLP information
|
|
339
610
|
|
|
340
611
|
[source,shell]
|
|
@@ -664,35 +935,84 @@ bytes = compressor.compress("file.exe", "file.kwj",
|
|
|
664
935
|
|
|
665
936
|
==== HLP (Windows Help) operations
|
|
666
937
|
|
|
667
|
-
===== Extract HLP file
|
|
938
|
+
===== Extract HLP file (auto-detects format)
|
|
668
939
|
|
|
669
940
|
[source,ruby]
|
|
670
941
|
----
|
|
942
|
+
# Works with both QuickHelp and Windows Help formats
|
|
671
943
|
decompressor = Cabriolet::HLP::Decompressor.new
|
|
672
|
-
|
|
944
|
+
header = decompressor.open("help.hlp")
|
|
945
|
+
|
|
946
|
+
# Format is automatically detected
|
|
947
|
+
case header
|
|
948
|
+
when Cabriolet::Models::HLPHeader
|
|
949
|
+
puts "QuickHelp format (DOS)"
|
|
950
|
+
when Cabriolet::Models::WinHelpHeader
|
|
951
|
+
puts "Windows Help format (#{header.version_string})"
|
|
952
|
+
end
|
|
673
953
|
|
|
674
954
|
# Extract files
|
|
675
|
-
|
|
676
|
-
decompressor.extract_file(file, "output/#{file.filename}")
|
|
677
|
-
end
|
|
955
|
+
decompressor.extract_all(header, "output/")
|
|
678
956
|
----
|
|
679
957
|
|
|
680
|
-
===== Create
|
|
958
|
+
===== Create QuickHelp file
|
|
681
959
|
|
|
682
960
|
[source,ruby]
|
|
683
961
|
----
|
|
684
962
|
compressor = Cabriolet::HLP::Compressor.new
|
|
685
963
|
|
|
686
|
-
# Add
|
|
687
|
-
compressor.
|
|
688
|
-
compressor.
|
|
964
|
+
# Add topics
|
|
965
|
+
compressor.add_data("Topic 1 text", "topic1")
|
|
966
|
+
compressor.add_data("Topic 2 text", "topic2")
|
|
967
|
+
|
|
968
|
+
# Generate QuickHelp format (DOS)
|
|
969
|
+
bytes = compressor.generate("help.hlp",
|
|
970
|
+
database_name: "MyHelp",
|
|
971
|
+
control_character: 0x3A) # ':'
|
|
972
|
+
----
|
|
973
|
+
|
|
974
|
+
===== Create Windows Help file
|
|
975
|
+
|
|
976
|
+
[source,ruby]
|
|
977
|
+
----
|
|
978
|
+
# Create WinHelp 3.x format file
|
|
979
|
+
compressor = Cabriolet::HLP::WinHelp::Compressor.new
|
|
980
|
+
|
|
981
|
+
# Add system metadata
|
|
982
|
+
compressor.add_system_file(
|
|
983
|
+
title: "My Help File",
|
|
984
|
+
copyright: "Copyright 2025",
|
|
985
|
+
contents: "contents.hlp")
|
|
986
|
+
|
|
987
|
+
# Add topics (automatically compressed with Zeck LZ77)
|
|
988
|
+
compressor.add_topic_file(["Topic 1 text", "Topic 2 text"], compress: true)
|
|
989
|
+
|
|
990
|
+
# Generate WinHelp 3.x or 4.x
|
|
991
|
+
bytes = compressor.generate("help.hlp", version: :winhelp3)
|
|
992
|
+
# or version: :winhelp4 for WinHelp 4.x format
|
|
993
|
+
----
|
|
994
|
+
|
|
995
|
+
===== Extract Windows Help internal files
|
|
996
|
+
|
|
997
|
+
[source,ruby]
|
|
998
|
+
----
|
|
999
|
+
decompressor = Cabriolet::HLP::WinHelp::Decompressor.new("help.hlp")
|
|
1000
|
+
header = decompressor.parse
|
|
1001
|
+
|
|
1002
|
+
# List internal files (|SYSTEM, |TOPIC, etc.)
|
|
1003
|
+
puts decompressor.internal_filenames
|
|
1004
|
+
|
|
1005
|
+
# Extract specific internal file
|
|
1006
|
+
system_data = decompressor.extract_system_file
|
|
1007
|
+
topic_data = decompressor.extract_topic_file
|
|
689
1008
|
|
|
690
|
-
#
|
|
691
|
-
|
|
1009
|
+
# Decompress topics
|
|
1010
|
+
if topic_data
|
|
1011
|
+
decompressed = decompressor.decompress_topic(topic_data, expected_size)
|
|
1012
|
+
end
|
|
692
1013
|
----
|
|
693
1014
|
|
|
694
|
-
NOTE:
|
|
695
|
-
libmspack source code.
|
|
1015
|
+
NOTE: Windows Help format has limited public documentation. Implementation is based on reverse engineering and the helpdeco project.
|
|
696
1016
|
|
|
697
1017
|
==== LIT (eBook) operations
|
|
698
1018
|
|
|
@@ -805,6 +1125,298 @@ custom_io = CustomIOSystem.new
|
|
|
805
1125
|
decompressor = Cabriolet::CAB::Decompressor.new(custom_io)
|
|
806
1126
|
----
|
|
807
1127
|
|
|
1128
|
+
=== Custom Algorithm Registration
|
|
1129
|
+
|
|
1130
|
+
Cabriolet allows you to register custom compression/decompression algorithms with the [`AlgorithmFactory`](lib/cabriolet/algorithm_factory.rb:1). This enables:
|
|
1131
|
+
|
|
1132
|
+
* **Custom implementations** of standard algorithms for optimization
|
|
1133
|
+
* **Experimental algorithms** for research and development
|
|
1134
|
+
* **Format-specific variations** of compression algorithms
|
|
1135
|
+
* **Testing environments** with isolated algorithm sets
|
|
1136
|
+
|
|
1137
|
+
==== Registering a Custom Algorithm
|
|
1138
|
+
|
|
1139
|
+
[source,ruby]
|
|
1140
|
+
----
|
|
1141
|
+
# Define your custom algorithm (must inherit from Base)
|
|
1142
|
+
class MyOptimizedLZX < Cabriolet::Decompressors::Base
|
|
1143
|
+
def decompress(input_size, output_size)
|
|
1144
|
+
# Your optimized implementation
|
|
1145
|
+
data = @input.read(input_size)
|
|
1146
|
+
# ... custom decompression logic
|
|
1147
|
+
@output.write(decompressed_data)
|
|
1148
|
+
output_size
|
|
1149
|
+
end
|
|
1150
|
+
end
|
|
1151
|
+
|
|
1152
|
+
# Register globally
|
|
1153
|
+
Cabriolet.algorithm_factory.register(
|
|
1154
|
+
:optimized_lzx,
|
|
1155
|
+
MyOptimizedLZX,
|
|
1156
|
+
category: :decompressor,
|
|
1157
|
+
priority: 10 # Higher priority = preferred over built-ins
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
# Use in extraction (automatically uses your custom algorithm)
|
|
1161
|
+
decompressor = Cabriolet::CAB::Decompressor.new("archive.cab")
|
|
1162
|
+
# When extracting LZX folders, your algorithm will be used
|
|
1163
|
+
----
|
|
1164
|
+
|
|
1165
|
+
==== Per-Instance Custom Factory
|
|
1166
|
+
|
|
1167
|
+
For isolated testing or experimentation without affecting global state:
|
|
1168
|
+
|
|
1169
|
+
[source,ruby]
|
|
1170
|
+
----
|
|
1171
|
+
# Create custom factory without built-in algorithms
|
|
1172
|
+
custom_factory = Cabriolet::AlgorithmFactory.new(auto_register: false)
|
|
1173
|
+
|
|
1174
|
+
# Register only your algorithms
|
|
1175
|
+
custom_factory.register(:my_algo, MyAlgorithm, category: :decompressor)
|
|
1176
|
+
|
|
1177
|
+
# Create decompressor instances with custom factory
|
|
1178
|
+
# (Note: Not all format handlers currently support custom factories)
|
|
1179
|
+
decompressor = Cabriolet::CAB::Decompressor.new
|
|
1180
|
+
# Custom factory usage would be implemented by format handlers
|
|
1181
|
+
----
|
|
1182
|
+
|
|
1183
|
+
==== Replacing Built-in Algorithms
|
|
1184
|
+
|
|
1185
|
+
You can replace built-in algorithms with optimized versions:
|
|
1186
|
+
|
|
1187
|
+
[source,ruby]
|
|
1188
|
+
----
|
|
1189
|
+
# Unregister the built-in
|
|
1190
|
+
Cabriolet.algorithm_factory.unregister(:lzss, :decompressor)
|
|
1191
|
+
|
|
1192
|
+
# Register your optimized version
|
|
1193
|
+
Cabriolet.algorithm_factory.register(
|
|
1194
|
+
:lzss,
|
|
1195
|
+
MyOptimizedLZSS,
|
|
1196
|
+
category: :decompressor,
|
|
1197
|
+
priority: 10
|
|
1198
|
+
)
|
|
1199
|
+
|
|
1200
|
+
# All future LZSS decompression will use your implementation
|
|
1201
|
+
----
|
|
1202
|
+
|
|
1203
|
+
==== Format-Specific Algorithms
|
|
1204
|
+
|
|
1205
|
+
Register algorithms that only apply to specific formats:
|
|
1206
|
+
|
|
1207
|
+
[source,ruby]
|
|
1208
|
+
----
|
|
1209
|
+
# Register CAB-specific LZX variant
|
|
1210
|
+
Cabriolet.algorithm_factory.register(
|
|
1211
|
+
:cab_lzx,
|
|
1212
|
+
CABOptimizedLZX,
|
|
1213
|
+
category: :decompressor,
|
|
1214
|
+
format: :cab # Only used for CAB files
|
|
1215
|
+
)
|
|
1216
|
+
|
|
1217
|
+
# Register CHM-specific variant
|
|
1218
|
+
Cabriolet.algorithm_factory.register(
|
|
1219
|
+
:chm_lzx,
|
|
1220
|
+
CHMOptimizedLZX,
|
|
1221
|
+
category: :decompressor,
|
|
1222
|
+
format: :chm # Only used for CHM files
|
|
1223
|
+
)
|
|
1224
|
+
----
|
|
1225
|
+
|
|
1226
|
+
==== Algorithm Requirements
|
|
1227
|
+
|
|
1228
|
+
Custom algorithms must:
|
|
1229
|
+
|
|
1230
|
+
* **Inherit from the appropriate base class**:
|
|
1231
|
+
** `Cabriolet::Compressors::Base` for compressors
|
|
1232
|
+
** `Cabriolet::Decompressors::Base` for decompressors
|
|
1233
|
+
|
|
1234
|
+
* **Implement required methods**:
|
|
1235
|
+
** Decompressors: `decompress(input_size, output_size)`
|
|
1236
|
+
** Compressors: `compress()`
|
|
1237
|
+
|
|
1238
|
+
* **Use provided instance variables**:
|
|
1239
|
+
** `@input` - Input handle (read operations)
|
|
1240
|
+
** `@output` - Output handle (write operations)
|
|
1241
|
+
** `@io_system` - I/O system for operations
|
|
1242
|
+
** `@buffer_size` - Buffer size for operations
|
|
1243
|
+
|
|
1244
|
+
**Example custom decompressor**:
|
|
1245
|
+
|
|
1246
|
+
[source,ruby]
|
|
1247
|
+
----
|
|
1248
|
+
class CustomAlgorithm < Cabriolet::Decompressors::Base
|
|
1249
|
+
def decompress(input_size, output_size)
|
|
1250
|
+
# Read compressed data
|
|
1251
|
+
compressed = @input.read(input_size)
|
|
1252
|
+
|
|
1253
|
+
# Your decompression logic
|
|
1254
|
+
decompressed = my_decompress_logic(compressed)
|
|
1255
|
+
|
|
1256
|
+
# Write decompressed data
|
|
1257
|
+
@output.write(decompressed)
|
|
1258
|
+
|
|
1259
|
+
# Return bytes written
|
|
1260
|
+
decompressed.bytesize
|
|
1261
|
+
end
|
|
1262
|
+
|
|
1263
|
+
private
|
|
1264
|
+
|
|
1265
|
+
def my_decompress_logic(data)
|
|
1266
|
+
# Custom decompression implementation
|
|
1267
|
+
end
|
|
1268
|
+
end
|
|
1269
|
+
----
|
|
1270
|
+
|
|
1271
|
+
**Example custom compressor**:
|
|
1272
|
+
|
|
1273
|
+
[source,ruby]
|
|
1274
|
+
----
|
|
1275
|
+
class CustomCompressor < Cabriolet::Compressors::Base
|
|
1276
|
+
def compress
|
|
1277
|
+
# Read uncompressed data
|
|
1278
|
+
data = @input.read
|
|
1279
|
+
|
|
1280
|
+
# Your compression logic
|
|
1281
|
+
compressed = my_compress_logic(data)
|
|
1282
|
+
|
|
1283
|
+
# Write compressed data
|
|
1284
|
+
@output.write(compressed)
|
|
1285
|
+
|
|
1286
|
+
# Return bytes written
|
|
1287
|
+
compressed.bytesize
|
|
1288
|
+
end
|
|
1289
|
+
|
|
1290
|
+
private
|
|
1291
|
+
|
|
1292
|
+
def my_compress_logic(data)
|
|
1293
|
+
# Custom compression implementation
|
|
1294
|
+
end
|
|
1295
|
+
end
|
|
1296
|
+
----
|
|
1297
|
+
|
|
1298
|
+
==== Use Cases
|
|
1299
|
+
|
|
1300
|
+
**Performance optimization**::
|
|
1301
|
+
Replace built-in algorithms with platform-optimized versions (e.g., using native extensions for specific platforms)
|
|
1302
|
+
|
|
1303
|
+
**Research and development**::
|
|
1304
|
+
Test experimental compression algorithms without modifying the core library
|
|
1305
|
+
|
|
1306
|
+
**Format variations**::
|
|
1307
|
+
Implement format-specific optimizations or variations of standard algorithms
|
|
1308
|
+
|
|
1309
|
+
**Testing**::
|
|
1310
|
+
Create isolated test environments with mock or simplified algorithms
|
|
1311
|
+
|
|
1312
|
+
== Plugin Architecture
|
|
1313
|
+
|
|
1314
|
+
Cabriolet supports a powerful plugin system that enables easy distribution and loading of extensions.
|
|
1315
|
+
|
|
1316
|
+
=== Installing Plugins
|
|
1317
|
+
|
|
1318
|
+
Plugins are distributed as Ruby gems with the naming pattern `cabriolet-plugin-*`:
|
|
1319
|
+
|
|
1320
|
+
[source,bash]
|
|
1321
|
+
----
|
|
1322
|
+
gem install cabriolet-plugin-bzip2
|
|
1323
|
+
----
|
|
1324
|
+
|
|
1325
|
+
=== Loading Plugins
|
|
1326
|
+
|
|
1327
|
+
Plugins are automatically discovered from installed gems:
|
|
1328
|
+
|
|
1329
|
+
[source,ruby]
|
|
1330
|
+
----
|
|
1331
|
+
require 'cabriolet'
|
|
1332
|
+
|
|
1333
|
+
# Discover all installed plugins
|
|
1334
|
+
Cabriolet.plugin_manager.discover_plugins
|
|
1335
|
+
|
|
1336
|
+
# Load and activate a specific plugin
|
|
1337
|
+
Cabriolet.plugin_manager.load_plugin('bzip2')
|
|
1338
|
+
Cabriolet.plugin_manager.activate_plugin('bzip2')
|
|
1339
|
+
|
|
1340
|
+
# Or auto-activate all plugins
|
|
1341
|
+
Cabriolet.plugin_manager.auto_activate_plugins
|
|
1342
|
+
----
|
|
1343
|
+
|
|
1344
|
+
=== Listing Plugins
|
|
1345
|
+
|
|
1346
|
+
[source,ruby]
|
|
1347
|
+
----
|
|
1348
|
+
# List all plugins
|
|
1349
|
+
plugins = Cabriolet.plugin_manager.list_plugins
|
|
1350
|
+
|
|
1351
|
+
# List only active plugins
|
|
1352
|
+
active = Cabriolet.plugin_manager.list_plugins(state: :active)
|
|
1353
|
+
|
|
1354
|
+
# Check if a plugin is active
|
|
1355
|
+
if Cabriolet.plugin_manager.plugin_active?('bzip2')
|
|
1356
|
+
puts "BZip2 plugin is active"
|
|
1357
|
+
end
|
|
1358
|
+
----
|
|
1359
|
+
|
|
1360
|
+
=== Creating Plugins
|
|
1361
|
+
|
|
1362
|
+
To create your own plugin, see the example plugins:
|
|
1363
|
+
|
|
1364
|
+
- `examples/plugins/cabriolet-plugin-example/` - Simple ROT13 example
|
|
1365
|
+
- `examples/plugins/cabriolet-plugin-bzip2/` - Advanced BZip2 example
|
|
1366
|
+
|
|
1367
|
+
Basic plugin structure:
|
|
1368
|
+
|
|
1369
|
+
[source,ruby]
|
|
1370
|
+
----
|
|
1371
|
+
class MyPlugin < Cabriolet::Plugin
|
|
1372
|
+
def metadata
|
|
1373
|
+
{
|
|
1374
|
+
name: "my-plugin",
|
|
1375
|
+
version: "1.0.0",
|
|
1376
|
+
author: "Your Name",
|
|
1377
|
+
description: "My custom compression algorithm",
|
|
1378
|
+
cabriolet_version: "~> 0.1"
|
|
1379
|
+
}
|
|
1380
|
+
end
|
|
1381
|
+
|
|
1382
|
+
def setup
|
|
1383
|
+
# Register your algorithms
|
|
1384
|
+
register_algorithm(:my_algo, MyCompressor, category: :compressor)
|
|
1385
|
+
register_algorithm(:my_algo, MyDecompressor, category: :decompressor)
|
|
1386
|
+
end
|
|
1387
|
+
end
|
|
1388
|
+
----
|
|
1389
|
+
|
|
1390
|
+
=== Plugin Configuration
|
|
1391
|
+
|
|
1392
|
+
Configure plugins via `~/.cabriolet/plugins.yml`:
|
|
1393
|
+
|
|
1394
|
+
[source,yaml]
|
|
1395
|
+
----
|
|
1396
|
+
discovery:
|
|
1397
|
+
auto_discover: true
|
|
1398
|
+
auto_load: true
|
|
1399
|
+
auto_activate: true
|
|
1400
|
+
|
|
1401
|
+
plugins:
|
|
1402
|
+
bzip2:
|
|
1403
|
+
enabled: true
|
|
1404
|
+
config:
|
|
1405
|
+
compression_level: 9
|
|
1406
|
+
----
|
|
1407
|
+
|
|
1408
|
+
=== Plugin Safety
|
|
1409
|
+
|
|
1410
|
+
All plugins are validated before loading:
|
|
1411
|
+
|
|
1412
|
+
- ✓ Inheritance validation
|
|
1413
|
+
- ✓ Metadata validation
|
|
1414
|
+
- ✓ Version compatibility checking
|
|
1415
|
+
- ✓ Dependency resolution
|
|
1416
|
+
- ✓ Safety scanning
|
|
1417
|
+
|
|
1418
|
+
Failed plugins are isolated and don't affect Cabriolet or other plugins.
|
|
1419
|
+
|
|
808
1420
|
=== Error Handling
|
|
809
1421
|
|
|
810
1422
|
==== Common errors
|
|
@@ -1101,6 +1713,26 @@ bundle exec rubocop -A # Auto-correct
|
|
|
1101
1713
|
|
|
1102
1714
|
== Known limitations
|
|
1103
1715
|
|
|
1716
|
+
For complete details on known issues and workarounds, see
|
|
1717
|
+
link:KNOWN_ISSUES.md[Known Issues].
|
|
1718
|
+
|
|
1719
|
+
=== LZX Compression
|
|
1720
|
+
|
|
1721
|
+
LZX compression is **production ready** for most use cases:
|
|
1722
|
+
|
|
1723
|
+
* ✅ **CHM files**: 100% working, all features
|
|
1724
|
+
* ✅ **Single-folder CAB**: 100% working
|
|
1725
|
+
* ✅ **Decompression**: UNCOMPRESSED blocks fully supported
|
|
1726
|
+
* ✅ **Compression**: UNCOMPRESSED blocks fully supported
|
|
1727
|
+
* ⚠️ **Multi-folder CAB**: Files at non-zero offsets in second+ folders
|
|
1728
|
+
** Affects: <5% of CAB files
|
|
1729
|
+
** Workaround: Use salvage mode or extract folders separately
|
|
1730
|
+
** Status: Deferred to v0.2.0
|
|
1731
|
+
* ⚠️ **VERBATIM/ALIGNED blocks**: Compression needs implementation
|
|
1732
|
+
** Affects: Advanced CHM creation
|
|
1733
|
+
** Decompression: Working
|
|
1734
|
+
** Status: Planned for v0.2.0
|
|
1735
|
+
|
|
1104
1736
|
=== Quantum compression
|
|
1105
1737
|
|
|
1106
1738
|
Quantum compression is **functional but experimental**:
|
|
@@ -1122,10 +1754,54 @@ Quantum compression is **functional but experimental**:
|
|
|
1122
1754
|
|
|
1123
1755
|
=== HLP/LIT/OAB Formats
|
|
1124
1756
|
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1127
|
-
|
|
1128
|
-
|
|
1757
|
+
* LIT format has no public specification (implementation based on libmspack)
|
|
1758
|
+
* HLP format supports both QuickHelp (DOS) and Windows Help (3.x/4.x)
|
|
1759
|
+
** QuickHelp format fully documented, production ready
|
|
1760
|
+
** Windows Help format based on reverse engineering, production ready
|
|
1761
|
+
* OAB format has limited documentation (implementation based on libmspack)
|
|
1762
|
+
* All formats are fully functional for basic operations
|
|
1763
|
+
* Edge cases for advanced features may exist
|
|
1764
|
+
|
|
1765
|
+
=== Not yet supported
|
|
1766
|
+
|
|
1767
|
+
The following features are documented as pending (64 specs total):
|
|
1768
|
+
|
|
1769
|
+
**Multi-file extraction** (6 specs):
|
|
1770
|
+
- MSZIP folders with multiple files
|
|
1771
|
+
- LZX folders with multiple files
|
|
1772
|
+
- Requires: State reuse implementation (4-6 hours)
|
|
1773
|
+
- Status: In progress for v0.1.0
|
|
1774
|
+
|
|
1775
|
+
**LZX VERBATIM/ALIGNED compression** (7 specs):
|
|
1776
|
+
- CHM round-trip compression
|
|
1777
|
+
- Optimal LZX compression
|
|
1778
|
+
- Decompression works, compression needs trees
|
|
1779
|
+
- Status: Deferred to v0.2.0
|
|
1780
|
+
|
|
1781
|
+
**Quantum edge cases** (22 specs):
|
|
1782
|
+
- Very long matches (14+ bytes)
|
|
1783
|
+
- Complex pattern encoding
|
|
1784
|
+
- Frame boundary cases
|
|
1785
|
+
- Note: Core functionality validated with libmspack, likely over-cautious
|
|
1786
|
+
- Status: Low priority, optional refinement
|
|
1787
|
+
|
|
1788
|
+
**LIT extraction tests** (4 specs):
|
|
1789
|
+
- Tests need adjustment for directory model
|
|
1790
|
+
- Parser works correctly
|
|
1791
|
+
- Status: Test refactoring needed (1-2 hours)
|
|
1792
|
+
|
|
1793
|
+
**QuickHelp real files** (4 specs):
|
|
1794
|
+
- Real file extraction tests
|
|
1795
|
+
- Fixture investigation needed
|
|
1796
|
+
- Status: Low priority
|
|
1797
|
+
|
|
1798
|
+
**Edge cases** (21 specs):
|
|
1799
|
+
- 1-byte search buffer
|
|
1800
|
+
- Various format-specific edge cases
|
|
1801
|
+
- Window size variations
|
|
1802
|
+
- Status: Low priority, optional enhancements
|
|
1803
|
+
|
|
1804
|
+
**Total pending**: 64 specs (5% of test suite)
|
|
1129
1805
|
|
|
1130
1806
|
|
|
1131
1807
|
== Troubleshooting
|
|
@@ -1151,17 +1827,6 @@ decompressor.fix_mszip = true
|
|
|
1151
1827
|
decompressor.salvage = true
|
|
1152
1828
|
----
|
|
1153
1829
|
|
|
1154
|
-
=== Performance issues
|
|
1155
|
-
|
|
1156
|
-
Problem:: Slow extraction
|
|
1157
|
-
|
|
1158
|
-
Solution:: Increase buffer size:
|
|
1159
|
-
|
|
1160
|
-
[source,ruby]
|
|
1161
|
-
----
|
|
1162
|
-
decompressor.buffer_size = 16384
|
|
1163
|
-
----
|
|
1164
|
-
|
|
1165
1830
|
|
|
1166
1831
|
== Specifications
|
|
1167
1832
|
|