summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-03-11 18:46:03 +0100
committerDominik Riebeling <Dominik.Riebeling@gmail.com>2013-11-04 22:14:17 +0100
commit739a7ae0e9acb27227f5473a003833ea5a9c97ef (patch)
tree81f6dfd81b4343745b21a6c00c286791827175e4
parent27111d83be815602ac35354e6a8e4e158c5968f9 (diff)
downloadrockbox-739a7ae0e9acb27227f5473a003833ea5a9c97ef.tar.gz
rockbox-739a7ae0e9acb27227f5473a003833ea5a9c97ef.zip
Add libmspack to rbutil
Change-Id: I520c14131ec1e12013f106c13cba00aac058ad83 Reviewed-on: http://gerrit.rockbox.org/391 Reviewed-by: Dominik Riebeling <Dominik.Riebeling@gmail.com>
-rw-r--r--rbutil/rbutilqt/mspack/COPYING.LIB504
-rw-r--r--rbutil/rbutilqt/mspack/README.ROCKBOX6
-rw-r--r--rbutil/rbutilqt/mspack/cab.h127
-rw-r--r--rbutil/rbutilqt/mspack/cabc.c24
-rw-r--r--rbutil/rbutilqt/mspack/cabd.c1444
-rw-r--r--rbutil/rbutilqt/mspack/chm.h122
-rw-r--r--rbutil/rbutilqt/mspack/chmc.c24
-rw-r--r--rbutil/rbutilqt/mspack/chmd.c1346
-rw-r--r--rbutil/rbutilqt/mspack/des.h15
-rw-r--r--rbutil/rbutilqt/mspack/hlp.h33
-rw-r--r--rbutil/rbutilqt/mspack/hlpc.c24
-rw-r--r--rbutil/rbutilqt/mspack/hlpd.c24
-rw-r--r--rbutil/rbutilqt/mspack/kwaj.h118
-rw-r--r--rbutil/rbutilqt/mspack/kwajc.c24
-rw-r--r--rbutil/rbutilqt/mspack/kwajd.c555
-rw-r--r--rbutil/rbutilqt/mspack/lit.h35
-rw-r--r--rbutil/rbutilqt/mspack/litc.c24
-rw-r--r--rbutil/rbutilqt/mspack/litd.c24
-rw-r--r--rbutil/rbutilqt/mspack/lzss.h66
-rw-r--r--rbutil/rbutilqt/mspack/lzssd.c93
-rw-r--r--rbutil/rbutilqt/mspack/lzx.h194
-rw-r--r--rbutil/rbutilqt/mspack/lzxc.c18
-rw-r--r--rbutil/rbutilqt/mspack/lzxd.c738
-rw-r--r--rbutil/rbutilqt/mspack/mspack.h2203
-rw-r--r--rbutil/rbutilqt/mspack/mszip.h121
-rw-r--r--rbutil/rbutilqt/mspack/mszipc.c18
-rw-r--r--rbutil/rbutilqt/mspack/mszipd.c475
-rw-r--r--rbutil/rbutilqt/mspack/qtm.h128
-rw-r--r--rbutil/rbutilqt/mspack/qtmd.c489
-rw-r--r--rbutil/rbutilqt/mspack/readbits.h207
-rw-r--r--rbutil/rbutilqt/mspack/readhuff.h173
-rw-r--r--rbutil/rbutilqt/mspack/sha.h15
-rw-r--r--rbutil/rbutilqt/mspack/system.c237
-rw-r--r--rbutil/rbutilqt/mspack/system.h124
-rw-r--r--rbutil/rbutilqt/mspack/szdd.h39
-rw-r--r--rbutil/rbutilqt/mspack/szddc.c24
-rw-r--r--rbutil/rbutilqt/mspack/szddd.c247
37 files changed, 10082 insertions, 0 deletions
diff --git a/rbutil/rbutilqt/mspack/COPYING.LIB b/rbutil/rbutilqt/mspack/COPYING.LIB
new file mode 100644
index 0000000000..b1e3f5a263
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/COPYING.LIB
@@ -0,0 +1,504 @@
1 GNU LESSER GENERAL PUBLIC LICENSE
2 Version 2.1, February 1999
3
4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9[This is the first released version of the Lesser GPL. It also counts
10 as the successor of the GNU Library Public License, version 2, hence
11 the version number 2.1.]
12
13 Preamble
14
15 The licenses for most software are designed to take away your
16freedom to share and change it. By contrast, the GNU General Public
17Licenses are intended to guarantee your freedom to share and change
18free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21specially designated software packages--typically libraries--of the
22Free Software Foundation and other authors who decide to use it. You
23can use it too, but we suggest you first think carefully about whether
24this license or the ordinary General Public License is the better
25strategy to use in any particular case, based on the explanations below.
26
27 When we speak of free software, we are referring to freedom of use,
28not price. Our General Public Licenses are designed to make sure that
29you have the freedom to distribute copies of free software (and charge
30for this service if you wish); that you receive source code or can get
31it if you want it; that you can change the software and use pieces of
32it in new free programs; and that you are informed that you can do
33these things.
34
35 To protect your rights, we need to make restrictions that forbid
36distributors to deny you these rights or to ask you to surrender these
37rights. These restrictions translate to certain responsibilities for
38you if you distribute copies of the library or if you modify it.
39
40 For example, if you distribute copies of the library, whether gratis
41or for a fee, you must give the recipients all the rights that we gave
42you. You must make sure that they, too, receive or can get the source
43code. If you link other code with the library, you must provide
44complete object files to the recipients, so that they can relink them
45with the library after making changes to the library and recompiling
46it. And you must show them these terms so they know their rights.
47
48 We protect your rights with a two-step method: (1) we copyright the
49library, and (2) we offer you this license, which gives you legal
50permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53there is no warranty for the free library. Also, if the library is
54modified by someone else and passed on, the recipients should know
55that what they have is not the original version, so that the original
56author's reputation will not be affected by problems that might be
57introduced by others.
58
59 Finally, software patents pose a constant threat to the existence of
60any free program. We wish to make sure that a company cannot
61effectively restrict the users of a free program by obtaining a
62restrictive license from a patent holder. Therefore, we insist that
63any patent license obtained for a version of the library must be
64consistent with the full freedom of use specified in this license.
65
66 Most GNU software, including some libraries, is covered by the
67ordinary GNU General Public License. This license, the GNU Lesser
68General Public License, applies to certain designated libraries, and
69is quite different from the ordinary General Public License. We use
70this license for certain libraries in order to permit linking those
71libraries into non-free programs.
72
73 When a program is linked with a library, whether statically or using
74a shared library, the combination of the two is legally speaking a
75combined work, a derivative of the original library. The ordinary
76General Public License therefore permits such linking only if the
77entire combination fits its criteria of freedom. The Lesser General
78Public License permits more lax criteria for linking other code with
79the library.
80
81 We call this license the "Lesser" General Public License because it
82does Less to protect the user's freedom than the ordinary General
83Public License. It also provides other free software developers Less
84of an advantage over competing non-free programs. These disadvantages
85are the reason we use the ordinary General Public License for many
86libraries. However, the Lesser license provides advantages in certain
87special circumstances.
88
89 For example, on rare occasions, there may be a special need to
90encourage the widest possible use of a certain library, so that it becomes
91a de-facto standard. To achieve this, non-free programs must be
92allowed to use the library. A more frequent case is that a free
93library does the same job as widely used non-free libraries. In this
94case, there is little to gain by limiting the free library to free
95software only, so we use the Lesser General Public License.
96
97 In other cases, permission to use a particular library in non-free
98programs enables a greater number of people to use a large body of
99free software. For example, permission to use the GNU C Library in
100non-free programs enables many more people to use the whole GNU
101operating system, as well as its variant, the GNU/Linux operating
102system.
103
104 Although the Lesser General Public License is Less protective of the
105users' freedom, it does ensure that the user of a program that is
106linked with the Library has the freedom and the wherewithal to run
107that program using a modified version of the Library.
108
109 The precise terms and conditions for copying, distribution and
110modification follow. Pay close attention to the difference between a
111"work based on the library" and a "work that uses the library". The
112former contains code derived from the library, whereas the latter must
113be combined with the library in order to run.
114
115 GNU LESSER GENERAL PUBLIC LICENSE
116 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
118 0. This License Agreement applies to any software library or other
119program which contains a notice placed by the copyright holder or
120other authorized party saying it may be distributed under the terms of
121this Lesser General Public License (also called "this License").
122Each licensee is addressed as "you".
123
124 A "library" means a collection of software functions and/or data
125prepared so as to be conveniently linked with application programs
126(which use some of those functions and data) to form executables.
127
128 The "Library", below, refers to any such software library or work
129which has been distributed under these terms. A "work based on the
130Library" means either the Library or any derivative work under
131copyright law: that is to say, a work containing the Library or a
132portion of it, either verbatim or with modifications and/or translated
133straightforwardly into another language. (Hereinafter, translation is
134included without limitation in the term "modification".)
135
136 "Source code" for a work means the preferred form of the work for
137making modifications to it. For a library, complete source code means
138all the source code for all modules it contains, plus any associated
139interface definition files, plus the scripts used to control compilation
140and installation of the library.
141
142 Activities other than copying, distribution and modification are not
143covered by this License; they are outside its scope. The act of
144running a program using the Library is not restricted, and output from
145such a program is covered only if its contents constitute a work based
146on the Library (independent of the use of the Library in a tool for
147writing it). Whether that is true depends on what the Library does
148and what the program that uses the Library does.
149
150 1. You may copy and distribute verbatim copies of the Library's
151complete source code as you receive it, in any medium, provided that
152you conspicuously and appropriately publish on each copy an
153appropriate copyright notice and disclaimer of warranty; keep intact
154all the notices that refer to this License and to the absence of any
155warranty; and distribute a copy of this License along with the
156Library.
157
158 You may charge a fee for the physical act of transferring a copy,
159and you may at your option offer warranty protection in exchange for a
160fee.
161
162 2. You may modify your copy or copies of the Library or any portion
163of it, thus forming a work based on the Library, and copy and
164distribute such modifications or work under the terms of Section 1
165above, provided that you also meet all of these conditions:
166
167 a) The modified work must itself be a software library.
168
169 b) You must cause the files modified to carry prominent notices
170 stating that you changed the files and the date of any change.
171
172 c) You must cause the whole of the work to be licensed at no
173 charge to all third parties under the terms of this License.
174
175 d) If a facility in the modified Library refers to a function or a
176 table of data to be supplied by an application program that uses
177 the facility, other than as an argument passed when the facility
178 is invoked, then you must make a good faith effort to ensure that,
179 in the event an application does not supply such function or
180 table, the facility still operates, and performs whatever part of
181 its purpose remains meaningful.
182
183 (For example, a function in a library to compute square roots has
184 a purpose that is entirely well-defined independent of the
185 application. Therefore, Subsection 2d requires that any
186 application-supplied function or table used by this function must
187 be optional: if the application does not supply it, the square
188 root function must still compute square roots.)
189
190These requirements apply to the modified work as a whole. If
191identifiable sections of that work are not derived from the Library,
192and can be reasonably considered independent and separate works in
193themselves, then this License, and its terms, do not apply to those
194sections when you distribute them as separate works. But when you
195distribute the same sections as part of a whole which is a work based
196on the Library, the distribution of the whole must be on the terms of
197this License, whose permissions for other licensees extend to the
198entire whole, and thus to each and every part regardless of who wrote
199it.
200
201Thus, it is not the intent of this section to claim rights or contest
202your rights to work written entirely by you; rather, the intent is to
203exercise the right to control the distribution of derivative or
204collective works based on the Library.
205
206In addition, mere aggregation of another work not based on the Library
207with the Library (or with a work based on the Library) on a volume of
208a storage or distribution medium does not bring the other work under
209the scope of this License.
210
211 3. You may opt to apply the terms of the ordinary GNU General Public
212License instead of this License to a given copy of the Library. To do
213this, you must alter all the notices that refer to this License, so
214that they refer to the ordinary GNU General Public License, version 2,
215instead of to this License. (If a newer version than version 2 of the
216ordinary GNU General Public License has appeared, then you can specify
217that version instead if you wish.) Do not make any other change in
218these notices.
219
220 Once this change is made in a given copy, it is irreversible for
221that copy, so the ordinary GNU General Public License applies to all
222subsequent copies and derivative works made from that copy.
223
224 This option is useful when you wish to copy part of the code of
225the Library into a program that is not a library.
226
227 4. You may copy and distribute the Library (or a portion or
228derivative of it, under Section 2) in object code or executable form
229under the terms of Sections 1 and 2 above provided that you accompany
230it with the complete corresponding machine-readable source code, which
231must be distributed under the terms of Sections 1 and 2 above on a
232medium customarily used for software interchange.
233
234 If distribution of object code is made by offering access to copy
235from a designated place, then offering equivalent access to copy the
236source code from the same place satisfies the requirement to
237distribute the source code, even though third parties are not
238compelled to copy the source along with the object code.
239
240 5. A program that contains no derivative of any portion of the
241Library, but is designed to work with the Library by being compiled or
242linked with it, is called a "work that uses the Library". Such a
243work, in isolation, is not a derivative work of the Library, and
244therefore falls outside the scope of this License.
245
246 However, linking a "work that uses the Library" with the Library
247creates an executable that is a derivative of the Library (because it
248contains portions of the Library), rather than a "work that uses the
249library". The executable is therefore covered by this License.
250Section 6 states terms for distribution of such executables.
251
252 When a "work that uses the Library" uses material from a header file
253that is part of the Library, the object code for the work may be a
254derivative work of the Library even though the source code is not.
255Whether this is true is especially significant if the work can be
256linked without the Library, or if the work is itself a library. The
257threshold for this to be true is not precisely defined by law.
258
259 If such an object file uses only numerical parameters, data
260structure layouts and accessors, and small macros and small inline
261functions (ten lines or less in length), then the use of the object
262file is unrestricted, regardless of whether it is legally a derivative
263work. (Executables containing this object code plus portions of the
264Library will still fall under Section 6.)
265
266 Otherwise, if the work is a derivative of the Library, you may
267distribute the object code for the work under the terms of Section 6.
268Any executables containing that work also fall under Section 6,
269whether or not they are linked directly with the Library itself.
270
271 6. As an exception to the Sections above, you may also combine or
272link a "work that uses the Library" with the Library to produce a
273work containing portions of the Library, and distribute that work
274under terms of your choice, provided that the terms permit
275modification of the work for the customer's own use and reverse
276engineering for debugging such modifications.
277
278 You must give prominent notice with each copy of the work that the
279Library is used in it and that the Library and its use are covered by
280this License. You must supply a copy of this License. If the work
281during execution displays copyright notices, you must include the
282copyright notice for the Library among them, as well as a reference
283directing the user to the copy of this License. Also, you must do one
284of these things:
285
286 a) Accompany the work with the complete corresponding
287 machine-readable source code for the Library including whatever
288 changes were used in the work (which must be distributed under
289 Sections 1 and 2 above); and, if the work is an executable linked
290 with the Library, with the complete machine-readable "work that
291 uses the Library", as object code and/or source code, so that the
292 user can modify the Library and then relink to produce a modified
293 executable containing the modified Library. (It is understood
294 that the user who changes the contents of definitions files in the
295 Library will not necessarily be able to recompile the application
296 to use the modified definitions.)
297
298 b) Use a suitable shared library mechanism for linking with the
299 Library. A suitable mechanism is one that (1) uses at run time a
300 copy of the library already present on the user's computer system,
301 rather than copying library functions into the executable, and (2)
302 will operate properly with a modified version of the library, if
303 the user installs one, as long as the modified version is
304 interface-compatible with the version that the work was made with.
305
306 c) Accompany the work with a written offer, valid for at
307 least three years, to give the same user the materials
308 specified in Subsection 6a, above, for a charge no more
309 than the cost of performing this distribution.
310
311 d) If distribution of the work is made by offering access to copy
312 from a designated place, offer equivalent access to copy the above
313 specified materials from the same place.
314
315 e) Verify that the user has already received a copy of these
316 materials or that you have already sent this user a copy.
317
318 For an executable, the required form of the "work that uses the
319Library" must include any data and utility programs needed for
320reproducing the executable from it. However, as a special exception,
321the materials to be distributed need not include anything that is
322normally distributed (in either source or binary form) with the major
323components (compiler, kernel, and so on) of the operating system on
324which the executable runs, unless that component itself accompanies
325the executable.
326
327 It may happen that this requirement contradicts the license
328restrictions of other proprietary libraries that do not normally
329accompany the operating system. Such a contradiction means you cannot
330use both them and the Library together in an executable that you
331distribute.
332
333 7. You may place library facilities that are a work based on the
334Library side-by-side in a single library together with other library
335facilities not covered by this License, and distribute such a combined
336library, provided that the separate distribution of the work based on
337the Library and of the other library facilities is otherwise
338permitted, and provided that you do these two things:
339
340 a) Accompany the combined library with a copy of the same work
341 based on the Library, uncombined with any other library
342 facilities. This must be distributed under the terms of the
343 Sections above.
344
345 b) Give prominent notice with the combined library of the fact
346 that part of it is a work based on the Library, and explaining
347 where to find the accompanying uncombined form of the same work.
348
349 8. You may not copy, modify, sublicense, link with, or distribute
350the Library except as expressly provided under this License. Any
351attempt otherwise to copy, modify, sublicense, link with, or
352distribute the Library is void, and will automatically terminate your
353rights under this License. However, parties who have received copies,
354or rights, from you under this License will not have their licenses
355terminated so long as such parties remain in full compliance.
356
357 9. You are not required to accept this License, since you have not
358signed it. However, nothing else grants you permission to modify or
359distribute the Library or its derivative works. These actions are
360prohibited by law if you do not accept this License. Therefore, by
361modifying or distributing the Library (or any work based on the
362Library), you indicate your acceptance of this License to do so, and
363all its terms and conditions for copying, distributing or modifying
364the Library or works based on it.
365
366 10. Each time you redistribute the Library (or any work based on the
367Library), the recipient automatically receives a license from the
368original licensor to copy, distribute, link with or modify the Library
369subject to these terms and conditions. You may not impose any further
370restrictions on the recipients' exercise of the rights granted herein.
371You are not responsible for enforcing compliance by third parties with
372this License.
373
374 11. If, as a consequence of a court judgment or allegation of patent
375infringement or for any other reason (not limited to patent issues),
376conditions are imposed on you (whether by court order, agreement or
377otherwise) that contradict the conditions of this License, they do not
378excuse you from the conditions of this License. If you cannot
379distribute so as to satisfy simultaneously your obligations under this
380License and any other pertinent obligations, then as a consequence you
381may not distribute the Library at all. For example, if a patent
382license would not permit royalty-free redistribution of the Library by
383all those who receive copies directly or indirectly through you, then
384the only way you could satisfy both it and this License would be to
385refrain entirely from distribution of the Library.
386
387If any portion of this section is held invalid or unenforceable under any
388particular circumstance, the balance of the section is intended to apply,
389and the section as a whole is intended to apply in other circumstances.
390
391It is not the purpose of this section to induce you to infringe any
392patents or other property right claims or to contest validity of any
393such claims; this section has the sole purpose of protecting the
394integrity of the free software distribution system which is
395implemented by public license practices. Many people have made
396generous contributions to the wide range of software distributed
397through that system in reliance on consistent application of that
398system; it is up to the author/donor to decide if he or she is willing
399to distribute software through any other system and a licensee cannot
400impose that choice.
401
402This section is intended to make thoroughly clear what is believed to
403be a consequence of the rest of this License.
404
405 12. If the distribution and/or use of the Library is restricted in
406certain countries either by patents or by copyrighted interfaces, the
407original copyright holder who places the Library under this License may add
408an explicit geographical distribution limitation excluding those countries,
409so that distribution is permitted only in or among countries not thus
410excluded. In such case, this License incorporates the limitation as if
411written in the body of this License.
412
413 13. The Free Software Foundation may publish revised and/or new
414versions of the Lesser General Public License from time to time.
415Such new versions will be similar in spirit to the present version,
416but may differ in detail to address new problems or concerns.
417
418Each version is given a distinguishing version number. If the Library
419specifies a version number of this License which applies to it and
420"any later version", you have the option of following the terms and
421conditions either of that version or of any later version published by
422the Free Software Foundation. If the Library does not specify a
423license version number, you may choose any version ever published by
424the Free Software Foundation.
425
426 14. If you wish to incorporate parts of the Library into other free
427programs whose distribution conditions are incompatible with these,
428write to the author to ask for permission. For software which is
429copyrighted by the Free Software Foundation, write to the Free
430Software Foundation; we sometimes make exceptions for this. Our
431decision will be guided by the two goals of preserving the free status
432of all derivatives of our free software and of promoting the sharing
433and reuse of software generally.
434
435 NO WARRANTY
436
437 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
447 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456DAMAGES.
457
458 END OF TERMS AND CONDITIONS
459
460 How to Apply These Terms to Your New Libraries
461
462 If you develop a new library, and you want it to be of the greatest
463possible use to the public, we recommend making it free software that
464everyone can redistribute and change. You can do so by permitting
465redistribution under these terms (or, alternatively, under the terms of the
466ordinary General Public License).
467
468 To apply these terms, attach the following notices to the library. It is
469safest to attach them to the start of each source file to most effectively
470convey the exclusion of warranty; and each file should have at least the
471"copyright" line and a pointer to where the full notice is found.
472
473 <one line to give the library's name and a brief idea of what it does.>
474 Copyright (C) <year> <name of author>
475
476 This library is free software; you can redistribute it and/or
477 modify it under the terms of the GNU Lesser General Public
478 License as published by the Free Software Foundation; either
479 version 2.1 of the License, or (at your option) any later version.
480
481 This library is distributed in the hope that it will be useful,
482 but WITHOUT ANY WARRANTY; without even the implied warranty of
483 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 Lesser General Public License for more details.
485
486 You should have received a copy of the GNU Lesser General Public
487 License along with this library; if not, write to the Free Software
488 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
489
490Also add information on how to contact you by electronic and paper mail.
491
492You should also get your employer (if you work as a programmer) or your
493school, if any, to sign a "copyright disclaimer" for the library, if
494necessary. Here is a sample; alter the names:
495
496 Yoyodyne, Inc., hereby disclaims all copyright interest in the
497 library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
499 <signature of Ty Coon>, 1 April 1990
500 Ty Coon, President of Vice
501
502That's all there is to it!
503
504
diff --git a/rbutil/rbutilqt/mspack/README.ROCKBOX b/rbutil/rbutilqt/mspack/README.ROCKBOX
new file mode 100644
index 0000000000..db5ba7f482
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/README.ROCKBOX
@@ -0,0 +1,6 @@
1This folder contains the mspack project for MS files compression/decompression.
2These files are distributed under the LGPL.
3The source files have been last synced with libmspack-0.3alpha
4http://sourceforge.net/projects/libmspack/on January 28, 2013
5
6
diff --git a/rbutil/rbutilqt/mspack/cab.h b/rbutil/rbutilqt/mspack/cab.h
new file mode 100644
index 0000000000..9f449d1f29
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/cab.h
@@ -0,0 +1,127 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_CAB_H
11#define MSPACK_CAB_H 1
12
13#include <mszip.h>
14#include <qtm.h>
15#include <lzx.h>
16
17/* generic CAB definitions */
18
19/* structure offsets */
20#define cfhead_Signature (0x00)
21#define cfhead_CabinetSize (0x08)
22#define cfhead_FileOffset (0x10)
23#define cfhead_MinorVersion (0x18)
24#define cfhead_MajorVersion (0x19)
25#define cfhead_NumFolders (0x1A)
26#define cfhead_NumFiles (0x1C)
27#define cfhead_Flags (0x1E)
28#define cfhead_SetID (0x20)
29#define cfhead_CabinetIndex (0x22)
30#define cfhead_SIZEOF (0x24)
31#define cfheadext_HeaderReserved (0x00)
32#define cfheadext_FolderReserved (0x02)
33#define cfheadext_DataReserved (0x03)
34#define cfheadext_SIZEOF (0x04)
35#define cffold_DataOffset (0x00)
36#define cffold_NumBlocks (0x04)
37#define cffold_CompType (0x06)
38#define cffold_SIZEOF (0x08)
39#define cffile_UncompressedSize (0x00)
40#define cffile_FolderOffset (0x04)
41#define cffile_FolderIndex (0x08)
42#define cffile_Date (0x0A)
43#define cffile_Time (0x0C)
44#define cffile_Attribs (0x0E)
45#define cffile_SIZEOF (0x10)
46#define cfdata_CheckSum (0x00)
47#define cfdata_CompressedSize (0x04)
48#define cfdata_UncompressedSize (0x06)
49#define cfdata_SIZEOF (0x08)
50
51/* flags */
52#define cffoldCOMPTYPE_MASK (0x000f)
53#define cffoldCOMPTYPE_NONE (0x0000)
54#define cffoldCOMPTYPE_MSZIP (0x0001)
55#define cffoldCOMPTYPE_QUANTUM (0x0002)
56#define cffoldCOMPTYPE_LZX (0x0003)
57#define cfheadPREV_CABINET (0x0001)
58#define cfheadNEXT_CABINET (0x0002)
59#define cfheadRESERVE_PRESENT (0x0004)
60#define cffileCONTINUED_FROM_PREV (0xFFFD)
61#define cffileCONTINUED_TO_NEXT (0xFFFE)
62#define cffileCONTINUED_PREV_AND_NEXT (0xFFFF)
63
64/* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed
65 * blocks have zero growth. MSZIP guarantees that it won't grow above
66 * uncompressed size by more than 12 bytes. LZX guarantees it won't grow
67 * more than 6144 bytes. Quantum has no documentation, but the largest
68 * block seen in the wild is 337 bytes above uncompressed size.
69 */
70#define CAB_BLOCKMAX (32768)
71#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
72
73/* CAB compression definitions */
74
75struct mscab_compressor_p {
76 struct mscab_compressor base;
77 struct mspack_system *system;
78 /* todo */
79};
80
81/* CAB decompression definitions */
82
83struct mscabd_decompress_state {
84 struct mscabd_folder_p *folder; /* current folder we're extracting from */
85 struct mscabd_folder_data *data; /* current folder split we're in */
86 unsigned int offset; /* uncompressed offset within folder */
87 unsigned int block; /* which block are we decompressing? */
88 struct mspack_system sys; /* special I/O code for decompressor */
89 int comp_type; /* type of compression used by folder */
90 int (*decompress)(void *, off_t); /* decompressor code */
91 void *state; /* decompressor state */
92 struct mscabd_cabinet_p *incab; /* cabinet where input data comes from */
93 struct mspack_file *infh; /* input file handle */
94 struct mspack_file *outfh; /* output file handle */
95 unsigned char *i_ptr, *i_end; /* input data consumed, end */
96 unsigned char input[CAB_INPUTMAX]; /* one input block of data */
97};
98
99struct mscab_decompressor_p {
100 struct mscab_decompressor base;
101 struct mscabd_decompress_state *d;
102 struct mspack_system *system;
103 int param[3]; /* !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! */
104 int error, read_error;
105};
106
107struct mscabd_cabinet_p {
108 struct mscabd_cabinet base;
109 off_t blocks_off; /* offset to data blocks */
110 int block_resv; /* reserved space in data blocks */
111};
112
113/* there is one of these for every cabinet a folder spans */
114struct mscabd_folder_data {
115 struct mscabd_folder_data *next;
116 struct mscabd_cabinet_p *cab; /* cabinet file of this folder span */
117 off_t offset; /* cabinet offset of first datablock */
118};
119
120struct mscabd_folder_p {
121 struct mscabd_folder base;
122 struct mscabd_folder_data data; /* where are the data blocks? */
123 struct mscabd_file *merge_prev; /* first file needing backwards merge */
124 struct mscabd_file *merge_next; /* first file needing forwards merge */
125};
126
127#endif
diff --git a/rbutil/rbutilqt/mspack/cabc.c b/rbutil/rbutilqt/mspack/cabc.c
new file mode 100644
index 0000000000..242e0347c3
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/cabc.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* CAB compression implementation */
11
12#include <system.h>
13#include <cab.h>
14
15struct mscab_compressor *
16 mspack_create_cab_compressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_cab_compressor(struct mscab_compressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/cabd.c b/rbutil/rbutilqt/mspack/cabd.c
new file mode 100644
index 0000000000..24ff2031f3
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/cabd.c
@@ -0,0 +1,1444 @@
1/* This file is part of libmspack.
2 * (C) 2003-2011 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* Cabinet (.CAB) files are a form of file archive. Each cabinet contains
11 * "folders", which are compressed spans of data. Each cabinet has
12 * "files", whose metadata is in the cabinet header, but whose actual data
13 * is stored compressed in one of the "folders". Cabinets can span more
14 * than one physical file on disk, in which case they are a "cabinet set",
15 * and usually the last folder of each cabinet extends into the next
16 * cabinet.
17 *
18 * For a complete description of the format, see the MSDN site:
19 * http://msdn.microsoft.com/en-us/library/bb267310.aspx
20 */
21
22/* CAB decompression implementation */
23
24#include <system.h>
25#include <cab.h>
26#include <assert.h>
27
28/* Notes on compliance with cabinet specification:
29 *
30 * One of the main changes between cabextract 0.6 and libmspack's cab
31 * decompressor is the move from block-oriented decompression to
32 * stream-oriented decompression.
33 *
34 * cabextract would read one data block from disk, decompress it with the
35 * appropriate method, then write the decompressed data. The CAB
36 * specification is specifically designed to work like this, as it ensures
37 * compression matches do not span the maximum decompressed block size
38 * limit of 32kb.
39 *
40 * However, the compression algorithms used are stream oriented, with
41 * specific hacks added to them to enforce the "individual 32kb blocks"
42 * rule in CABs. In other file formats, they do not have this limitation.
43 *
44 * In order to make more generalised decompressors, libmspack's CAB
45 * decompressor has moved from being block-oriented to more stream
46 * oriented. This also makes decompression slightly faster.
47 *
48 * However, this leads to incompliance with the CAB specification. The
49 * CAB controller can no longer ensure each block of input given to the
50 * decompressors is matched with their output. The "decompressed size" of
51 * each individual block is thrown away.
52 *
53 * Each CAB block is supposed to be seen as individually compressed. This
54 * means each consecutive data block can have completely different
55 * "uncompressed" sizes, ranging from 1 to 32768 bytes. However, in
56 * reality, all data blocks in a folder decompress to exactly 32768 bytes,
57 * excepting the final block.
58 *
59 * Given this situation, the decompression algorithms are designed to
60 * realign their input bitstreams on 32768 output-byte boundaries, and
61 * various other special cases have been made. libmspack will not
62 * correctly decompress LZX or Quantum compressed folders where the blocks
63 * do not follow this "32768 bytes until last block" pattern. It could be
64 * implemented if needed, but hopefully this is not necessary -- it has
65 * not been seen in over 3Gb of CAB archives.
66 */
67
68/* prototypes */
69static struct mscabd_cabinet * cabd_open(
70 struct mscab_decompressor *base, const char *filename);
71static void cabd_close(
72 struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
73static int cabd_read_headers(
74 struct mspack_system *sys, struct mspack_file *fh,
75 struct mscabd_cabinet_p *cab, off_t offset, int quiet);
76static char *cabd_read_string(
77 struct mspack_system *sys, struct mspack_file *fh,
78 struct mscabd_cabinet_p *cab, int *error);
79
80static struct mscabd_cabinet *cabd_search(
81 struct mscab_decompressor *base, const char *filename);
82static int cabd_find(
83 struct mscab_decompressor_p *self, unsigned char *buf,
84 struct mspack_file *fh, const char *filename, off_t flen,
85 off_t *firstlen, struct mscabd_cabinet_p **firstcab);
86
87static int cabd_prepend(
88 struct mscab_decompressor *base, struct mscabd_cabinet *cab,
89 struct mscabd_cabinet *prevcab);
90static int cabd_append(
91 struct mscab_decompressor *base, struct mscabd_cabinet *cab,
92 struct mscabd_cabinet *nextcab);
93static int cabd_merge(
94 struct mscab_decompressor *base, struct mscabd_cabinet *lcab,
95 struct mscabd_cabinet *rcab);
96static int cabd_can_merge_folders(
97 struct mspack_system *sys, struct mscabd_folder_p *lfol,
98 struct mscabd_folder_p *rfol);
99
100static int cabd_extract(
101 struct mscab_decompressor *base, struct mscabd_file *file,
102 const char *filename);
103static int cabd_init_decomp(
104 struct mscab_decompressor_p *self, unsigned int ct);
105static void cabd_free_decomp(
106 struct mscab_decompressor_p *self);
107static int cabd_sys_read(
108 struct mspack_file *file, void *buffer, int bytes);
109static int cabd_sys_write(
110 struct mspack_file *file, void *buffer, int bytes);
111static int cabd_sys_read_block(
112 struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
113 int ignore_cksum);
114static unsigned int cabd_checksum(
115 unsigned char *data, unsigned int bytes, unsigned int cksum);
116static struct noned_state *noned_init(
117 struct mspack_system *sys, struct mspack_file *in, struct mspack_file *out,
118 int bufsize);
119
120static int noned_decompress(
121 struct noned_state *s, off_t bytes);
122static void noned_free(
123 struct noned_state *state);
124
125static int cabd_param(
126 struct mscab_decompressor *base, int param, int value);
127
128static int cabd_error(
129 struct mscab_decompressor *base);
130
131
132/***************************************
133 * MSPACK_CREATE_CAB_DECOMPRESSOR
134 ***************************************
135 * constructor
136 */
137struct mscab_decompressor *
138 mspack_create_cab_decompressor(struct mspack_system *sys)
139{
140 struct mscab_decompressor_p *self = NULL;
141
142 if (!sys) sys = mspack_default_system;
143 if (!mspack_valid_system(sys)) return NULL;
144
145 if ((self = (struct mscab_decompressor_p *) sys->alloc(sys, sizeof(struct mscab_decompressor_p)))) {
146 self->base.open = &cabd_open;
147 self->base.close = &cabd_close;
148 self->base.search = &cabd_search;
149 self->base.extract = &cabd_extract;
150 self->base.prepend = &cabd_prepend;
151 self->base.append = &cabd_append;
152 self->base.set_param = &cabd_param;
153 self->base.last_error = &cabd_error;
154 self->system = sys;
155 self->d = NULL;
156 self->error = MSPACK_ERR_OK;
157
158 self->param[MSCABD_PARAM_SEARCHBUF] = 32768;
159 self->param[MSCABD_PARAM_FIXMSZIP] = 0;
160 self->param[MSCABD_PARAM_DECOMPBUF] = 4096;
161 }
162 return (struct mscab_decompressor *) self;
163}
164
165/***************************************
166 * MSPACK_DESTROY_CAB_DECOMPRESSOR
167 ***************************************
168 * destructor
169 */
170void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
171 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
172 if (self) {
173 struct mspack_system *sys = self->system;
174 cabd_free_decomp(self);
175 if (self->d) {
176 if (self->d->infh) sys->close(self->d->infh);
177 sys->free(self->d);
178 }
179 sys->free(self);
180 }
181}
182
183
184/***************************************
185 * CABD_OPEN
186 ***************************************
187 * opens a file and tries to read it as a cabinet file
188 */
189static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
190 const char *filename)
191{
192 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
193 struct mscabd_cabinet_p *cab = NULL;
194 struct mspack_system *sys;
195 struct mspack_file *fh;
196 int error;
197
198 if (!base) return NULL;
199 sys = self->system;
200
201 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
202 if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
203 cab->base.filename = filename;
204 error = cabd_read_headers(sys, fh, cab, (off_t) 0, 0);
205 if (error) {
206 cabd_close(base, (struct mscabd_cabinet *) cab);
207 cab = NULL;
208 }
209 self->error = error;
210 }
211 else {
212 self->error = MSPACK_ERR_NOMEMORY;
213 }
214 sys->close(fh);
215 }
216 else {
217 self->error = MSPACK_ERR_OPEN;
218 }
219 return (struct mscabd_cabinet *) cab;
220}
221
222/***************************************
223 * CABD_CLOSE
224 ***************************************
225 * frees all memory associated with a given mscabd_cabinet.
226 */
227static void cabd_close(struct mscab_decompressor *base,
228 struct mscabd_cabinet *origcab)
229{
230 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
231 struct mscabd_folder_data *dat, *ndat;
232 struct mscabd_cabinet *cab, *ncab;
233 struct mscabd_folder *fol, *nfol;
234 struct mscabd_file *fi, *nfi;
235 struct mspack_system *sys;
236
237 if (!base) return;
238 sys = self->system;
239
240 self->error = MSPACK_ERR_OK;
241
242 while (origcab) {
243 /* free files */
244 for (fi = origcab->files; fi; fi = nfi) {
245 nfi = fi->next;
246 sys->free(fi->filename);
247 sys->free(fi);
248 }
249
250 /* free folders */
251 for (fol = origcab->folders; fol; fol = nfol) {
252 nfol = fol->next;
253
254 /* free folder decompression state if it has been decompressed */
255 if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
256 if (self->d->infh) sys->close(self->d->infh);
257 cabd_free_decomp(self);
258 sys->free(self->d);
259 self->d = NULL;
260 }
261
262 /* free folder data segments */
263 for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
264 ndat = dat->next;
265 sys->free(dat);
266 }
267 sys->free(fol);
268 }
269
270 /* free predecessor cabinets (and the original cabinet's strings) */
271 for (cab = origcab; cab; cab = ncab) {
272 ncab = cab->prevcab;
273 sys->free(cab->prevname);
274 sys->free(cab->nextname);
275 sys->free(cab->previnfo);
276 sys->free(cab->nextinfo);
277 if (cab != origcab) sys->free(cab);
278 }
279
280 /* free successor cabinets */
281 for (cab = origcab->nextcab; cab; cab = ncab) {
282 ncab = cab->nextcab;
283 sys->free(cab->prevname);
284 sys->free(cab->nextname);
285 sys->free(cab->previnfo);
286 sys->free(cab->nextinfo);
287 sys->free(cab);
288 }
289
290 /* free actual cabinet structure */
291 cab = origcab->next;
292 sys->free(origcab);
293
294 /* repeat full procedure again with the cab->next pointer (if set) */
295 origcab = cab;
296 }
297}
298
299/***************************************
300 * CABD_READ_HEADERS
301 ***************************************
302 * reads the cabinet file header, folder list and file list.
303 * fills out a pre-existing mscabd_cabinet structure, allocates memory
304 * for folders and files as necessary
305 */
306static int cabd_read_headers(struct mspack_system *sys,
307 struct mspack_file *fh,
308 struct mscabd_cabinet_p *cab,
309 off_t offset, int quiet)
310{
311 int num_folders, num_files, folder_resv, i, x;
312 struct mscabd_folder_p *fol, *linkfol = NULL;
313 struct mscabd_file *file, *linkfile = NULL;
314 unsigned char buf[64];
315
316 /* initialise pointers */
317 cab->base.next = NULL;
318 cab->base.files = NULL;
319 cab->base.folders = NULL;
320 cab->base.prevcab = cab->base.nextcab = NULL;
321 cab->base.prevname = cab->base.nextname = NULL;
322 cab->base.previnfo = cab->base.nextinfo = NULL;
323
324 cab->base.base_offset = offset;
325
326 /* seek to CFHEADER */
327 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
328 return MSPACK_ERR_SEEK;
329 }
330
331 /* read in the CFHEADER */
332 if (sys->read(fh, &buf[0], cfhead_SIZEOF) != cfhead_SIZEOF) {
333 return MSPACK_ERR_READ;
334 }
335
336 /* check for "MSCF" signature */
337 if (EndGetI32(&buf[cfhead_Signature]) != 0x4643534D) {
338 return MSPACK_ERR_SIGNATURE;
339 }
340
341 /* some basic header fields */
342 cab->base.length = EndGetI32(&buf[cfhead_CabinetSize]);
343 cab->base.set_id = EndGetI16(&buf[cfhead_SetID]);
344 cab->base.set_index = EndGetI16(&buf[cfhead_CabinetIndex]);
345
346 /* get the number of folders */
347 num_folders = EndGetI16(&buf[cfhead_NumFolders]);
348 if (num_folders == 0) {
349 if (!quiet) sys->message(fh, "no folders in cabinet.");
350 return MSPACK_ERR_DATAFORMAT;
351 }
352
353 /* get the number of files */
354 num_files = EndGetI16(&buf[cfhead_NumFiles]);
355 if (num_files == 0) {
356 if (!quiet) sys->message(fh, "no files in cabinet.");
357 return MSPACK_ERR_DATAFORMAT;
358 }
359
360 /* check cabinet version */
361 if ((buf[cfhead_MajorVersion] != 1) && (buf[cfhead_MinorVersion] != 3)) {
362 if (!quiet) sys->message(fh, "WARNING; cabinet version is not 1.3");
363 }
364
365 /* read the reserved-sizes part of header, if present */
366 cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
367 if (cab->base.flags & cfheadRESERVE_PRESENT) {
368 if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
369 return MSPACK_ERR_READ;
370 }
371 cab->base.header_resv = EndGetI16(&buf[cfheadext_HeaderReserved]);
372 folder_resv = buf[cfheadext_FolderReserved];
373 cab->block_resv = buf[cfheadext_DataReserved];
374
375 if (cab->base.header_resv > 60000) {
376 if (!quiet) sys->message(fh, "WARNING; reserved header > 60000.");
377 }
378
379 /* skip the reserved header */
380 if (cab->base.header_resv) {
381 if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
382 return MSPACK_ERR_SEEK;
383 }
384 }
385 }
386 else {
387 cab->base.header_resv = 0;
388 folder_resv = 0;
389 cab->block_resv = 0;
390 }
391
392 /* read name and info of preceeding cabinet in set, if present */
393 if (cab->base.flags & cfheadPREV_CABINET) {
394 cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x;
395 cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
396 }
397
398 /* read name and info of next cabinet in set, if present */
399 if (cab->base.flags & cfheadNEXT_CABINET) {
400 cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x;
401 cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
402 }
403
404 /* read folders */
405 for (i = 0; i < num_folders; i++) {
406 if (sys->read(fh, &buf[0], cffold_SIZEOF) != cffold_SIZEOF) {
407 return MSPACK_ERR_READ;
408 }
409 if (folder_resv) {
410 if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
411 return MSPACK_ERR_SEEK;
412 }
413 }
414
415 if (!(fol = (struct mscabd_folder_p *) sys->alloc(sys, sizeof(struct mscabd_folder_p)))) {
416 return MSPACK_ERR_NOMEMORY;
417 }
418 fol->base.next = NULL;
419 fol->base.comp_type = EndGetI16(&buf[cffold_CompType]);
420 fol->base.num_blocks = EndGetI16(&buf[cffold_NumBlocks]);
421 fol->data.next = NULL;
422 fol->data.cab = (struct mscabd_cabinet_p *) cab;
423 fol->data.offset = offset + (off_t)
424 ( (unsigned int) EndGetI32(&buf[cffold_DataOffset]) );
425 fol->merge_prev = NULL;
426 fol->merge_next = NULL;
427
428 /* link folder into list of folders */
429 if (!linkfol) cab->base.folders = (struct mscabd_folder *) fol;
430 else linkfol->base.next = (struct mscabd_folder *) fol;
431 linkfol = fol;
432 }
433
434 /* read files */
435 for (i = 0; i < num_files; i++) {
436 if (sys->read(fh, &buf[0], cffile_SIZEOF) != cffile_SIZEOF) {
437 return MSPACK_ERR_READ;
438 }
439
440 if (!(file = (struct mscabd_file *) sys->alloc(sys, sizeof(struct mscabd_file)))) {
441 return MSPACK_ERR_NOMEMORY;
442 }
443
444 file->next = NULL;
445 file->length = EndGetI32(&buf[cffile_UncompressedSize]);
446 file->attribs = EndGetI16(&buf[cffile_Attribs]);
447 file->offset = EndGetI32(&buf[cffile_FolderOffset]);
448
449 /* set folder pointer */
450 x = EndGetI16(&buf[cffile_FolderIndex]);
451 if (x < cffileCONTINUED_FROM_PREV) {
452 /* normal folder index; count up to the correct folder. the folder
453 * pointer will be NULL if folder index is invalid */
454 struct mscabd_folder *ifol = cab->base.folders;
455 while (x--) if (ifol) ifol = ifol->next;
456 file->folder = ifol;
457
458 if (!ifol) {
459 sys->free(file);
460 D(("invalid folder index"))
461 return MSPACK_ERR_DATAFORMAT;
462 }
463 }
464 else {
465 /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
466 * CONTINUED_PREV_AND_NEXT */
467 if ((x == cffileCONTINUED_TO_NEXT) ||
468 (x == cffileCONTINUED_PREV_AND_NEXT))
469 {
470 /* get last folder */
471 struct mscabd_folder *ifol = cab->base.folders;
472 while (ifol->next) ifol = ifol->next;
473 file->folder = ifol;
474
475 /* set "merge next" pointer */
476 fol = (struct mscabd_folder_p *) ifol;
477 if (!fol->merge_next) fol->merge_next = file;
478 }
479
480 if ((x == cffileCONTINUED_FROM_PREV) ||
481 (x == cffileCONTINUED_PREV_AND_NEXT))
482 {
483 /* get first folder */
484 file->folder = cab->base.folders;
485
486 /* set "merge prev" pointer */
487 fol = (struct mscabd_folder_p *) file->folder;
488 if (!fol->merge_prev) fol->merge_prev = file;
489 }
490 }
491
492 /* get time */
493 x = EndGetI16(&buf[cffile_Time]);
494 file->time_h = x >> 11;
495 file->time_m = (x >> 5) & 0x3F;
496 file->time_s = (x << 1) & 0x3E;
497
498 /* get date */
499 x = EndGetI16(&buf[cffile_Date]);
500 file->date_d = x & 0x1F;
501 file->date_m = (x >> 5) & 0xF;
502 file->date_y = (x >> 9) + 1980;
503
504 /* get filename */
505 file->filename = cabd_read_string(sys, fh, cab, &x);
506 if (x) {
507 sys->free(file);
508 return x;
509 }
510
511 /* link file entry into file list */
512 if (!linkfile) cab->base.files = file;
513 else linkfile->next = file;
514 linkfile = file;
515 }
516
517 return MSPACK_ERR_OK;
518}
519
520static char *cabd_read_string(struct mspack_system *sys,
521 struct mspack_file *fh,
522 struct mscabd_cabinet_p *cab, int *error)
523{
524 off_t base = sys->tell(fh);
525 char buf[256], *str;
526 unsigned int len, i, ok;
527
528 /* read up to 256 bytes */
529 len = sys->read(fh, &buf[0], 256);
530
531 /* search for a null terminator in the buffer */
532 for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
533 if (!ok) {
534 *error = MSPACK_ERR_DATAFORMAT;
535 return NULL;
536 }
537
538 len = i + 1;
539
540 /* set the data stream to just after the string and return */
541 if (sys->seek(fh, base + (off_t)len, MSPACK_SYS_SEEK_START)) {
542 *error = MSPACK_ERR_SEEK;
543 return NULL;
544 }
545
546 if (!(str = (char *) sys->alloc(sys, len))) {
547 *error = MSPACK_ERR_NOMEMORY;
548 return NULL;
549 }
550
551 sys->copy(&buf[0], str, len);
552 *error = MSPACK_ERR_OK;
553 return str;
554}
555
556/***************************************
557 * CABD_SEARCH, CABD_FIND
558 ***************************************
559 * cabd_search opens a file, finds its extent, allocates a search buffer,
560 * then reads through the whole file looking for possible cabinet headers.
561 * if it finds any, it tries to read them as real cabinets. returns a linked
562 * list of results
563 *
564 * cabd_find is the inner loop of cabd_search, to make it easier to
565 * break out of the loop and be sure that all resources are freed
566 */
567static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
568 const char *filename)
569{
570 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
571 struct mscabd_cabinet_p *cab = NULL;
572 struct mspack_system *sys;
573 unsigned char *search_buf;
574 struct mspack_file *fh;
575 off_t filelen, firstlen = 0;
576
577 if (!base) return NULL;
578 sys = self->system;
579
580 /* allocate a search buffer */
581 search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->param[MSCABD_PARAM_SEARCHBUF]);
582 if (!search_buf) {
583 self->error = MSPACK_ERR_NOMEMORY;
584 return NULL;
585 }
586
587 /* open file and get its full file length */
588 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
589 if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
590 self->error = cabd_find(self, search_buf, fh, filename,
591 filelen, &firstlen, &cab);
592 }
593
594 /* truncated / extraneous data warning: */
595 if (firstlen && (firstlen != filelen) &&
596 (!cab || (cab->base.base_offset == 0)))
597 {
598 if (firstlen < filelen) {
599 sys->message(fh, "WARNING; possible %" LD
600 " extra bytes at end of file.",
601 filelen - firstlen);
602 }
603 else {
604 sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
605 firstlen - filelen);
606 }
607 }
608
609 sys->close(fh);
610 }
611 else {
612 self->error = MSPACK_ERR_OPEN;
613 }
614
615 /* free the search buffer */
616 sys->free(search_buf);
617
618 return (struct mscabd_cabinet *) cab;
619}
620
621static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
622 struct mspack_file *fh, const char *filename, off_t flen,
623 off_t *firstlen, struct mscabd_cabinet_p **firstcab)
624{
625 struct mscabd_cabinet_p *cab, *link = NULL;
626 off_t caboff, offset, length;
627 struct mspack_system *sys = self->system;
628 unsigned char *p, *pend, state = 0;
629 unsigned int cablen_u32 = 0, foffset_u32 = 0;
630 int false_cabs = 0;
631
632#ifndef LARGEFILE_SUPPORT
633 /* detect 32-bit off_t overflow */
634 if (flen < 0) {
635 sys->message(fh, largefile_msg);
636 return MSPACK_ERR_OK;
637 }
638#endif
639
640 /* search through the full file length */
641 for (offset = 0; offset < flen; offset += length) {
642 /* search length is either the full length of the search buffer, or the
643 * amount of data remaining to the end of the file, whichever is less. */
644 length = flen - offset;
645 if (length > self->param[MSCABD_PARAM_SEARCHBUF]) {
646 length = self->param[MSCABD_PARAM_SEARCHBUF];
647 }
648
649 /* fill the search buffer with data from disk */
650 if (sys->read(fh, &buf[0], (int) length) != (int) length) {
651 return MSPACK_ERR_READ;
652 }
653
654 /* FAQ avoidance strategy */
655 if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
656 sys->message(fh, "WARNING; found InstallShield header. "
657 "This is probably an InstallShield file. "
658 "Use UNSHIELD from www.synce.org to unpack it.");
659 }
660
661 /* read through the entire buffer. */
662 for (p = &buf[0], pend = &buf[length]; p < pend; ) {
663 switch (state) {
664 /* starting state */
665 case 0:
666 /* we spend most of our time in this while loop, looking for
667 * a leading 'M' of the 'MSCF' signature */
668 while (p < pend && *p != 0x4D) p++;
669 /* if we found tht 'M', advance state */
670 if (p++ < pend) state = 1;
671 break;
672
673 /* verify that the next 3 bytes are 'S', 'C' and 'F' */
674 case 1: state = (*p++ == 0x53) ? 2 : 0; break;
675 case 2: state = (*p++ == 0x43) ? 3 : 0; break;
676 case 3: state = (*p++ == 0x46) ? 4 : 0; break;
677
678 /* we don't care about bytes 4-7 (see default: for action) */
679
680 /* bytes 8-11 are the overall length of the cabinet */
681 case 8: cablen_u32 = *p++; state++; break;
682 case 9: cablen_u32 |= *p++ << 8; state++; break;
683 case 10: cablen_u32 |= *p++ << 16; state++; break;
684 case 11: cablen_u32 |= *p++ << 24; state++; break;
685
686 /* we don't care about bytes 12-15 (see default: for action) */
687
688 /* bytes 16-19 are the offset within the cabinet of the filedata */
689 case 16: foffset_u32 = *p++; state++; break;
690 case 17: foffset_u32 |= *p++ << 8; state++; break;
691 case 18: foffset_u32 |= *p++ << 16; state++; break;
692 case 19: foffset_u32 |= *p++ << 24;
693 /* now we have recieved 20 bytes of potential cab header. work out
694 * the offset in the file of this potential cabinet */
695 caboff = offset + (p - &buf[0]) - 20;
696
697 /* should reading cabinet fail, restart search just after 'MSCF' */
698 offset = caboff + 4;
699
700 /* capture the "length of cabinet" field if there is a cabinet at
701 * offset 0 in the file, regardless of whether the cabinet can be
702 * read correctly or not */
703 if (caboff == 0) *firstlen = (off_t) cablen_u32;
704
705 /* check that the files offset is less than the alleged length of
706 * the cabinet, and that the offset + the alleged length are
707 * 'roughly' within the end of overall file length */
708 if ((foffset_u32 < cablen_u32) &&
709 ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
710 ((caboff + (off_t) cablen_u32) < (flen + 32)) )
711 {
712 /* likely cabinet found -- try reading it */
713 if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
714 return MSPACK_ERR_NOMEMORY;
715 }
716 cab->base.filename = filename;
717 if (cabd_read_headers(sys, fh, cab, caboff, 1)) {
718 /* destroy the failed cabinet */
719 cabd_close((struct mscab_decompressor *) self,
720 (struct mscabd_cabinet *) cab);
721 false_cabs++;
722 }
723 else {
724 /* cabinet read correctly! */
725
726 /* link the cab into the list */
727 if (!link) *firstcab = cab;
728 else link->base.next = (struct mscabd_cabinet *) cab;
729 link = cab;
730
731 /* cause the search to restart after this cab's data. */
732 offset = caboff + (off_t) cablen_u32;
733
734#ifndef LARGEFILE_SUPPORT
735 /* detect 32-bit off_t overflow */
736 if (offset < caboff) {
737 sys->message(fh, largefile_msg);
738 return MSPACK_ERR_OK;
739 }
740#endif
741 }
742 }
743
744 /* restart search */
745 if (offset >= flen) return MSPACK_ERR_OK;
746 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
747 return MSPACK_ERR_SEEK;
748 }
749 length = 0;
750 p = pend;
751 state = 0;
752 break;
753
754 /* for bytes 4-7 and 12-15, just advance state/pointer */
755 default:
756 p++, state++;
757 } /* switch(state) */
758 } /* for (... p < pend ...) */
759 } /* for (... offset < length ...) */
760
761 if (false_cabs) {
762 D(("%d false cabinets found", false_cabs))
763 }
764
765 return MSPACK_ERR_OK;
766}
767
768/***************************************
769 * CABD_MERGE, CABD_PREPEND, CABD_APPEND
770 ***************************************
771 * joins cabinets together, also merges split folders between these two
772 * cabinets only. This includes freeing the duplicate folder and file(s)
773 * and allocating a further mscabd_folder_data structure to append to the
774 * merged folder's data parts list.
775 */
776static int cabd_prepend(struct mscab_decompressor *base,
777 struct mscabd_cabinet *cab,
778 struct mscabd_cabinet *prevcab)
779{
780 return cabd_merge(base, prevcab, cab);
781}
782
783static int cabd_append(struct mscab_decompressor *base,
784 struct mscabd_cabinet *cab,
785 struct mscabd_cabinet *nextcab)
786{
787 return cabd_merge(base, cab, nextcab);
788}
789
790static int cabd_merge(struct mscab_decompressor *base,
791 struct mscabd_cabinet *lcab,
792 struct mscabd_cabinet *rcab)
793{
794 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
795 struct mscabd_folder_data *data, *ndata;
796 struct mscabd_folder_p *lfol, *rfol;
797 struct mscabd_file *fi, *rfi, *lfi;
798 struct mscabd_cabinet *cab;
799 struct mspack_system *sys;
800
801 if (!self) return MSPACK_ERR_ARGS;
802 sys = self->system;
803
804 /* basic args check */
805 if (!lcab || !rcab || (lcab == rcab)) {
806 D(("lcab NULL, rcab NULL or lcab = rcab"))
807 return self->error = MSPACK_ERR_ARGS;
808 }
809
810 /* check there's not already a cabinet attached */
811 if (lcab->nextcab || rcab->prevcab) {
812 D(("cabs already joined"))
813 return self->error = MSPACK_ERR_ARGS;
814 }
815
816 /* do not create circular cabinet chains */
817 for (cab = lcab->prevcab; cab; cab = cab->prevcab) {
818 if (cab == rcab) {D(("circular!")) return self->error = MSPACK_ERR_ARGS;}
819 }
820 for (cab = rcab->nextcab; cab; cab = cab->nextcab) {
821 if (cab == lcab) {D(("circular!")) return self->error = MSPACK_ERR_ARGS;}
822 }
823
824 /* warn about odd set IDs or indices */
825 if (lcab->set_id != rcab->set_id) {
826 sys->message(NULL, "WARNING; merged cabinets with differing Set IDs.");
827 }
828
829 if (lcab->set_index > rcab->set_index) {
830 sys->message(NULL, "WARNING; merged cabinets with odd order.");
831 }
832
833 /* merging the last folder in lcab with the first folder in rcab */
834 lfol = (struct mscabd_folder_p *) lcab->folders;
835 rfol = (struct mscabd_folder_p *) rcab->folders;
836 while (lfol->base.next) lfol = (struct mscabd_folder_p *) lfol->base.next;
837
838 /* do we need to merge folders? */
839 if (!lfol->merge_next && !rfol->merge_prev) {
840 /* no, at least one of the folders is not for merging */
841
842 /* attach cabs */
843 lcab->nextcab = rcab;
844 rcab->prevcab = lcab;
845
846 /* attach folders */
847 lfol->base.next = (struct mscabd_folder *) rfol;
848
849 /* attach files */
850 fi = lcab->files;
851 while (fi->next) fi = fi->next;
852 fi->next = rcab->files;
853 }
854 else {
855 /* folder merge required - do the files match? */
856 if (! cabd_can_merge_folders(sys, lfol, rfol)) {
857 return self->error = MSPACK_ERR_DATAFORMAT;
858 }
859
860 /* allocate a new folder data structure */
861 if (!(data = (struct mscabd_folder_data *) sys->alloc(sys, sizeof(struct mscabd_folder_data)))) {
862 return self->error = MSPACK_ERR_NOMEMORY;
863 }
864
865 /* attach cabs */
866 lcab->nextcab = rcab;
867 rcab->prevcab = lcab;
868
869 /* append rfol's data to lfol */
870 ndata = &lfol->data;
871 while (ndata->next) ndata = ndata->next;
872 ndata->next = data;
873 *data = rfol->data;
874 rfol->data.next = NULL;
875
876 /* lfol becomes rfol.
877 * NOTE: special case, don't merge if rfol is merge prev and next,
878 * rfol->merge_next is going to be deleted, so keep lfol's version
879 * instead */
880 lfol->base.num_blocks += rfol->base.num_blocks - 1;
881 if ((rfol->merge_next == NULL) ||
882 (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
883 {
884 lfol->merge_next = rfol->merge_next;
885 }
886
887 /* attach the rfol's folder (except the merge folder) */
888 while (lfol->base.next) lfol = (struct mscabd_folder_p *) lfol->base.next;
889 lfol->base.next = rfol->base.next;
890
891 /* free disused merge folder */
892 sys->free(rfol);
893
894 /* attach rfol's files */
895 fi = lcab->files;
896 while (fi->next) fi = fi->next;
897 fi->next = rcab->files;
898
899 /* delete all files from rfol's merge folder */
900 lfi = NULL;
901 for (fi = lcab->files; fi ; fi = rfi) {
902 rfi = fi->next;
903 /* if file's folder matches the merge folder, unlink and free it */
904 if (fi->folder == (struct mscabd_folder *) rfol) {
905 if (lfi) lfi->next = rfi; else lcab->files = rfi;
906 sys->free(fi->filename);
907 sys->free(fi);
908 }
909 else lfi = fi;
910 }
911 }
912
913 /* all done! fix files and folders pointers in all cabs so they all
914 * point to the same list */
915 for (cab = lcab->prevcab; cab; cab = cab->prevcab) {
916 cab->files = lcab->files;
917 cab->folders = lcab->folders;
918 }
919
920 for (cab = lcab->nextcab; cab; cab = cab->nextcab) {
921 cab->files = lcab->files;
922 cab->folders = lcab->folders;
923 }
924
925 return self->error = MSPACK_ERR_OK;
926}
927
928/* decides if two folders are OK to merge */
929static int cabd_can_merge_folders(struct mspack_system *sys,
930 struct mscabd_folder_p *lfol,
931 struct mscabd_folder_p *rfol)
932{
933 struct mscabd_file *lfi, *rfi, *l, *r;
934 int matching = 1;
935
936 /* check that both folders use the same compression method/settings */
937 if (lfol->base.comp_type != rfol->base.comp_type) {
938 D(("folder merge: compression type mismatch"))
939 return 0;
940 }
941
942 if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
943 D(("folder merge: one cabinet has no files to merge"))
944 return 0;
945 }
946
947 /* for all files in lfol (which is the last folder in whichever cab and
948 * only has files to merge), compare them to the files from rfol. They
949 * should be identical in number and order. to verify this, check the
950 * offset and length of each file. */
951 for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
952 if (!r || (l->offset != r->offset) || (l->length != r->length)) {
953 matching = 0;
954 break;
955 }
956 }
957
958 if (matching) return 1;
959
960 /* if rfol does not begin with an identical copy of the files in lfol, make
961 * make a judgement call; if at least ONE file from lfol is in rfol, allow
962 * the merge with a warning about missing files. */
963 matching = 0;
964 for (l = lfi; l; l = l->next) {
965 for (r = rfi; r; r = r->next) {
966 if (l->offset == r->offset && l->length == r->length) break;
967 }
968 if (r) matching = 1; else sys->message(NULL,
969 "WARNING; merged file %s not listed in both cabinets", l->filename);
970 }
971 return matching;
972}
973
974
975/***************************************
976 * CABD_EXTRACT
977 ***************************************
978 * extracts a file from a cabinet
979 */
980static int cabd_extract(struct mscab_decompressor *base,
981 struct mscabd_file *file, const char *filename)
982{
983 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
984 struct mscabd_folder_p *fol;
985 struct mspack_system *sys;
986 struct mspack_file *fh;
987
988 if (!self) return MSPACK_ERR_ARGS;
989 if (!file) return self->error = MSPACK_ERR_ARGS;
990
991 sys = self->system;
992 fol = (struct mscabd_folder_p *) file->folder;
993
994 /* check if file can be extracted */
995 if ((!fol) || (fol->merge_prev) ||
996 (((file->offset + file->length) / CAB_BLOCKMAX) > fol->base.num_blocks))
997 {
998 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
999 "cabinet set is incomplete.", file->filename);
1000 return self->error = MSPACK_ERR_DATAFORMAT;
1001 }
1002
1003 /* allocate generic decompression state */
1004 if (!self->d) {
1005 self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state));
1006 if (!self->d) return self->error = MSPACK_ERR_NOMEMORY;
1007 self->d->folder = NULL;
1008 self->d->data = NULL;
1009 self->d->sys = *sys;
1010 self->d->sys.read = &cabd_sys_read;
1011 self->d->sys.write = &cabd_sys_write;
1012 self->d->state = NULL;
1013 self->d->infh = NULL;
1014 self->d->incab = NULL;
1015 }
1016
1017 /* do we need to change folder or reset the current folder? */
1018 if ((self->d->folder != fol) || (self->d->offset > file->offset)) {
1019 /* do we need to open a new cab file? */
1020 if (!self->d->infh || (fol->data.cab != self->d->incab)) {
1021 /* close previous file handle if from a different cab */
1022 if (self->d->infh) sys->close(self->d->infh);
1023 self->d->incab = fol->data.cab;
1024 self->d->infh = sys->open(sys, fol->data.cab->base.filename,
1025 MSPACK_SYS_OPEN_READ);
1026 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
1027 }
1028 /* seek to start of data blocks */
1029 if (sys->seek(self->d->infh, fol->data.offset, MSPACK_SYS_SEEK_START)) {
1030 return self->error = MSPACK_ERR_SEEK;
1031 }
1032
1033 /* set up decompressor */
1034 if (cabd_init_decomp(self, (unsigned int) fol->base.comp_type)) {
1035 return self->error;
1036 }
1037
1038 /* initialise new folder state */
1039 self->d->folder = fol;
1040 self->d->data = &fol->data;
1041 self->d->offset = 0;
1042 self->d->block = 0;
1043 self->d->i_ptr = self->d->i_end = &self->d->input[0];
1044
1045 /* read_error lasts for the lifetime of a decompressor */
1046 self->read_error = MSPACK_ERR_OK;
1047 }
1048
1049 /* open file for output */
1050 if (!(fh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
1051 return self->error = MSPACK_ERR_OPEN;
1052 }
1053
1054 self->error = MSPACK_ERR_OK;
1055
1056 /* if file has more than 0 bytes */
1057 if (file->length) {
1058 off_t bytes;
1059 int error;
1060 /* get to correct offset.
1061 * - use NULL fh to say 'no writing' to cabd_sys_write()
1062 * - if cabd_sys_read() has an error, it will set self->read_error
1063 * and pass back MSPACK_ERR_READ
1064 */
1065 self->d->outfh = NULL;
1066 if ((bytes = file->offset - self->d->offset)) {
1067 error = self->d->decompress(self->d->state, bytes);
1068 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1069 }
1070
1071 /* if getting to the correct offset was error free, unpack file */
1072 if (!self->error) {
1073 self->d->outfh = fh;
1074 error = self->d->decompress(self->d->state, (off_t) file->length);
1075 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1076 }
1077 }
1078
1079 /* close output file */
1080 sys->close(fh);
1081 self->d->outfh = NULL;
1082
1083 return self->error;
1084}
1085
1086/***************************************
1087 * CABD_INIT_DECOMP, CABD_FREE_DECOMP
1088 ***************************************
1089 * cabd_init_decomp initialises decompression state, according to which
1090 * decompression method was used. relies on self->d->folder being the same
1091 * as when initialised.
1092 *
1093 * cabd_free_decomp frees decompression state, according to which method
1094 * was used.
1095 */
1096static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
1097{
1098 struct mspack_file *fh = (struct mspack_file *) self;
1099
1100 assert(self && self->d);
1101
1102 /* free any existing decompressor */
1103 cabd_free_decomp(self);
1104
1105 self->d->comp_type = ct;
1106
1107 switch (ct & cffoldCOMPTYPE_MASK) {
1108 case cffoldCOMPTYPE_NONE:
1109 self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
1110 self->d->state = noned_init(&self->d->sys, fh, fh,
1111 self->param[MSCABD_PARAM_DECOMPBUF]);
1112 break;
1113 case cffoldCOMPTYPE_MSZIP:
1114 self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
1115 self->d->state = mszipd_init(&self->d->sys, fh, fh,
1116 self->param[MSCABD_PARAM_DECOMPBUF],
1117 self->param[MSCABD_PARAM_FIXMSZIP]);
1118 break;
1119 case cffoldCOMPTYPE_QUANTUM:
1120 self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
1121 self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
1122 self->param[MSCABD_PARAM_DECOMPBUF]);
1123 break;
1124 case cffoldCOMPTYPE_LZX:
1125 self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
1126 self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
1127 self->param[MSCABD_PARAM_DECOMPBUF], (off_t) 0);
1128 break;
1129 default:
1130 return self->error = MSPACK_ERR_DATAFORMAT;
1131 }
1132 return self->error = (self->d->state) ? MSPACK_ERR_OK : MSPACK_ERR_NOMEMORY;
1133}
1134
1135static void cabd_free_decomp(struct mscab_decompressor_p *self) {
1136 if (!self || !self->d || !self->d->folder || !self->d->state) return;
1137
1138 switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
1139 case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break;
1140 case cffoldCOMPTYPE_MSZIP: mszipd_free((struct mszipd_stream *) self->d->state); break;
1141 case cffoldCOMPTYPE_QUANTUM: qtmd_free((struct qtmd_stream *) self->d->state); break;
1142 case cffoldCOMPTYPE_LZX: lzxd_free((struct lzxd_stream *) self->d->state); break;
1143 }
1144 self->d->decompress = NULL;
1145 self->d->state = NULL;
1146}
1147
1148/***************************************
1149 * CABD_SYS_READ, CABD_SYS_WRITE
1150 ***************************************
1151 * cabd_sys_read is the internal reader function which the decompressors
1152 * use. will read data blocks (and merge split blocks) from the cabinet
1153 * and serve the read bytes to the decompressors
1154 *
1155 * cabd_sys_write is the internal writer function which the decompressors
1156 * use. it either writes data to disk (self->d->outfh) with the real
1157 * sys->write() function, or does nothing with the data when
1158 * self->d->outfh == NULL. advances self->d->offset
1159 */
1160static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
1161 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
1162 unsigned char *buf = (unsigned char *) buffer;
1163 struct mspack_system *sys = self->system;
1164 int avail, todo, outlen, ignore_cksum;
1165
1166 ignore_cksum = self->param[MSCABD_PARAM_FIXMSZIP] &&
1167 ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP);
1168
1169 todo = bytes;
1170 while (todo > 0) {
1171 avail = self->d->i_end - self->d->i_ptr;
1172
1173 /* if out of input data, read a new block */
1174 if (avail) {
1175 /* copy as many input bytes available as possible */
1176 if (avail > todo) avail = todo;
1177 sys->copy(self->d->i_ptr, buf, (size_t) avail);
1178 self->d->i_ptr += avail;
1179 buf += avail;
1180 todo -= avail;
1181 }
1182 else {
1183 /* out of data, read a new block */
1184
1185 /* check if we're out of input blocks, advance block counter */
1186 if (self->d->block++ >= self->d->folder->base.num_blocks) {
1187 self->read_error = MSPACK_ERR_DATAFORMAT;
1188 break;
1189 }
1190
1191 /* read a block */
1192 self->read_error = cabd_sys_read_block(sys, self->d, &outlen, ignore_cksum);
1193 if (self->read_error) return -1;
1194
1195 /* special Quantum hack -- trailer byte to allow the decompressor
1196 * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
1197 * anything from 0 to 4 trailing null bytes. */
1198 if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
1199 *self->d->i_end++ = 0xFF;
1200 }
1201
1202 /* is this the last block? */
1203 if (self->d->block >= self->d->folder->base.num_blocks) {
1204 /* last block */
1205 if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
1206 /* special LZX hack -- on the last block, inform LZX of the
1207 * size of the output data stream. */
1208 lzxd_set_output_length((struct lzxd_stream *) self->d->state, (off_t)
1209 ((self->d->block-1) * CAB_BLOCKMAX + outlen));
1210 }
1211 }
1212 else {
1213 /* not the last block */
1214 if (outlen != CAB_BLOCKMAX) {
1215 self->system->message(self->d->infh,
1216 "WARNING; non-maximal data block");
1217 }
1218 }
1219 } /* if (avail) */
1220 } /* while (todo > 0) */
1221 return bytes - todo;
1222}
1223
1224static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1225 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
1226 self->d->offset += bytes;
1227 if (self->d->outfh) {
1228 return self->system->write(self->d->outfh, buffer, bytes);
1229 }
1230 return bytes;
1231}
1232
1233/***************************************
1234 * CABD_SYS_READ_BLOCK
1235 ***************************************
1236 * reads a whole data block from a cab file. the block may span more than
1237 * one cab file, if it does then the fragments will be reassembled
1238 */
1239static int cabd_sys_read_block(struct mspack_system *sys,
1240 struct mscabd_decompress_state *d,
1241 int *out, int ignore_cksum)
1242{
1243 unsigned char hdr[cfdata_SIZEOF];
1244 unsigned int cksum;
1245 int len;
1246
1247 /* reset the input block pointer and end of block pointer */
1248 d->i_ptr = d->i_end = &d->input[0];
1249
1250 do {
1251 /* read the block header */
1252 if (sys->read(d->infh, &hdr[0], cfdata_SIZEOF) != cfdata_SIZEOF) {
1253 return MSPACK_ERR_READ;
1254 }
1255
1256 /* skip any reserved block headers */
1257 if (d->data->cab->block_resv &&
1258 sys->seek(d->infh, (off_t) d->data->cab->block_resv,
1259 MSPACK_SYS_SEEK_CUR))
1260 {
1261 return MSPACK_ERR_SEEK;
1262 }
1263
1264 /* blocks must not be over CAB_INPUTMAX in size */
1265 len = EndGetI16(&hdr[cfdata_CompressedSize]);
1266 if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) {
1267 D(("block size > CAB_INPUTMAX (%ld + %d)", d->i_end - d->i_ptr, len))
1268 return MSPACK_ERR_DATAFORMAT;
1269 }
1270
1271 /* blocks must not expand to more than CAB_BLOCKMAX */
1272 if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
1273 D(("block size > CAB_BLOCKMAX"))
1274 return MSPACK_ERR_DATAFORMAT;
1275 }
1276
1277 /* read the block data */
1278 if (sys->read(d->infh, d->i_end, len) != len) {
1279 return MSPACK_ERR_READ;
1280 }
1281
1282 /* perform checksum test on the block (if one is stored) */
1283 if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
1284 unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
1285 if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
1286 if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
1287 sys->message(d->infh, "WARNING; bad block checksum found");
1288 }
1289 }
1290
1291 /* advance end of block pointer to include newly read data */
1292 d->i_end += len;
1293
1294 /* uncompressed size == 0 means this block was part of a split block
1295 * and it continues as the first block of the next cabinet in the set.
1296 * otherwise, this is the last part of the block, and no more block
1297 * reading needs to be done.
1298 */
1299 /* EXIT POINT OF LOOP -- uncompressed size != 0 */
1300 if ((*out = EndGetI16(&hdr[cfdata_UncompressedSize]))) {
1301 return MSPACK_ERR_OK;
1302 }
1303
1304 /* otherwise, advance to next cabinet */
1305
1306 /* close current file handle */
1307 sys->close(d->infh);
1308 d->infh = NULL;
1309
1310 /* advance to next member in the cabinet set */
1311 if (!(d->data = d->data->next)) {
1312 D(("ran out of splits in cabinet set"))
1313 return MSPACK_ERR_DATAFORMAT;
1314 }
1315
1316 /* open next cab file */
1317 d->incab = d->data->cab;
1318 if (!(d->infh = sys->open(sys, d->incab->base.filename,
1319 MSPACK_SYS_OPEN_READ)))
1320 {
1321 return MSPACK_ERR_OPEN;
1322 }
1323
1324 /* seek to start of data blocks */
1325 if (sys->seek(d->infh, d->data->offset, MSPACK_SYS_SEEK_START)) {
1326 return MSPACK_ERR_SEEK;
1327 }
1328 } while (1);
1329
1330 /* not reached */
1331 return MSPACK_ERR_OK;
1332}
1333
1334static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1335 unsigned int cksum)
1336{
1337 unsigned int len, ul = 0;
1338
1339 for (len = bytes >> 2; len--; data += 4) {
1340 cksum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
1341 }
1342
1343 switch (bytes & 3) {
1344 case 3: ul |= *data++ << 16;
1345 case 2: ul |= *data++ << 8;
1346 case 1: ul |= *data;
1347 }
1348 cksum ^= ul;
1349
1350 return cksum;
1351}
1352
1353/***************************************
1354 * NONED_INIT, NONED_DECOMPRESS, NONED_FREE
1355 ***************************************
1356 * the "not compressed" method decompressor
1357 */
1358struct noned_state {
1359 struct mspack_system *sys;
1360 struct mspack_file *i;
1361 struct mspack_file *o;
1362 unsigned char *buf;
1363 int bufsize;
1364};
1365
1366static struct noned_state *noned_init(struct mspack_system *sys,
1367 struct mspack_file *in,
1368 struct mspack_file *out,
1369 int bufsize)
1370{
1371 struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
1372 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize);
1373 if (state && buf) {
1374 state->sys = sys;
1375 state->i = in;
1376 state->o = out;
1377 state->buf = buf;
1378 state->bufsize = bufsize;
1379 }
1380 else {
1381 sys->free(buf);
1382 sys->free(state);
1383 state = NULL;
1384 }
1385 return state;
1386}
1387
1388static int noned_decompress(struct noned_state *s, off_t bytes) {
1389 int run;
1390 while (bytes > 0) {
1391 run = (bytes > s->bufsize) ? s->bufsize : (int) bytes;
1392 if (s->sys->read(s->i, &s->buf[0], run) != run) return MSPACK_ERR_READ;
1393 if (s->sys->write(s->o, &s->buf[0], run) != run) return MSPACK_ERR_WRITE;
1394 bytes -= run;
1395 }
1396 return MSPACK_ERR_OK;
1397}
1398
1399static void noned_free(struct noned_state *state) {
1400 struct mspack_system *sys;
1401 if (state) {
1402 sys = state->sys;
1403 sys->free(state->buf);
1404 sys->free(state);
1405 }
1406}
1407
1408
1409/***************************************
1410 * CABD_PARAM
1411 ***************************************
1412 * allows a parameter to be set
1413 */
1414static int cabd_param(struct mscab_decompressor *base, int param, int value) {
1415 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
1416 if (!self) return MSPACK_ERR_ARGS;
1417
1418 switch (param) {
1419 case MSCABD_PARAM_SEARCHBUF:
1420 if (value < 4) return MSPACK_ERR_ARGS;
1421 self->param[MSCABD_PARAM_SEARCHBUF] = value;
1422 break;
1423 case MSCABD_PARAM_FIXMSZIP:
1424 self->param[MSCABD_PARAM_FIXMSZIP] = value;
1425 break;
1426 case MSCABD_PARAM_DECOMPBUF:
1427 if (value < 4) return MSPACK_ERR_ARGS;
1428 self->param[MSCABD_PARAM_DECOMPBUF] = value;
1429 break;
1430 default:
1431 return MSPACK_ERR_ARGS;
1432 }
1433 return MSPACK_ERR_OK;
1434}
1435
1436/***************************************
1437 * CABD_ERROR
1438 ***************************************
1439 * returns the last error that occurred
1440 */
1441static int cabd_error(struct mscab_decompressor *base) {
1442 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
1443 return (self) ? self->error : MSPACK_ERR_ARGS;
1444}
diff --git a/rbutil/rbutilqt/mspack/chm.h b/rbutil/rbutilqt/mspack/chm.h
new file mode 100644
index 0000000000..a85d2e1731
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/chm.h
@@ -0,0 +1,122 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_CHM_H
11#define MSPACK_CHM_H 1
12
13#include <lzx.h>
14
15/* generic CHM definitions */
16
17#define chmhead_Signature (0x0000)
18#define chmhead_Version (0x0004)
19#define chmhead_HeaderLen (0x0008)
20#define chmhead_Unknown1 (0x000C)
21#define chmhead_Timestamp (0x0010)
22#define chmhead_LanguageID (0x0014)
23#define chmhead_GUID1 (0x0018)
24#define chmhead_GUID2 (0x0028)
25#define chmhead_SIZEOF (0x0038)
26
27#define chmhst_OffsetHS0 (0x0000)
28#define chmhst_LengthHS0 (0x0008)
29#define chmhst_OffsetHS1 (0x0010)
30#define chmhst_LengthHS1 (0x0018)
31#define chmhst_SIZEOF (0x0020)
32#define chmhst3_OffsetCS0 (0x0020)
33#define chmhst3_SIZEOF (0x0028)
34
35#define chmhs0_Unknown1 (0x0000)
36#define chmhs0_Unknown2 (0x0004)
37#define chmhs0_FileLen (0x0008)
38#define chmhs0_Unknown3 (0x0010)
39#define chmhs0_Unknown4 (0x0014)
40#define chmhs0_SIZEOF (0x0018)
41
42#define chmhs1_Signature (0x0000)
43#define chmhs1_Version (0x0004)
44#define chmhs1_HeaderLen (0x0008)
45#define chmhs1_Unknown1 (0x000C)
46#define chmhs1_ChunkSize (0x0010)
47#define chmhs1_Density (0x0014)
48#define chmhs1_Depth (0x0018)
49#define chmhs1_IndexRoot (0x001C)
50#define chmhs1_FirstPMGL (0x0020)
51#define chmhs1_LastPMGL (0x0024)
52#define chmhs1_Unknown2 (0x0028)
53#define chmhs1_NumChunks (0x002C)
54#define chmhs1_LanguageID (0x0030)
55#define chmhs1_GUID (0x0034)
56#define chmhs1_Unknown3 (0x0044)
57#define chmhs1_Unknown4 (0x0048)
58#define chmhs1_Unknown5 (0x004C)
59#define chmhs1_Unknown6 (0x0050)
60#define chmhs1_SIZEOF (0x0054)
61
62#define pmgl_Signature (0x0000)
63#define pmgl_QuickRefSize (0x0004)
64#define pmgl_Unknown1 (0x0008)
65#define pmgl_PrevChunk (0x000C)
66#define pmgl_NextChunk (0x0010)
67#define pmgl_Entries (0x0014)
68#define pmgl_headerSIZEOF (0x0014)
69
70#define pmgi_Signature (0x0000)
71#define pmgi_QuickRefSize (0x0004)
72#define pmgi_Entries (0x0008)
73#define pmgi_headerSIZEOF (0x000C)
74
75#define lzxcd_Length (0x0000)
76#define lzxcd_Signature (0x0004)
77#define lzxcd_Version (0x0008)
78#define lzxcd_ResetInterval (0x000C)
79#define lzxcd_WindowSize (0x0010)
80#define lzxcd_CacheSize (0x0014)
81#define lzxcd_Unknown1 (0x0018)
82#define lzxcd_SIZEOF (0x001C)
83
84#define lzxrt_Unknown1 (0x0000)
85#define lzxrt_NumEntries (0x0004)
86#define lzxrt_EntrySize (0x0008)
87#define lzxrt_TableOffset (0x000C)
88#define lzxrt_UncompLen (0x0010)
89#define lzxrt_CompLen (0x0018)
90#define lzxrt_FrameLen (0x0020)
91#define lzxrt_Entries (0x0028)
92#define lzxrt_headerSIZEOF (0x0028)
93
94/* CHM compression definitions */
95
96struct mschm_compressor_p {
97 struct mschm_compressor base;
98 struct mspack_system *system;
99 char *temp_file;
100 int use_temp_file;
101 int error;
102};
103
104/* CHM decompression definitions */
105struct mschmd_decompress_state {
106 struct mschmd_header *chm; /* CHM file being decompressed */
107 off_t offset; /* uncompressed offset within folder */
108 off_t inoffset; /* offset in input file */
109 struct lzxd_stream *state; /* LZX decompressor state */
110 struct mspack_system sys; /* special I/O code for decompressor */
111 struct mspack_file *infh; /* input file handle */
112 struct mspack_file *outfh; /* output file handle */
113};
114
115struct mschm_decompressor_p {
116 struct mschm_decompressor base;
117 struct mspack_system *system;
118 struct mschmd_decompress_state *d;
119 int error;
120};
121
122#endif
diff --git a/rbutil/rbutilqt/mspack/chmc.c b/rbutil/rbutilqt/mspack/chmc.c
new file mode 100644
index 0000000000..72f6c5b389
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/chmc.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* CHM compression implementation */
11
12#include <system.h>
13#include <chm.h>
14
15struct mschm_compressor *
16 mspack_create_chm_compressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_chm_compressor(struct mschm_compressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/chmd.c b/rbutil/rbutilqt/mspack/chmd.c
new file mode 100644
index 0000000000..6e4a1bf24f
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/chmd.c
@@ -0,0 +1,1346 @@
1/* This file is part of libmspack.
2 * (C) 2003-2011 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* CHM decompression implementation */
11
12#include <system.h>
13#include <chm.h>
14
15/* prototypes */
16static struct mschmd_header * chmd_open(
17 struct mschm_decompressor *base, const char *filename);
18static struct mschmd_header * chmd_fast_open(
19 struct mschm_decompressor *base, const char *filename);
20static struct mschmd_header *chmd_real_open(
21 struct mschm_decompressor *base, const char *filename, int entire);
22static void chmd_close(
23 struct mschm_decompressor *base, struct mschmd_header *chm);
24static int chmd_read_headers(
25 struct mspack_system *sys, struct mspack_file *fh,
26 struct mschmd_header *chm, int entire);
27static int chmd_fast_find(
28 struct mschm_decompressor *base, struct mschmd_header *chm,
29 const char *filename, struct mschmd_file *f_ptr, int f_size);
30static unsigned char *read_chunk(
31 struct mschm_decompressor_p *self, struct mschmd_header *chm,
32 struct mspack_file *fh, unsigned int chunk);
33static int search_chunk(
34 struct mschmd_header *chm, const unsigned char *chunk, const char *filename,
35 const unsigned char **result, const unsigned char **result_end);
36static inline int compare(
37 const char *s1, const char *s2, int l1, int l2);
38static int chmd_extract(
39 struct mschm_decompressor *base, struct mschmd_file *file,
40 const char *filename);
41static int chmd_sys_write(
42 struct mspack_file *file, void *buffer, int bytes);
43static int chmd_init_decomp(
44 struct mschm_decompressor_p *self, struct mschmd_file *file);
45static int read_reset_table(
46 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
47 int entry, off_t *length_ptr, off_t *offset_ptr);
48static int read_spaninfo(
49 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
50 off_t *length_ptr);
51static int find_sys_file(
52 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
53 struct mschmd_file **f_ptr, const char *name);
54static unsigned char *read_sys_file(
55 struct mschm_decompressor_p *self, struct mschmd_file *file);
56static int chmd_error(
57 struct mschm_decompressor *base);
58static int read_off64(
59 off_t *var, unsigned char *mem, struct mspack_system *sys,
60 struct mspack_file *fh);
61
62/* filenames of the system files used for decompression.
63 * Content and ControlData are essential.
64 * ResetTable is preferred, but SpanInfo can be used if not available
65 */
66static const char *content_name = "::DataSpace/Storage/MSCompressed/Content";
67static const char *control_name = "::DataSpace/Storage/MSCompressed/ControlData";
68static const char *spaninfo_name = "::DataSpace/Storage/MSCompressed/SpanInfo";
69static const char *rtable_name = "::DataSpace/Storage/MSCompressed/Transform/"
70 "{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable";
71
72/***************************************
73 * MSPACK_CREATE_CHM_DECOMPRESSOR
74 ***************************************
75 * constructor
76 */
77struct mschm_decompressor *
78 mspack_create_chm_decompressor(struct mspack_system *sys)
79{
80 struct mschm_decompressor_p *self = NULL;
81
82 if (!sys) sys = mspack_default_system;
83 if (!mspack_valid_system(sys)) return NULL;
84
85 if ((self = (struct mschm_decompressor_p *) sys->alloc(sys, sizeof(struct mschm_decompressor_p)))) {
86 self->base.open = &chmd_open;
87 self->base.close = &chmd_close;
88 self->base.extract = &chmd_extract;
89 self->base.last_error = &chmd_error;
90 self->base.fast_open = &chmd_fast_open;
91 self->base.fast_find = &chmd_fast_find;
92 self->system = sys;
93 self->error = MSPACK_ERR_OK;
94 self->d = NULL;
95 }
96 return (struct mschm_decompressor *) self;
97}
98
99/***************************************
100 * MSPACK_DESTROY_CAB_DECOMPRESSOR
101 ***************************************
102 * destructor
103 */
104void mspack_destroy_chm_decompressor(struct mschm_decompressor *base) {
105 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
106 if (self) {
107 struct mspack_system *sys = self->system;
108 if (self->d) {
109 if (self->d->infh) sys->close(self->d->infh);
110 if (self->d->state) lzxd_free(self->d->state);
111 sys->free(self->d);
112 }
113 sys->free(self);
114 }
115}
116
117/***************************************
118 * CHMD_OPEN
119 ***************************************
120 * opens a file and tries to read it as a CHM file.
121 * Calls chmd_real_open() with entire=1.
122 */
123static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
124 const char *filename)
125{
126 return chmd_real_open(base, filename, 1);
127}
128
129/***************************************
130 * CHMD_FAST_OPEN
131 ***************************************
132 * opens a file and tries to read it as a CHM file, but does not read
133 * the file headers. Calls chmd_real_open() with entire=0
134 */
135static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
136 const char *filename)
137{
138 return chmd_real_open(base, filename, 0);
139}
140
141/***************************************
142 * CHMD_REAL_OPEN
143 ***************************************
144 * the real implementation of chmd_open() and chmd_fast_open(). It simply
145 * passes the "entire" parameter to chmd_read_headers(), which will then
146 * either read all headers, or a bare mininum.
147 */
148static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
149 const char *filename, int entire)
150{
151 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
152 struct mschmd_header *chm = NULL;
153 struct mspack_system *sys;
154 struct mspack_file *fh;
155 int error;
156
157 if (!base) return NULL;
158 sys = self->system;
159
160 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
161 if ((chm = (struct mschmd_header *) sys->alloc(sys, sizeof(struct mschmd_header)))) {
162 chm->filename = filename;
163 error = chmd_read_headers(sys, fh, chm, entire);
164 if (error) {
165 /* if the error is DATAFORMAT, and there are some results, return
166 * partial results with a warning, rather than nothing */
167 if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) {
168 sys->message(fh, "WARNING; contents are corrupt");
169 error = MSPACK_ERR_OK;
170 }
171 else {
172 chmd_close(base, chm);
173 chm = NULL;
174 }
175 }
176 self->error = error;
177 }
178 else {
179 self->error = MSPACK_ERR_NOMEMORY;
180 }
181 sys->close(fh);
182 }
183 else {
184 self->error = MSPACK_ERR_OPEN;
185 }
186 return chm;
187}
188
189/***************************************
190 * CHMD_CLOSE
191 ***************************************
192 * frees all memory associated with a given mschmd_header
193 */
194static void chmd_close(struct mschm_decompressor *base,
195 struct mschmd_header *chm)
196{
197 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
198 struct mschmd_file *fi, *nfi;
199 struct mspack_system *sys;
200 unsigned int i;
201
202 if (!base) return;
203 sys = self->system;
204
205 self->error = MSPACK_ERR_OK;
206
207 /* free files */
208 for (fi = chm->files; fi; fi = nfi) {
209 nfi = fi->next;
210 sys->free(fi);
211 }
212 for (fi = chm->sysfiles; fi; fi = nfi) {
213 nfi = fi->next;
214 sys->free(fi);
215 }
216
217 /* if this CHM was being decompressed, free decompression state */
218 if (self->d && (self->d->chm == chm)) {
219 if (self->d->infh) sys->close(self->d->infh);
220 if (self->d->state) lzxd_free(self->d->state);
221 sys->free(self->d);
222 self->d = NULL;
223 }
224
225 /* if this CHM had a chunk cache, free it and contents */
226 if (chm->chunk_cache) {
227 for (i = 0; i < chm->num_chunks; i++) sys->free(chm->chunk_cache[i]);
228 sys->free(chm->chunk_cache);
229 }
230
231 sys->free(chm);
232}
233
234/***************************************
235 * CHMD_READ_HEADERS
236 ***************************************
237 * reads the basic CHM file headers. If the "entire" parameter is
238 * non-zero, all file entries will also be read. fills out a pre-existing
239 * mschmd_header structure, allocates memory for files as necessary
240 */
241
242/* The GUIDs found in CHM headers */
243static const unsigned char guids[32] = {
244 /* {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC} */
245 0x10, 0xFD, 0x01, 0x7C, 0xAA, 0x7B, 0xD0, 0x11,
246 0x9E, 0x0C, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEC,
247 /* {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC} */
248 0x11, 0xFD, 0x01, 0x7C, 0xAA, 0x7B, 0xD0, 0x11,
249 0x9E, 0x0C, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEC
250};
251
252/* reads an encoded integer into a variable; 7 bits of data per byte,
253 * the high bit is used to indicate that there is another byte */
254#define READ_ENCINT(var) do { \
255 (var) = 0; \
256 do { \
257 if (p > end) goto chunk_end; \
258 (var) = ((var) << 7) | (*p & 0x7F); \
259 } while (*p++ & 0x80); \
260} while (0)
261
262static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
263 struct mschmd_header *chm, int entire)
264{
265 unsigned int section, name_len, x, errors, num_chunks;
266 unsigned char buf[0x54], *chunk = NULL, *name, *p, *end;
267 struct mschmd_file *fi, *link = NULL;
268 off_t offset, length;
269 int num_entries;
270
271 /* initialise pointers */
272 chm->files = NULL;
273 chm->sysfiles = NULL;
274 chm->chunk_cache = NULL;
275 chm->sec0.base.chm = chm;
276 chm->sec0.base.id = 0;
277 chm->sec1.base.chm = chm;
278 chm->sec1.base.id = 1;
279 chm->sec1.content = NULL;
280 chm->sec1.control = NULL;
281 chm->sec1.spaninfo = NULL;
282 chm->sec1.rtable = NULL;
283
284 /* read the first header */
285 if (sys->read(fh, &buf[0], chmhead_SIZEOF) != chmhead_SIZEOF) {
286 return MSPACK_ERR_READ;
287 }
288
289 /* check ITSF signature */
290 if (EndGetI32(&buf[chmhead_Signature]) != 0x46535449) {
291 return MSPACK_ERR_SIGNATURE;
292 }
293
294 /* check both header GUIDs */
295 if (mspack_memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) {
296 D(("incorrect GUIDs"))
297 return MSPACK_ERR_SIGNATURE;
298 }
299
300 chm->version = EndGetI32(&buf[chmhead_Version]);
301 chm->timestamp = EndGetM32(&buf[chmhead_Timestamp]);
302 chm->language = EndGetI32(&buf[chmhead_LanguageID]);
303 if (chm->version > 3) {
304 sys->message(fh, "WARNING; CHM version > 3");
305 }
306
307 /* read the header section table */
308 if (sys->read(fh, &buf[0], chmhst3_SIZEOF) != chmhst3_SIZEOF) {
309 return MSPACK_ERR_READ;
310 }
311
312 /* chmhst3_OffsetCS0 does not exist in version 1 or 2 CHM files.
313 * The offset will be corrected later, once HS1 is read.
314 */
315 if (read_off64(&offset, &buf[chmhst_OffsetHS0], sys, fh) ||
316 read_off64(&chm->dir_offset, &buf[chmhst_OffsetHS1], sys, fh) ||
317 read_off64(&chm->sec0.offset, &buf[chmhst3_OffsetCS0], sys, fh))
318 {
319 return MSPACK_ERR_DATAFORMAT;
320 }
321
322 /* seek to header section 0 */
323 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
324 return MSPACK_ERR_SEEK;
325 }
326
327 /* read header section 0 */
328 if (sys->read(fh, &buf[0], chmhs0_SIZEOF) != chmhs0_SIZEOF) {
329 return MSPACK_ERR_READ;
330 }
331 if (read_off64(&chm->length, &buf[chmhs0_FileLen], sys, fh)) {
332 return MSPACK_ERR_DATAFORMAT;
333 }
334
335 /* seek to header section 1 */
336 if (sys->seek(fh, chm->dir_offset, MSPACK_SYS_SEEK_START)) {
337 return MSPACK_ERR_SEEK;
338 }
339
340 /* read header section 1 */
341 if (sys->read(fh, &buf[0], chmhs1_SIZEOF) != chmhs1_SIZEOF) {
342 return MSPACK_ERR_READ;
343 }
344
345 chm->dir_offset = sys->tell(fh);
346 chm->chunk_size = EndGetI32(&buf[chmhs1_ChunkSize]);
347 chm->density = EndGetI32(&buf[chmhs1_Density]);
348 chm->depth = EndGetI32(&buf[chmhs1_Depth]);
349 chm->index_root = EndGetI32(&buf[chmhs1_IndexRoot]);
350 chm->num_chunks = EndGetI32(&buf[chmhs1_NumChunks]);
351 chm->first_pmgl = EndGetI32(&buf[chmhs1_FirstPMGL]);
352 chm->last_pmgl = EndGetI32(&buf[chmhs1_LastPMGL]);
353
354 if (chm->version < 3) {
355 /* versions before 3 don't have chmhst3_OffsetCS0 */
356 chm->sec0.offset = chm->dir_offset + (chm->chunk_size * chm->num_chunks);
357 }
358
359 /* ensure chunk size is large enough for signature and num_entries */
360 if (chm->chunk_size < (pmgl_Entries + 2)) {
361 return MSPACK_ERR_DATAFORMAT;
362 }
363
364 /* if we are doing a quick read, stop here! */
365 if (!entire) {
366 return MSPACK_ERR_OK;
367 }
368
369 /* seek to the first PMGL chunk, and reduce the number of chunks to read */
370 if ((x = chm->first_pmgl) != 0) {
371 if (sys->seek(fh,(off_t) (x * chm->chunk_size), MSPACK_SYS_SEEK_CUR)) {
372 return MSPACK_ERR_SEEK;
373 }
374 }
375 num_chunks = chm->last_pmgl - x + 1;
376
377 if (!(chunk = (unsigned char *) sys->alloc(sys, (size_t)chm->chunk_size))) {
378 return MSPACK_ERR_NOMEMORY;
379 }
380
381 /* read and process all chunks from FirstPMGL to LastPMGL */
382 errors = 0;
383 while (num_chunks--) {
384 /* read next chunk */
385 if (sys->read(fh, chunk, (int)chm->chunk_size) != (int)chm->chunk_size) {
386 sys->free(chunk);
387 return MSPACK_ERR_READ;
388 }
389
390 /* process only directory (PMGL) chunks */
391 if (EndGetI32(&chunk[pmgl_Signature]) != 0x4C474D50) continue;
392
393 if (EndGetI32(&chunk[pmgl_QuickRefSize]) < 2) {
394 sys->message(fh, "WARNING; PMGL quickref area is too small");
395 }
396 if (EndGetI32(&chunk[pmgl_QuickRefSize]) >
397 ((int)chm->chunk_size - pmgl_Entries))
398 {
399 sys->message(fh, "WARNING; PMGL quickref area is too large");
400 }
401
402 p = &chunk[pmgl_Entries];
403 end = &chunk[chm->chunk_size - 2];
404 num_entries = EndGetI16(end);
405
406 while (num_entries--) {
407 READ_ENCINT(name_len); name = p; p += name_len;
408 READ_ENCINT(section);
409 READ_ENCINT(offset);
410 READ_ENCINT(length);
411
412 /* empty files and directory names are stored as a file entry at
413 * offset 0 with length 0. We want to keep empty files, but not
414 * directory names, which end with a "/" */
415 if ((offset == 0) && (length == 0)) {
416 if ((name_len > 0) && (name[name_len-1] == '/')) continue;
417 }
418
419 if (section > 1) {
420 sys->message(fh, "invalid section number '%u'.", section);
421 continue;
422 }
423
424 if (!(fi = (struct mschmd_file *) sys->alloc(sys, sizeof(struct mschmd_file) + name_len + 1))) {
425 sys->free(chunk);
426 return MSPACK_ERR_NOMEMORY;
427 }
428
429 fi->next = NULL;
430 fi->filename = (char *) &fi[1];
431 fi->section = ((section == 0) ? (struct mschmd_section *) (&chm->sec0)
432 : (struct mschmd_section *) (&chm->sec1));
433 fi->offset = offset;
434 fi->length = length;
435 sys->copy(name, fi->filename, (size_t) name_len);
436 fi->filename[name_len] = '\0';
437
438 if (name[0] == ':' && name[1] == ':') {
439 /* system file */
440 if (mspack_memcmp(&name[2], &content_name[2], 31L) == 0) {
441 if (mspack_memcmp(&name[33], &content_name[33], 8L) == 0) {
442 chm->sec1.content = fi;
443 }
444 else if (mspack_memcmp(&name[33], &control_name[33], 11L) == 0) {
445 chm->sec1.control = fi;
446 }
447 else if (mspack_memcmp(&name[33], &spaninfo_name[33], 8L) == 0) {
448 chm->sec1.spaninfo = fi;
449 }
450 else if (mspack_memcmp(&name[33], &rtable_name[33], 72L) == 0) {
451 chm->sec1.rtable = fi;
452 }
453 }
454 fi->next = chm->sysfiles;
455 chm->sysfiles = fi;
456 }
457 else {
458 /* normal file */
459 if (link) link->next = fi; else chm->files = fi;
460 link = fi;
461 }
462 }
463
464 /* this is reached either when num_entries runs out, or if
465 * reading data from the chunk reached a premature end of chunk */
466 chunk_end:
467 if (num_entries >= 0) {
468 D(("chunk ended before all entries could be read"))
469 errors++;
470 }
471
472 }
473 sys->free(chunk);
474 return (errors > 0) ? MSPACK_ERR_DATAFORMAT : MSPACK_ERR_OK;
475}
476
477/***************************************
478 * CHMD_FAST_FIND
479 ***************************************
480 * uses PMGI index chunks and quickref data to quickly locate a file
481 * directly from the on-disk index.
482 *
483 * TODO: protect against infinite loops in chunks (where pgml_NextChunk
484 * or a PGMI index entry point to an already visited chunk)
485 */
486static int chmd_fast_find(struct mschm_decompressor *base,
487 struct mschmd_header *chm, const char *filename,
488 struct mschmd_file *f_ptr, int f_size)
489{
490 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
491 struct mspack_system *sys;
492 struct mspack_file *fh;
493 const unsigned char *chunk, *p, *end;
494 int err = MSPACK_ERR_OK, result = -1;
495 unsigned int n, sec;
496
497 if (!self || !chm || !f_ptr || (f_size != sizeof(struct mschmd_file))) {
498 return MSPACK_ERR_ARGS;
499 }
500 sys = self->system;
501
502 /* clear the results structure */
503 memset(f_ptr, 0, f_size);
504
505 if (!(fh = sys->open(sys, chm->filename, MSPACK_SYS_OPEN_READ))) {
506 return MSPACK_ERR_OPEN;
507 }
508
509 /* go through PMGI chunk hierarchy to reach PMGL chunk */
510 if (chm->index_root < chm->num_chunks) {
511 n = chm->index_root;
512 for (;;) {
513 if (!(chunk = read_chunk(self, chm, fh, n))) {
514 sys->close(fh);
515 return self->error;
516 }
517
518 /* search PMGI/PMGL chunk. exit early if no entry found */
519 if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) {
520 break;
521 }
522
523 /* found result. loop around for next chunk if this is PMGI */
524 if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
525 }
526 }
527 else {
528 /* PMGL chunks only, search from first_pmgl to last_pmgl */
529 for (n = chm->first_pmgl; n <= chm->last_pmgl;
530 n = EndGetI32(&chunk[pmgl_NextChunk]))
531 {
532 if (!(chunk = read_chunk(self, chm, fh, n))) {
533 err = self->error;
534 break;
535 }
536
537 /* search PMGL chunk. exit if file found */
538 if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) {
539 break;
540 }
541 }
542 }
543
544 /* if we found a file, read it */
545 if (result > 0) {
546 READ_ENCINT(sec);
547 f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0
548 : (struct mschmd_section *) &chm->sec1;
549 READ_ENCINT(f_ptr->offset);
550 READ_ENCINT(f_ptr->length);
551 }
552 else if (result < 0) {
553 err = MSPACK_ERR_DATAFORMAT;
554 }
555
556 sys->close(fh);
557 return self->error = err;
558
559 chunk_end:
560 D(("read beyond end of chunk entries"))
561 sys->close(fh);
562 return self->error = MSPACK_ERR_DATAFORMAT;
563}
564
565/* reads the given chunk into memory, storing it in a chunk cache
566 * so it doesn't need to be read from disk more than once
567 */
568static unsigned char *read_chunk(struct mschm_decompressor_p *self,
569 struct mschmd_header *chm,
570 struct mspack_file *fh,
571 unsigned int chunk_num)
572{
573 struct mspack_system *sys = self->system;
574 unsigned char *buf;
575
576 /* check arguments - most are already checked by chmd_fast_find */
577 if (chunk_num > chm->num_chunks) return NULL;
578
579 /* ensure chunk cache is available */
580 if (!chm->chunk_cache) {
581 size_t size = sizeof(unsigned char *) * chm->num_chunks;
582 if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) {
583 self->error = MSPACK_ERR_NOMEMORY;
584 return NULL;
585 }
586 memset(chm->chunk_cache, 0, size);
587 }
588
589 /* try to answer out of chunk cache */
590 if (chm->chunk_cache[chunk_num]) return chm->chunk_cache[chunk_num];
591
592 /* need to read chunk - allocate memory for it */
593 if (!(buf = (unsigned char *) sys->alloc(sys, chm->chunk_size))) {
594 self->error = MSPACK_ERR_NOMEMORY;
595 return NULL;
596 }
597
598 /* seek to block and read it */
599 if (sys->seek(fh, (off_t) (chm->dir_offset + (chunk_num * chm->chunk_size)),
600 MSPACK_SYS_SEEK_START))
601 {
602 self->error = MSPACK_ERR_SEEK;
603 sys->free(buf);
604 return NULL;
605 }
606 if (sys->read(fh, buf, (int)chm->chunk_size) != (int)chm->chunk_size) {
607 self->error = MSPACK_ERR_READ;
608 sys->free(buf);
609 return NULL;
610 }
611
612 /* check the signature. Is is PMGL or PMGI? */
613 if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) &&
614 ((buf[3] == 0x4C) || (buf[3] == 0x49))))
615 {
616 self->error = MSPACK_ERR_SEEK;
617 sys->free(buf);
618 return NULL;
619 }
620
621 /* all OK. Store chunk in cache and return it */
622 return chm->chunk_cache[chunk_num] = buf;
623}
624
625/* searches a PMGI/PMGL chunk for a given filename entry. Returns -1 on
626 * data format error, 0 if entry definitely not found, 1 if entry
627 * found. In the latter case, *result and *result_end are set pointing
628 * to that entry's data (either the "next chunk" ENCINT for a PMGI or
629 * the section, offset and length ENCINTs for a PMGL).
630 *
631 * In the case of PMGL chunks, the entry has definitely been
632 * found. In the case of PMGI chunks, the entry which points to the
633 * chunk that may eventually contain that entry has been found.
634 */
635static int search_chunk(struct mschmd_header *chm,
636 const unsigned char *chunk,
637 const char *filename,
638 const unsigned char **result,
639 const unsigned char **result_end)
640{
641 const unsigned char *start, *end, *p;
642 unsigned int qr_size, num_entries, qr_entries, qr_density, name_len;
643 unsigned int L, R, M, sec, fname_len, entries_off, is_pmgl;
644 int cmp;
645
646 fname_len = strlen(filename);
647
648 /* PMGL chunk or PMGI chunk? (note: read_chunk() has already
649 * checked the rest of the characters in the chunk signature) */
650 if (chunk[3] == 0x4C) {
651 is_pmgl = 1;
652 entries_off = pmgl_Entries;
653 }
654 else {
655 is_pmgl = 0;
656 entries_off = pmgi_Entries;
657 }
658
659 /* Step 1: binary search first filename of each QR entry
660 * - target filename == entry
661 * found file
662 * - target filename < all entries
663 * file not found
664 * - target filename > all entries
665 * proceed to step 2 using final entry
666 * - target filename between two searched entries
667 * proceed to step 2
668 */
669 qr_size = EndGetI32(&chunk[pmgl_QuickRefSize]);
670 start = &chunk[chm->chunk_size - 2];
671 end = &chunk[chm->chunk_size - qr_size];
672 num_entries = EndGetI16(start);
673 qr_density = 1 + (1 << chm->density);
674 qr_entries = (num_entries + qr_density-1) / qr_density;
675
676 if (num_entries == 0) {
677 D(("chunk has no entries"))
678 return -1;
679 }
680
681 if (qr_size > chm->chunk_size) {
682 D(("quickref size > chunk size"))
683 return -1;
684 }
685
686 *result_end = end;
687
688 if (((int)qr_entries * 2) > (start - end)) {
689 D(("WARNING; more quickrefs than quickref space"))
690 qr_entries = 0; /* but we can live with it */
691 }
692
693 if (qr_entries > 0) {
694 L = 0;
695 R = qr_entries - 1;
696 do {
697 /* pick new midpoint */
698 M = (L + R) >> 1;
699
700 /* compare filename with entry QR points to */
701 p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
702 READ_ENCINT(name_len);
703 if (p + name_len > end) goto chunk_end;
704 cmp = compare(filename, (char *)p, fname_len, name_len);
705
706 if (cmp == 0) break;
707 else if (cmp < 0) { if (M) R = M - 1; else return 0; }
708 else if (cmp > 0) L = M + 1;
709 } while (L <= R);
710 M = (L + R) >> 1;
711
712 if (cmp == 0) {
713 /* exact match! */
714 p += name_len;
715 *result = p;
716 return 1;
717 }
718
719 /* otherwise, read the group of entries for QR entry M */
720 p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
721 num_entries -= (M * qr_density);
722 if (num_entries > qr_density) num_entries = qr_density;
723 }
724 else {
725 p = &chunk[entries_off];
726 }
727
728 /* Step 2: linear search through the set of entries reached in step 1.
729 * - filename == any entry
730 * found entry
731 * - filename < all entries (PMGI) or any entry (PMGL)
732 * entry not found, stop now
733 * - filename > all entries
734 * entry not found (PMGL) / maybe found (PMGI)
735 * -
736 */
737 *result = NULL;
738 while (num_entries-- > 0) {
739 READ_ENCINT(name_len);
740 if (p + name_len > end) goto chunk_end;
741 cmp = compare(filename, (char *)p, fname_len, name_len);
742 p += name_len;
743
744 if (cmp == 0) {
745 /* entry found */
746 *result = p;
747 return 1;
748 }
749
750 if (cmp < 0) {
751 /* entry not found (PMGL) / maybe found (PMGI) */
752 break;
753 }
754
755 /* read and ignore the rest of this entry */
756 if (is_pmgl) {
757 READ_ENCINT(R); /* skip section */
758 READ_ENCINT(R); /* skip offset */
759 READ_ENCINT(R); /* skip length */
760 }
761 else {
762 *result = p; /* store potential final result */
763 READ_ENCINT(R); /* skip chunk number */
764 }
765 }
766
767 /* PMGL? not found. PMGI? maybe found */
768 return (is_pmgl) ? 0 : (*result ? 1 : 0);
769
770 chunk_end:
771 D(("reached end of chunk data while searching"))
772 return -1;
773}
774
775#if HAVE_TOWLOWER
776# if HAVE_WCTYPE_H
777# include <wctype.h>
778# endif
779# define TOLOWER(x) towlower(x)
780#elif HAVE_TOLOWER
781# if HAVE_CTYPE_H
782# include <ctype.h>
783# endif
784# define TOLOWER(x) tolower(x)
785#else
786# define TOLOWER(x) (((x)<0||(x)>256)?(x):mspack_tolower_map[(x)])
787/* Map of char -> lowercase char for the first 256 chars. Generated with:
788 * LC_CTYPE=en_GB.utf-8 perl -Mlocale -le 'print map{ord(lc chr).","} 0..255'
789 */
790static const unsigned char mspack_tolower_map[256] = {
791 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
792 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
793 53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,106,
794 107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,
795 95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
796 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
797 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,
798 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,
799 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
800 191,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,
801 242,243,244,245,246,215,248,249,250,251,252,253,254,223,224,225,226,227,228,
802 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
803 248,249,250,251,252,253,254,255
804};
805#endif
806
807/* decodes a UTF-8 character from s[] into c. Will not read past e. */
808#define GET_UTF8_CHAR(s, e, c) do { \
809 unsigned char x = *s++; \
810 if (x < 0x80) c = x; \
811 else if (x < 0xC0) c = -1; \
812 else if (x < 0xE0) { \
813 c = (s >= e) ? -1 : ((x & 0x1F) << 6) | (*s++ & 0x3F); \
814 } \
815 else if (x < 0xF0) { \
816 c = (s+2 > e) ? -1 : ((x & 0x0F) << 12) | ((s[0] & 0x3F) << 6) \
817 | (s[1] & 0x3F); \
818 s += 2; \
819 } \
820 else if (x < 0xF8) { \
821 c = (s+3 > e) ? -1 : ((x & 0x07) << 18) | ((s[0] & 0x3F) << 12) \
822 | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); \
823 s += 3; \
824 } \
825 else if (x < 0xFC) { \
826 c = (s+4 > e) ? -1 : ((x & 0x03) << 24) | ((s[0] & 0x3F) << 18) \
827 | ((s[1] & 0x3F) << 12)|((s[2] & 0x3F) << 6)|(s[3] & 0x3F); \
828 s += 4; \
829 } \
830 else if (x < 0xFE) { \
831 c = (s+5>e)?-1:((x&1)<<30)|((s[0]&0x3F)<<24)|((s[1]&0x3F)<<18)| \
832 ((s[2] & 0x3F) << 12) | ((s[3] & 0x3F) << 6)|(s[4] & 0x3F); \
833 s += 5; \
834 } \
835 else c = -1; \
836} while (0)
837
838/* case-insensitively compares two UTF8 encoded strings. String length for
839 * both strings must be provided, null bytes are not terminators */
840static inline int compare(const char *s1, const char *s2, int l1, int l2) {
841 register const unsigned char *p1 = (const unsigned char *) s1;
842 register const unsigned char *p2 = (const unsigned char *) s2;
843 register const unsigned char *e1 = p1 + l1, *e2 = p2 + l2;
844 int c1, c2;
845
846 while (p1 < e1 && p2 < e2) {
847 GET_UTF8_CHAR(p1, e1, c1);
848 GET_UTF8_CHAR(p2, e2, c2);
849 if (c1 == c2) continue;
850 c1 = TOLOWER(c1);
851 c2 = TOLOWER(c2);
852 if (c1 != c2) return c1 - c2;
853 }
854 return l1 - l2;
855}
856
857
858/***************************************
859 * CHMD_EXTRACT
860 ***************************************
861 * extracts a file from a CHM helpfile
862 */
863static int chmd_extract(struct mschm_decompressor *base,
864 struct mschmd_file *file, const char *filename)
865{
866 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
867 struct mspack_system *sys;
868 struct mschmd_header *chm;
869 struct mspack_file *fh;
870 off_t bytes;
871
872 if (!self) return MSPACK_ERR_ARGS;
873 if (!file || !file->section) return self->error = MSPACK_ERR_ARGS;
874 sys = self->system;
875 chm = file->section->chm;
876
877 /* create decompression state if it doesn't exist */
878 if (!self->d) {
879 self->d = (struct mschmd_decompress_state *) sys->alloc(sys, sizeof(struct mschmd_decompress_state));
880 if (!self->d) return self->error = MSPACK_ERR_NOMEMORY;
881 self->d->chm = chm;
882 self->d->offset = 0;
883 self->d->state = NULL;
884 self->d->sys = *sys;
885 self->d->sys.write = &chmd_sys_write;
886 self->d->infh = NULL;
887 self->d->outfh = NULL;
888 }
889
890 /* open input chm file if not open, or the open one is a different chm */
891 if (!self->d->infh || (self->d->chm != chm)) {
892 if (self->d->infh) sys->close(self->d->infh);
893 if (self->d->state) lzxd_free(self->d->state);
894 self->d->chm = chm;
895 self->d->offset = 0;
896 self->d->state = NULL;
897 self->d->infh = sys->open(sys, chm->filename, MSPACK_SYS_OPEN_READ);
898 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
899 }
900
901 /* open file for output */
902 if (!(fh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
903 return self->error = MSPACK_ERR_OPEN;
904 }
905
906 /* if file is empty, simply creating it is enough */
907 if (!file->length) {
908 sys->close(fh);
909 return self->error = MSPACK_ERR_OK;
910 }
911
912 self->error = MSPACK_ERR_OK;
913
914 switch (file->section->id) {
915 case 0: /* Uncompressed section file */
916 /* simple seek + copy */
917 if (sys->seek(self->d->infh, file->section->chm->sec0.offset
918 + file->offset, MSPACK_SYS_SEEK_START))
919 {
920 self->error = MSPACK_ERR_SEEK;
921 }
922 else {
923 unsigned char buf[512];
924 off_t length = file->length;
925 while (length > 0) {
926 int run = sizeof(buf);
927 if ((off_t)run > length) run = (int)length;
928 if (sys->read(self->d->infh, &buf[0], run) != run) {
929 self->error = MSPACK_ERR_READ;
930 break;
931 }
932 if (sys->write(fh, &buf[0], run) != run) {
933 self->error = MSPACK_ERR_WRITE;
934 break;
935 }
936 length -= run;
937 }
938 }
939 break;
940
941 case 1: /* MSCompressed section file */
942 /* (re)initialise compression state if we it is not yet initialised,
943 * or we have advanced too far and have to backtrack
944 */
945 if (!self->d->state || (file->offset < self->d->offset)) {
946 if (self->d->state) {
947 lzxd_free(self->d->state);
948 self->d->state = NULL;
949 }
950 if (chmd_init_decomp(self, file)) break;
951 }
952
953 /* seek to input data */
954 if (sys->seek(self->d->infh, self->d->inoffset, MSPACK_SYS_SEEK_START)) {
955 self->error = MSPACK_ERR_SEEK;
956 break;
957 }
958
959 /* get to correct offset. */
960 self->d->outfh = NULL;
961 if ((bytes = file->offset - self->d->offset)) {
962 self->error = lzxd_decompress(self->d->state, bytes);
963 }
964
965 /* if getting to the correct offset was error free, unpack file */
966 if (!self->error) {
967 self->d->outfh = fh;
968 self->error = lzxd_decompress(self->d->state, file->length);
969 }
970
971 /* save offset in input source stream, in case there is a section 0
972 * file between now and the next section 1 file extracted */
973 self->d->inoffset = sys->tell(self->d->infh);
974
975 /* if an LZX error occured, the LZX decompressor is now useless */
976 if (self->error) {
977 if (self->d->state) lzxd_free(self->d->state);
978 self->d->state = NULL;
979 }
980 break;
981 }
982
983 sys->close(fh);
984 return self->error;
985}
986
987/***************************************
988 * CHMD_SYS_WRITE
989 ***************************************
990 * chmd_sys_write is the internal writer function which the decompressor
991 * uses. If either writes data to disk (self->d->outfh) with the real
992 * sys->write() function, or does nothing with the data when
993 * self->d->outfh == NULL. advances self->d->offset.
994 */
995static int chmd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
996 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) file;
997 self->d->offset += bytes;
998 if (self->d->outfh) {
999 return self->system->write(self->d->outfh, buffer, bytes);
1000 }
1001 return bytes;
1002}
1003
1004/***************************************
1005 * CHMD_INIT_DECOMP
1006 ***************************************
1007 * Initialises the LZX decompressor to decompress the compressed stream,
1008 * from the nearest reset offset and length that is needed for the given
1009 * file.
1010 */
1011static int chmd_init_decomp(struct mschm_decompressor_p *self,
1012 struct mschmd_file *file)
1013{
1014 int window_size, window_bits, reset_interval, entry, err;
1015 struct mspack_system *sys = self->system;
1016 struct mschmd_sec_mscompressed *sec;
1017 unsigned char *data;
1018 off_t length, offset;
1019
1020 sec = (struct mschmd_sec_mscompressed *) file->section;
1021
1022 /* ensure we have a mscompressed content section */
1023 err = find_sys_file(self, sec, &sec->content, content_name);
1024 if (err) return self->error = err;
1025
1026 /* ensure we have a ControlData file */
1027 err = find_sys_file(self, sec, &sec->control, control_name);
1028 if (err) return self->error = err;
1029
1030 /* read ControlData */
1031 if (sec->control->length < lzxcd_SIZEOF) {
1032 D(("ControlData file is too short"))
1033 return self->error = MSPACK_ERR_DATAFORMAT;
1034 }
1035 if (!(data = read_sys_file(self, sec->control))) {
1036 D(("can't read mscompressed control data file"))
1037 return self->error;
1038 }
1039
1040 /* check LZXC signature */
1041 if (EndGetI32(&data[lzxcd_Signature]) != 0x43585A4C) {
1042 sys->free(data);
1043 return self->error = MSPACK_ERR_SIGNATURE;
1044 }
1045
1046 /* read reset_interval and window_size and validate version number */
1047 switch (EndGetI32(&data[lzxcd_Version])) {
1048 case 1:
1049 reset_interval = EndGetI32(&data[lzxcd_ResetInterval]);
1050 window_size = EndGetI32(&data[lzxcd_WindowSize]);
1051 break;
1052 case 2:
1053 reset_interval = EndGetI32(&data[lzxcd_ResetInterval]) * LZX_FRAME_SIZE;
1054 window_size = EndGetI32(&data[lzxcd_WindowSize]) * LZX_FRAME_SIZE;
1055 break;
1056 default:
1057 D(("bad controldata version"))
1058 sys->free(data);
1059 return self->error = MSPACK_ERR_DATAFORMAT;
1060 }
1061
1062 /* free ControlData */
1063 sys->free(data);
1064
1065 /* find window_bits from window_size */
1066 switch (window_size) {
1067 case 0x008000: window_bits = 15; break;
1068 case 0x010000: window_bits = 16; break;
1069 case 0x020000: window_bits = 17; break;
1070 case 0x040000: window_bits = 18; break;
1071 case 0x080000: window_bits = 19; break;
1072 case 0x100000: window_bits = 20; break;
1073 case 0x200000: window_bits = 21; break;
1074 default:
1075 D(("bad controldata window size"))
1076 return self->error = MSPACK_ERR_DATAFORMAT;
1077 }
1078
1079 /* validate reset_interval */
1080 if (reset_interval % LZX_FRAME_SIZE) {
1081 D(("bad controldata reset interval"))
1082 return self->error = MSPACK_ERR_DATAFORMAT;
1083 }
1084
1085 /* which reset table entry would we like? */
1086 entry = file->offset / reset_interval;
1087 /* convert from reset interval multiple (usually 64k) to 32k frames */
1088 entry *= reset_interval / LZX_FRAME_SIZE;
1089
1090 /* read the reset table entry */
1091 if (read_reset_table(self, sec, entry, &length, &offset)) {
1092 /* the uncompressed length given in the reset table is dishonest.
1093 * the uncompressed data is always padded out from the given
1094 * uncompressed length up to the next reset interval */
1095 length += reset_interval - 1;
1096 length &= -reset_interval;
1097 }
1098 else {
1099 /* if we can't read the reset table entry, just start from
1100 * the beginning. Use spaninfo to get the uncompressed length */
1101 entry = 0;
1102 offset = 0;
1103 err = read_spaninfo(self, sec, &length);
1104 }
1105 if (err) return self->error = err;
1106
1107 /* get offset of compressed data stream:
1108 * = offset of uncompressed section from start of file
1109 * + offset of compressed stream from start of uncompressed section
1110 * + offset of chosen reset interval from start of compressed stream */
1111 self->d->inoffset = file->section->chm->sec0.offset + sec->content->offset + offset;
1112
1113 /* set start offset and overall remaining stream length */
1114 self->d->offset = entry * LZX_FRAME_SIZE;
1115 length -= self->d->offset;
1116
1117 /* initialise LZX stream */
1118 self->d->state = lzxd_init(&self->d->sys, self->d->infh,
1119 (struct mspack_file *) self, window_bits,
1120 reset_interval / LZX_FRAME_SIZE,
1121 4096, length);
1122 if (!self->d->state) self->error = MSPACK_ERR_NOMEMORY;
1123 return self->error;
1124}
1125
1126/***************************************
1127 * READ_RESET_TABLE
1128 ***************************************
1129 * Reads one entry out of the reset table. Also reads the uncompressed
1130 * data length. Writes these to offset_ptr and length_ptr respectively.
1131 * Returns non-zero for success, zero for failure.
1132 */
1133static int read_reset_table(struct mschm_decompressor_p *self,
1134 struct mschmd_sec_mscompressed *sec,
1135 int entry, off_t *length_ptr, off_t *offset_ptr)
1136{
1137 struct mspack_system *sys = self->system;
1138 unsigned char *data;
1139 int pos, entrysize;
1140
1141 /* do we have a ResetTable file? */
1142 int err = find_sys_file(self, sec, &sec->rtable, rtable_name);
1143 if (err) return 0;
1144
1145 /* read ResetTable file */
1146 if (sec->rtable->length < lzxrt_headerSIZEOF) {
1147 D(("ResetTable file is too short"))
1148 return 0;
1149 }
1150 if (!(data = read_sys_file(self, sec->rtable))) {
1151 D(("can't read reset table"))
1152 return 0;
1153 }
1154
1155 /* check sanity of reset table */
1156 if (EndGetI32(&data[lzxrt_FrameLen]) != LZX_FRAME_SIZE) {
1157 D(("bad reset table frame length"))
1158 sys->free(data);
1159 return 0;
1160 }
1161
1162 /* get the uncompressed length of the LZX stream */
1163 if (read_off64(length_ptr, data, sys, self->d->infh)) {
1164 sys->free(data);
1165 return 0;
1166 }
1167
1168 entrysize = EndGetI32(&data[lzxrt_EntrySize]);
1169 pos = EndGetI32(&data[lzxrt_TableOffset]) + (entry * entrysize);
1170
1171 /* ensure reset table entry for this offset exists */
1172 if (entry < EndGetI32(&data[lzxrt_NumEntries]) &&
1173 ((pos + entrysize) <= sec->rtable->length))
1174 {
1175 switch (entrysize) {
1176 case 4:
1177 *offset_ptr = EndGetI32(&data[pos]);
1178 err = 0;
1179 break;
1180 case 8:
1181 err = read_off64(offset_ptr, &data[pos], sys, self->d->infh);
1182 break;
1183 default:
1184 D(("reset table entry size neither 4 nor 8"))
1185 err = 1;
1186 break;
1187 }
1188 }
1189 else {
1190 D(("bad reset interval"))
1191 err = 1;
1192 }
1193
1194 /* free the reset table */
1195 sys->free(data);
1196
1197 /* return success */
1198 return (err == 0);
1199}
1200
1201/***************************************
1202 * READ_SPANINFO
1203 ***************************************
1204 * Reads the uncompressed data length from the spaninfo file.
1205 * Returns zero for success or a non-zero error code for failure.
1206 */
1207static int read_spaninfo(struct mschm_decompressor_p *self,
1208 struct mschmd_sec_mscompressed *sec,
1209 off_t *length_ptr)
1210{
1211 struct mspack_system *sys = self->system;
1212 unsigned char *data;
1213
1214 /* find SpanInfo file */
1215 int err = find_sys_file(self, sec, &sec->spaninfo, spaninfo_name);
1216 if (err) return MSPACK_ERR_DATAFORMAT;
1217
1218 /* check it's large enough */
1219 if (sec->spaninfo->length != 8) {
1220 D(("SpanInfo file is wrong size"))
1221 return MSPACK_ERR_DATAFORMAT;
1222 }
1223
1224 /* read the SpanInfo file */
1225 if (!(data = read_sys_file(self, sec->spaninfo))) {
1226 D(("can't read SpanInfo file"))
1227 return self->error;
1228 }
1229
1230 /* get the uncompressed length of the LZX stream */
1231 err = read_off64(length_ptr, data, sys, self->d->infh);
1232
1233 sys->free(data);
1234 return (err) ? MSPACK_ERR_DATAFORMAT : MSPACK_ERR_OK;
1235}
1236
1237/***************************************
1238 * FIND_SYS_FILE
1239 ***************************************
1240 * Uses chmd_fast_find to locate a system file, and fills out that system
1241 * file's entry and links it into the list of system files. Returns zero
1242 * for success, non-zero for both failure and the file not existing.
1243 */
1244static int find_sys_file(struct mschm_decompressor_p *self,
1245 struct mschmd_sec_mscompressed *sec,
1246 struct mschmd_file **f_ptr, const char *name)
1247{
1248 struct mspack_system *sys = self->system;
1249 struct mschmd_file result;
1250
1251 /* already loaded */
1252 if (*f_ptr) return MSPACK_ERR_OK;
1253
1254 /* try using fast_find to find the file - return DATAFORMAT error if
1255 * it fails, or successfully doesn't find the file */
1256 if (chmd_fast_find((struct mschm_decompressor *) self, sec->base.chm,
1257 name, &result, (int)sizeof(result)) || !result.section)
1258 {
1259 return MSPACK_ERR_DATAFORMAT;
1260 }
1261
1262 if (!(*f_ptr = (struct mschmd_file *) sys->alloc(sys, sizeof(result)))) {
1263 return MSPACK_ERR_NOMEMORY;
1264 }
1265
1266 /* copy result */
1267 *(*f_ptr) = result;
1268 (*f_ptr)->filename = (char *) name;
1269
1270 /* link file into sysfiles list */
1271 (*f_ptr)->next = sec->base.chm->sysfiles;
1272 sec->base.chm->sysfiles = *f_ptr;
1273 return MSPACK_ERR_OK;
1274}
1275
1276/***************************************
1277 * READ_SYS_FILE
1278 ***************************************
1279 * Allocates memory for a section 0 (uncompressed) file and reads it into
1280 * memory.
1281 */
1282static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
1283 struct mschmd_file *file)
1284{
1285 struct mspack_system *sys = self->system;
1286 unsigned char *data = NULL;
1287 int len;
1288
1289 if (!file || !file->section || (file->section->id != 0)) {
1290 self->error = MSPACK_ERR_DATAFORMAT;
1291 return NULL;
1292 }
1293
1294 len = (int) file->length;
1295
1296 if (!(data = (unsigned char *) sys->alloc(sys, (size_t) len))) {
1297 self->error = MSPACK_ERR_NOMEMORY;
1298 return NULL;
1299 }
1300 if (sys->seek(self->d->infh, file->section->chm->sec0.offset
1301 + file->offset, MSPACK_SYS_SEEK_START))
1302 {
1303 self->error = MSPACK_ERR_SEEK;
1304 sys->free(data);
1305 return NULL;
1306 }
1307 if (sys->read(self->d->infh, data, len) != len) {
1308 self->error = MSPACK_ERR_READ;
1309 sys->free(data);
1310 return NULL;
1311 }
1312 return data;
1313}
1314
1315/***************************************
1316 * CHMD_ERROR
1317 ***************************************
1318 * returns the last error that occurred
1319 */
1320static int chmd_error(struct mschm_decompressor *base) {
1321 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
1322 return (self) ? self->error : MSPACK_ERR_ARGS;
1323}
1324
1325/***************************************
1326 * READ_OFF64
1327 ***************************************
1328 * Reads a 64-bit signed integer from memory in Intel byte order.
1329 * If running on a system with a 64-bit off_t, this is simply done.
1330 * If running on a system with a 32-bit off_t, offsets up to 0x7FFFFFFF
1331 * are accepted, offsets beyond that cause an error message.
1332 */
1333static int read_off64(off_t *var, unsigned char *mem,
1334 struct mspack_system *sys, struct mspack_file *fh)
1335{
1336#ifdef LARGEFILE_SUPPORT
1337 *var = EndGetI64(mem);
1338#else
1339 *var = EndGetI32(mem);
1340 if ((*var & 0x80000000) || EndGetI32(mem+4)) {
1341 sys->message(fh, (char *)largefile_msg);
1342 return 1;
1343 }
1344#endif
1345 return 0;
1346}
diff --git a/rbutil/rbutilqt/mspack/des.h b/rbutil/rbutilqt/mspack/des.h
new file mode 100644
index 0000000000..64a1ed27e4
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/des.h
@@ -0,0 +1,15 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_DES_H
11#define MSPACK_DES_H 1
12
13/* DES encryption / decryption definitions */
14
15#endif
diff --git a/rbutil/rbutilqt/mspack/hlp.h b/rbutil/rbutilqt/mspack/hlp.h
new file mode 100644
index 0000000000..b7486fa160
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/hlp.h
@@ -0,0 +1,33 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_HLP_H
11#define MSPACK_HLP_H 1
12
13#include <lzss.h>
14
15/* generic HLP definitions */
16
17/* HLP compression definitions */
18
19struct mshlp_compressor_p {
20 struct mshlp_compressor base;
21 struct mspack_system *system;
22 /* todo */
23};
24
25/* HLP decompression definitions */
26
27struct mshlp_decompressor_p {
28 struct mshlp_decompressor base;
29 struct mspack_system *system;
30 /* todo */
31};
32
33#endif
diff --git a/rbutil/rbutilqt/mspack/hlpc.c b/rbutil/rbutilqt/mspack/hlpc.c
new file mode 100644
index 0000000000..60eabfe207
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/hlpc.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* HLP compression implementation */
11
12#include <system.h>
13#include <hlp.h>
14
15struct mshlp_compressor *
16 mspack_create_hlp_compressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_hlp_compressor(struct mshlp_compressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/hlpd.c b/rbutil/rbutilqt/mspack/hlpd.c
new file mode 100644
index 0000000000..43354f008f
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/hlpd.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* HLP decompression implementation */
11
12#include <system.h>
13#include <hlp.h>
14
15struct mshlp_decompressor *
16 mspack_create_hlp_decompressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_hlp_decompressor(struct mshlp_decompressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/kwaj.h b/rbutil/rbutilqt/mspack/kwaj.h
new file mode 100644
index 0000000000..09673c0779
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/kwaj.h
@@ -0,0 +1,118 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_KWAJ_H
11#define MSPACK_KWAJ_H 1
12
13#include <lzss.h>
14
15/* generic KWAJ definitions */
16#define kwajh_Signature1 (0x00)
17#define kwajh_Signature2 (0x04)
18#define kwajh_CompMethod (0x08)
19#define kwajh_DataOffset (0x0a)
20#define kwajh_Flags (0x0c)
21#define kwajh_SIZEOF (0x0e)
22
23/* KWAJ compression definitions */
24
25struct mskwaj_compressor_p {
26 struct mskwaj_compressor base;
27 struct mspack_system *system;
28 /* todo */
29 int param[2]; /* !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! */
30 int error;
31};
32
33/* KWAJ decompression definitions */
34
35struct mskwaj_decompressor_p {
36 struct mskwaj_decompressor base;
37 struct mspack_system *system;
38 int error;
39};
40
41struct mskwajd_header_p {
42 struct mskwajd_header base;
43 struct mspack_file *fh;
44};
45
46/* input buffer size during decompression - not worth parameterising IMHO */
47#define KWAJ_INPUT_SIZE (2048)
48
49/* huffman codes that are 9 bits or less are decoded immediately */
50#define KWAJ_TABLEBITS (9)
51
52/* number of codes in each huffman table */
53#define KWAJ_MATCHLEN1_SYMS (16)
54#define KWAJ_MATCHLEN2_SYMS (16)
55#define KWAJ_LITLEN_SYMS (32)
56#define KWAJ_OFFSET_SYMS (64)
57#define KWAJ_LITERAL_SYMS (256)
58
59/* define decoding table sizes */
60#define KWAJ_TABLESIZE (1 << KWAJ_TABLEBITS)
61#if KWAJ_TABLESIZE < (KWAJ_MATCHLEN1_SYMS * 2)
62# define KWAJ_MATCHLEN1_TBLSIZE (KWAJ_MATCHLEN1_SYMS * 4)
63#else
64# define KWAJ_MATCHLEN1_TBLSIZE (KWAJ_TABLESIZE + (KWAJ_MATCHLEN1_SYMS * 2))
65#endif
66#if KWAJ_TABLESIZE < (KWAJ_MATCHLEN2_SYMS * 2)
67# define KWAJ_MATCHLEN2_TBLSIZE (KWAJ_MATCHLEN2_SYMS * 4)
68#else
69# define KWAJ_MATCHLEN2_TBLSIZE (KWAJ_TABLESIZE + (KWAJ_MATCHLEN2_SYMS * 2))
70#endif
71#if KWAJ_TABLESIZE < (KWAJ_LITLEN_SYMS * 2)
72# define KWAJ_LITLEN_TBLSIZE (KWAJ_LITLEN_SYMS * 4)
73#else
74# define KWAJ_LITLEN_TBLSIZE (KWAJ_TABLESIZE + (KWAJ_LITLEN_SYMS * 2))
75#endif
76#if KWAJ_TABLESIZE < (KWAJ_OFFSET_SYMS * 2)
77# define KWAJ_OFFSET_TBLSIZE (KWAJ_OFFSET_SYMS * 4)
78#else
79# define KWAJ_OFFSET_TBLSIZE (KWAJ_TABLESIZE + (KWAJ_OFFSET_SYMS * 2))
80#endif
81#if KWAJ_TABLESIZE < (KWAJ_LITERAL_SYMS * 2)
82# define KWAJ_LITERAL_TBLSIZE (KWAJ_LITERAL_SYMS * 4)
83#else
84# define KWAJ_LITERAL_TBLSIZE (KWAJ_TABLESIZE + (KWAJ_LITERAL_SYMS * 2))
85#endif
86
87struct kwajd_stream {
88 /* I/O buffering */
89 struct mspack_system *sys;
90 struct mspack_file *input;
91 struct mspack_file *output;
92 unsigned char *i_ptr, *i_end;
93 unsigned int bit_buffer, bits_left;
94 int input_end;
95
96 /* huffman code lengths */
97 unsigned char MATCHLEN1_len [KWAJ_MATCHLEN1_SYMS];
98 unsigned char MATCHLEN2_len [KWAJ_MATCHLEN2_SYMS];
99 unsigned char LITLEN_len [KWAJ_LITLEN_SYMS];
100 unsigned char OFFSET_len [KWAJ_OFFSET_SYMS];
101 unsigned char LITERAL_len [KWAJ_LITERAL_SYMS];
102
103 /* huffman decoding tables */
104 unsigned short MATCHLEN1_table [KWAJ_MATCHLEN1_TBLSIZE];
105 unsigned short MATCHLEN2_table [KWAJ_MATCHLEN2_TBLSIZE];
106 unsigned short LITLEN_table [KWAJ_LITLEN_TBLSIZE];
107 unsigned short OFFSET_table [KWAJ_OFFSET_TBLSIZE];
108 unsigned short LITERAL_table [KWAJ_LITERAL_TBLSIZE];
109
110 /* input buffer */
111 unsigned char inbuf[KWAJ_INPUT_SIZE];
112
113 /* history window */
114 unsigned char window[LZSS_WINDOW_SIZE];
115};
116
117
118#endif
diff --git a/rbutil/rbutilqt/mspack/kwajc.c b/rbutil/rbutilqt/mspack/kwajc.c
new file mode 100644
index 0000000000..b88ed7690a
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/kwajc.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* KWAJ compression implementation */
11
12#include <system.h>
13#include <kwaj.h>
14
15struct mskwaj_compressor *
16 mspack_create_kwaj_compressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_kwaj_compressor(struct mskwaj_compressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/kwajd.c b/rbutil/rbutilqt/mspack/kwajd.c
new file mode 100644
index 0000000000..d891b6a7e3
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/kwajd.c
@@ -0,0 +1,555 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was
5 * written by Jeff Johnson.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13/* KWAJ decompression implementation */
14
15#include <system.h>
16#include <kwaj.h>
17
18/* prototypes */
19static struct mskwajd_header *kwajd_open(
20 struct mskwaj_decompressor *base, const char *filename);
21static void kwajd_close(
22 struct mskwaj_decompressor *base, struct mskwajd_header *hdr);
23static int kwajd_read_headers(
24 struct mspack_system *sys, struct mspack_file *fh,
25 struct mskwajd_header *hdr);
26static int kwajd_extract(
27 struct mskwaj_decompressor *base, struct mskwajd_header *hdr,
28 const char *filename);
29static int kwajd_decompress(
30 struct mskwaj_decompressor *base, const char *input, const char *output);
31static int kwajd_error(
32 struct mskwaj_decompressor *base);
33
34static struct kwajd_stream *lzh_init(
35 struct mspack_system *sys, struct mspack_file *in, struct mspack_file *out);
36static int lzh_decompress(
37 struct kwajd_stream *kwaj);
38static void lzh_free(
39 struct kwajd_stream *kwaj);
40static int lzh_read_lens(
41 struct kwajd_stream *kwaj,
42 unsigned int type, unsigned int numsyms,
43 unsigned char *lens, unsigned short *table);
44static int lzh_read_input(
45 struct kwajd_stream *kwaj);
46
47
48/***************************************
49 * MSPACK_CREATE_KWAJ_DECOMPRESSOR
50 ***************************************
51 * constructor
52 */
53struct mskwaj_decompressor *
54 mspack_create_kwaj_decompressor(struct mspack_system *sys)
55{
56 struct mskwaj_decompressor_p *self = NULL;
57
58 if (!sys) sys = mspack_default_system;
59 if (!mspack_valid_system(sys)) return NULL;
60
61 if ((self = (struct mskwaj_decompressor_p *) sys->alloc(sys, sizeof(struct mskwaj_decompressor_p)))) {
62 self->base.open = &kwajd_open;
63 self->base.close = &kwajd_close;
64 self->base.extract = &kwajd_extract;
65 self->base.decompress = &kwajd_decompress;
66 self->base.last_error = &kwajd_error;
67 self->system = sys;
68 self->error = MSPACK_ERR_OK;
69 }
70 return (struct mskwaj_decompressor *) self;
71}
72
73/***************************************
74 * MSPACK_DESTROY_KWAJ_DECOMPRESSOR
75 ***************************************
76 * destructor
77 */
78void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *base)
79{
80 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
81 if (self) {
82 struct mspack_system *sys = self->system;
83 sys->free(self);
84 }
85}
86
87/***************************************
88 * KWAJD_OPEN
89 ***************************************
90 * opens a KWAJ file without decompressing, reads header
91 */
92static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
93 const char *filename)
94{
95 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
96 struct mskwajd_header *hdr;
97 struct mspack_system *sys;
98 struct mspack_file *fh;
99
100 if (!self) return NULL;
101 sys = self->system;
102
103 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
104 hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
105 if (fh && hdr) {
106 ((struct mskwajd_header_p *) hdr)->fh = fh;
107 self->error = kwajd_read_headers(sys, fh, hdr);
108 }
109 else {
110 if (!fh) self->error = MSPACK_ERR_OPEN;
111 if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
112 }
113
114 if (self->error) {
115 if (fh) sys->close(fh);
116 if (hdr) sys->free(hdr);
117 hdr = NULL;
118 }
119
120 return hdr;
121}
122
123/***************************************
124 * KWAJD_CLOSE
125 ***************************************
126 * closes a KWAJ file
127 */
128static void kwajd_close(struct mskwaj_decompressor *base,
129 struct mskwajd_header *hdr)
130{
131 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
132 struct mskwajd_header_p *hdr_p = (struct mskwajd_header_p *) hdr;
133
134 if (!self || !self->system) return;
135
136 /* close the file handle associated */
137 self->system->close(hdr_p->fh);
138
139 /* free the memory associated */
140 self->system->free(hdr);
141
142 self->error = MSPACK_ERR_OK;
143}
144
145/***************************************
146 * KWAJD_READ_HEADERS
147 ***************************************
148 * reads the headers of a KWAJ format file
149 */
150static int kwajd_read_headers(struct mspack_system *sys,
151 struct mspack_file *fh,
152 struct mskwajd_header *hdr)
153{
154 unsigned char buf[16];
155 int i;
156
157 /* read in the header */
158 if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) {
159 return MSPACK_ERR_READ;
160 }
161
162 /* check for "KWAJ" signature */
163 if (((unsigned int) EndGetI32(&buf[kwajh_Signature1]) != 0x4A41574B) ||
164 ((unsigned int) EndGetI32(&buf[kwajh_Signature2]) != 0xD127F088))
165 {
166 return MSPACK_ERR_SIGNATURE;
167 }
168
169 /* basic header fields */
170 hdr->comp_type = EndGetI16(&buf[kwajh_CompMethod]);
171 hdr->data_offset = EndGetI16(&buf[kwajh_DataOffset]);
172 hdr->headers = EndGetI16(&buf[kwajh_Flags]);
173 hdr->length = 0;
174 hdr->filename = NULL;
175 hdr->extra = NULL;
176 hdr->extra_length = 0;
177
178 /* optional headers */
179
180 /* 4 bytes: length of unpacked file */
181 if (hdr->headers & MSKWAJ_HDR_HASLENGTH) {
182 if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
183 hdr->length = EndGetI32(&buf[0]);
184 }
185
186 /* 2 bytes: unknown purpose */
187 if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN1) {
188 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
189 }
190
191 /* 2 bytes: length of section, then [length] bytes: unknown purpose */
192 if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) {
193 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
194 i = EndGetI16(&buf[0]);
195 if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK;
196 }
197
198 /* filename and extension */
199 if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
200 off_t pos = sys->tell(fh);
201 char *fn = (char *) sys->alloc(sys, (size_t) 13);
202
203 /* allocate memory for maximum length filename */
204 if (! fn) return MSPACK_ERR_NOMEMORY;
205 hdr->filename = fn;
206
207 /* copy filename if present */
208 if (hdr->headers & MSKWAJ_HDR_HASFILENAME) {
209 if (sys->read(fh, &buf[0], 9) != 9) return MSPACK_ERR_READ;
210 for (i = 0; i < 9; i++, fn++) if (!(*fn = buf[i])) break;
211 pos += (i < 9) ? i+1 : 9;
212 if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START))
213 return MSPACK_ERR_SEEK;
214 }
215
216 /* copy extension if present */
217 if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) {
218 *fn++ = '.';
219 if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
220 for (i = 0; i < 4; i++, fn++) if (!(*fn = buf[i])) break;
221 pos += (i < 4) ? i+1 : 4;
222 if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START))
223 return MSPACK_ERR_SEEK;
224 }
225 *fn = '\0';
226 }
227
228 /* 2 bytes: extra text length then [length] bytes of extra text data */
229 if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) {
230 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
231 i = EndGetI16(&buf[0]);
232 hdr->extra = (char *) sys->alloc(sys, (size_t)i+1);
233 if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
234 if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
235 hdr->extra[i] = '\0';
236 hdr->extra_length = i;
237 }
238 return MSPACK_ERR_OK;
239}
240
241/***************************************
242 * KWAJD_EXTRACT
243 ***************************************
244 * decompresses a KWAJ file
245 */
246static int kwajd_extract(struct mskwaj_decompressor *base,
247 struct mskwajd_header *hdr, const char *filename)
248{
249 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
250 struct mspack_system *sys;
251 struct mspack_file *fh, *outfh;
252
253 if (!self) return MSPACK_ERR_ARGS;
254 if (!hdr) return self->error = MSPACK_ERR_ARGS;
255
256 sys = self->system;
257 fh = ((struct mskwajd_header_p *) hdr)->fh;
258
259 /* seek to the compressed data */
260 if (sys->seek(fh, hdr->data_offset, MSPACK_SYS_SEEK_START)) {
261 return self->error = MSPACK_ERR_SEEK;
262 }
263
264 /* open file for output */
265 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
266 return self->error = MSPACK_ERR_OPEN;
267 }
268
269 self->error = MSPACK_ERR_OK;
270
271 /* decompress based on format */
272 if (hdr->comp_type == MSKWAJ_COMP_NONE ||
273 hdr->comp_type == MSKWAJ_COMP_XOR)
274 {
275 /* NONE is a straight copy. XOR is a copy xored with 0xFF */
276 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE);
277 if (buf) {
278 int read, i;
279 while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
280 if (hdr->comp_type == MSKWAJ_COMP_XOR) {
281 for (i = 0; i < read; i++) buf[i] ^= 0xFF;
282 }
283 if (sys->write(outfh, buf, read) != read) {
284 self->error = MSPACK_ERR_WRITE;
285 break;
286 }
287 }
288 if (read < 0) self->error = MSPACK_ERR_READ;
289 sys->free(buf);
290 }
291 else {
292 self->error = MSPACK_ERR_NOMEMORY;
293 }
294 }
295 else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
296 self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
297 LZSS_MODE_EXPAND);
298 }
299 else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
300 struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
301 self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY;
302 lzh_free(lzh);
303 }
304 else {
305 self->error = MSPACK_ERR_DATAFORMAT;
306 }
307
308 /* close output file */
309 sys->close(outfh);
310
311 return self->error;
312}
313
314/***************************************
315 * KWAJD_DECOMPRESS
316 ***************************************
317 * unpacks directly from input to output
318 */
319static int kwajd_decompress(struct mskwaj_decompressor *base,
320 const char *input, const char *output)
321{
322 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
323 struct mskwajd_header *hdr;
324 int error;
325
326 if (!self) return MSPACK_ERR_ARGS;
327
328 if (!(hdr = kwajd_open(base, input))) return self->error;
329 error = kwajd_extract(base, hdr, output);
330 kwajd_close(base, hdr);
331 return self->error = error;
332}
333
334/***************************************
335 * KWAJD_ERROR
336 ***************************************
337 * returns the last error that occurred
338 */
339static int kwajd_error(struct mskwaj_decompressor *base)
340{
341 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
342 return (self) ? self->error : MSPACK_ERR_ARGS;
343}
344
345/***************************************
346 * LZH_INIT, LZH_DECOMPRESS, LZH_FREE
347 ***************************************
348 * unpacks KWAJ method 3 files
349 */
350
351/* import bit-reading macros and code */
352#define BITS_TYPE struct kwajd_stream
353#define BITS_VAR lzh
354#define BITS_ORDER_MSB
355#define BITS_NO_READ_INPUT
356#define READ_BYTES do { \
357 if (i_ptr >= i_end) { \
358 if ((err = lzh_read_input(lzh))) return err; \
359 i_ptr = lzh->i_ptr; \
360 i_end = lzh->i_end; \
361 } \
362 INJECT_BITS(*i_ptr++, 8); \
363} while (0)
364#include <readbits.h>
365
366/* import huffman-reading macros and code */
367#define TABLEBITS(tbl) KWAJ_TABLEBITS
368#define MAXSYMBOLS(tbl) KWAJ_##tbl##_SYMS
369#define HUFF_TABLE(tbl,idx) lzh->tbl##_table[idx]
370#define HUFF_LEN(tbl,idx) lzh->tbl##_len[idx]
371#define HUFF_ERROR return MSPACK_ERR_DATAFORMAT
372#include <readhuff.h>
373
374/* In the KWAJ LZH format, there is no special 'eof' marker, it just
375 * ends. Depending on how many bits are left in the final byte when
376 * the stream ends, that might be enough to start another literal or
377 * match. The only easy way to detect that we've come to an end is to
378 * guard all bit-reading. We allow fake bits to be read once we reach
379 * the end of the stream, but we check if we then consumed any of
380 * those fake bits, after doing the READ_BITS / READ_HUFFSYM. This
381 * isn't how the default readbits.h read_input() works (it simply lets
382 * 2 fake bytes in then stops), so we implement our own.
383 */
384#define READ_BITS_SAFE(val, n) do { \
385 READ_BITS(val, n); \
386 if (lzh->input_end && bits_left < lzh->input_end) \
387 return MSPACK_ERR_OK; \
388} while (0)
389
390#define READ_HUFFSYM_SAFE(tbl, val) do { \
391 READ_HUFFSYM(tbl, val); \
392 if (lzh->input_end && bits_left < lzh->input_end) \
393 return MSPACK_ERR_OK; \
394} while (0)
395
396#define BUILD_TREE(tbl, type) \
397 STORE_BITS; \
398 err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), \
399 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0)); \
400 if (err) return err; \
401 RESTORE_BITS; \
402 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
403 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
404 return MSPACK_ERR_DATAFORMAT;
405
406#define WRITE_BYTE do { \
407 if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \
408 return MSPACK_ERR_WRITE; \
409} while (0)
410
411static struct kwajd_stream *lzh_init(struct mspack_system *sys,
412 struct mspack_file *in, struct mspack_file *out)
413{
414 struct kwajd_stream *lzh;
415
416 if (!sys || !in || !out) return NULL;
417 if (!(lzh = (struct kwajd_stream *) sys->alloc(sys, sizeof(struct kwajd_stream)))) return NULL;
418
419 lzh->sys = sys;
420 lzh->input = in;
421 lzh->output = out;
422 return lzh;
423}
424
425static int lzh_decompress(struct kwajd_stream *lzh)
426{
427 register unsigned int bit_buffer;
428 register int bits_left, i;
429 register unsigned short sym;
430 unsigned char *i_ptr, *i_end, lit_run = 0;
431 int j, pos = 0, len, offset, err;
432 unsigned int types[6];
433
434 /* reset global state */
435 INIT_BITS;
436 RESTORE_BITS;
437 memset(&lzh->window[0], LZSS_WINDOW_FILL, (size_t) LZSS_WINDOW_SIZE);
438
439 /* read 6 encoding types (for byte alignment) but only 5 are needed */
440 for (i = 0; i < 6; i++) READ_BITS_SAFE(types[i], 4);
441
442 /* read huffman table symbol lengths and build huffman trees */
443 BUILD_TREE(MATCHLEN1, types[0]);
444 BUILD_TREE(MATCHLEN2, types[1]);
445 BUILD_TREE(LITLEN, types[2]);
446 BUILD_TREE(OFFSET, types[3]);
447 BUILD_TREE(LITERAL, types[4]);
448
449 while (!lzh->input_end) {
450 if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len);
451 else READ_HUFFSYM_SAFE(MATCHLEN1, len);
452
453 if (len > 0) {
454 len += 2;
455 lit_run = 0; /* not the end of a literal run */
456 READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6;
457 READ_BITS_SAFE(j, 6); offset |= j;
458
459 /* copy match as output and into the ring buffer */
460 while (len-- > 0) {
461 lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095];
462 WRITE_BYTE;
463 pos++; pos &= 4095;
464 }
465 }
466 else {
467 READ_HUFFSYM_SAFE(LITLEN, len); len++;
468 lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */
469 while (len-- > 0) {
470 READ_HUFFSYM_SAFE(LITERAL, j);
471 /* copy as output and into the ring buffer */
472 lzh->window[pos] = j;
473 WRITE_BYTE;
474 pos++; pos &= 4095;
475 }
476 }
477 }
478 return MSPACK_ERR_OK;
479}
480
481static void lzh_free(struct kwajd_stream *lzh)
482{
483 struct mspack_system *sys;
484 if (!lzh || !lzh->sys) return;
485 sys = lzh->sys;
486 sys->free(lzh);
487}
488
489static int lzh_read_lens(struct kwajd_stream *lzh,
490 unsigned int type, unsigned int numsyms,
491 unsigned char *lens, unsigned short *table)
492{
493 register unsigned int bit_buffer;
494 register int bits_left;
495 unsigned char *i_ptr, *i_end;
496 unsigned int i, c, sel;
497 int err;
498
499 RESTORE_BITS;
500 switch (type) {
501 case 0:
502 i = numsyms; c = (i==16)?4: (i==32)?5: (i==64)?6: (i==256)?8 :0;
503 for (i = 0; i < numsyms; i++) lens[i] = c;
504 break;
505
506 case 1:
507 READ_BITS_SAFE(c, 4); lens[0] = c;
508 for (i = 1; i < numsyms; i++) {
509 READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = c;
510 else { READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = ++c;
511 else { READ_BITS_SAFE(c, 4); lens[i] = c; }}
512 }
513 break;
514
515 case 2:
516 READ_BITS_SAFE(c, 4); lens[0] = c;
517 for (i = 1; i < numsyms; i++) {
518 READ_BITS_SAFE(sel, 2);
519 if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1;
520 lens[i] = c;
521 }
522 break;
523
524 case 3:
525 for (i = 0; i < numsyms; i++) {
526 READ_BITS_SAFE(c, 4); lens[i] = c;
527 }
528 break;
529 }
530 STORE_BITS;
531 return MSPACK_ERR_OK;
532}
533
534static int lzh_read_input(struct kwajd_stream *lzh) {
535 int read;
536 if (lzh->input_end) {
537 lzh->input_end += 8;
538 lzh->inbuf[0] = 0;
539 read = 1;
540 }
541 else {
542 read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE);
543 if (read < 0) return MSPACK_ERR_READ;
544 if (read == 0) {
545 lzh->input_end = 8;
546 lzh->inbuf[0] = 0;
547 read = 1;
548 }
549 }
550
551 /* update i_ptr and i_end */
552 lzh->i_ptr = &lzh->inbuf[0];
553 lzh->i_end = &lzh->inbuf[read];
554 return MSPACK_ERR_OK;
555}
diff --git a/rbutil/rbutilqt/mspack/lit.h b/rbutil/rbutilqt/mspack/lit.h
new file mode 100644
index 0000000000..79ba44d877
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/lit.h
@@ -0,0 +1,35 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_LIT_H
11#define MSPACK_LIT_H 1
12
13#include <lzx.h>
14#include <des.h>
15#include <sha.h>
16
17/* generic LIT definitions */
18
19/* LIT compression definitions */
20
21struct mslit_compressor_p {
22 struct mslit_compressor base;
23 struct mspack_system *system;
24 /* todo */
25};
26
27/* LIT decompression definitions */
28
29struct mslit_decompressor_p {
30 struct mslit_decompressor base;
31 struct mspack_system *system;
32 /* todo */
33};
34
35#endif
diff --git a/rbutil/rbutilqt/mspack/litc.c b/rbutil/rbutilqt/mspack/litc.c
new file mode 100644
index 0000000000..a8a709af07
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/litc.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* LIT compression implementation */
11
12#include <system.h>
13#include <lit.h>
14
15struct mslit_compressor *
16 mspack_create_lit_compressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_lit_compressor(struct mslit_compressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/litd.c b/rbutil/rbutilqt/mspack/litd.c
new file mode 100644
index 0000000000..6e0dc9af27
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/litd.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* LIT decompression implementation */
11
12#include <system.h>
13#include <lit.h>
14
15struct mslit_decompressor *
16 mspack_create_lit_decompressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_lit_decompressor(struct mslit_decompressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/lzss.h b/rbutil/rbutilqt/mspack/lzss.h
new file mode 100644
index 0000000000..55e761b5bf
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/lzss.h
@@ -0,0 +1,66 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_LZSS_H
11#define MSPACK_LZSS_H 1
12
13#ifdef __cplusplus
14extern "C" {
15#endif
16
17/* LZSS compression / decompression definitions */
18
19#define LZSS_WINDOW_SIZE (4096)
20#define LZSS_WINDOW_FILL (0x20)
21
22#define LZSS_MODE_EXPAND (0)
23#define LZSS_MODE_MSHELP (1)
24#define LZSS_MODE_QBASIC (2)
25
26/**
27 * Decompresses an LZSS stream.
28 *
29 * Input bytes will be read in as necessary using the system->read()
30 * function with the input file handle given. This will continue until
31 * system->read() returns 0 bytes, or an error. Errors will be passed
32 * out of the function as MSPACK_ERR_READ errors. Input streams should
33 * convey an "end of input stream" by refusing to supply all the bytes
34 * that LZSS asks for when they reach the end of the stream, rather
35 * than return an error code.
36 *
37 * Output bytes will be passed to the system->write() function, using
38 * the output file handle given. More than one call may be made to
39 * system->write().
40 *
41 * As EXPAND.EXE (SZDD/KWAJ), Microsoft Help and QBasic have slightly
42 * different encodings for the control byte and matches, a "mode"
43 * parameter is allowed, to choose the encoding.
44 *
45 * @param system an mspack_system structure used to read from
46 * the input stream and write to the output
47 * stream, also to allocate and free memory.
48 * @param input an input stream with the LZSS data.
49 * @param output an output stream to write the decoded data to.
50 * @param input_buffer_size the number of bytes to use as an input
51 * bitstream buffer.
52 * @param mode one of #LZSS_MODE_EXPAND, #LZSS_MODE_MSHELP or
53 * #LZSS_MODE_QBASIC
54 * @return an error code, or MSPACK_ERR_OK if successful
55 */
56extern int lzss_decompress(struct mspack_system *system,
57 struct mspack_file *input,
58 struct mspack_file *output,
59 int input_buffer_size,
60 int mode);
61
62#ifdef __cplusplus
63}
64#endif
65
66#endif
diff --git a/rbutil/rbutilqt/mspack/lzssd.c b/rbutil/rbutilqt/mspack/lzssd.c
new file mode 100644
index 0000000000..df294bc132
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/lzssd.c
@@ -0,0 +1,93 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * LZSS is a derivative of LZ77 and was created by James Storer and
5 * Thomas Szymanski in 1982. Haruhiko Okumura wrote a very popular C
6 * implementation.
7 *
8 * libmspack is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
10 *
11 * For further details, see the file COPYING.LIB distributed with libmspack
12 */
13
14#include <system.h>
15#include <lzss.h>
16
17#define ENSURE_BYTES do { \
18 if (i_ptr >= i_end) { \
19 read = system->read(input, &inbuf[0], \
20 input_buffer_size); \
21 if (read <= 0) { \
22 system->free(window); \
23 return (read < 0) ? MSPACK_ERR_READ \
24 : MSPACK_ERR_OK; \
25 } \
26 i_ptr = &inbuf[0]; i_end = &inbuf[read]; \
27 } \
28} while (0)
29
30#define WRITE_BYTE do { \
31 if (system->write(output, &window[pos], 1) != 1) { \
32 system->free(window); \
33 return MSPACK_ERR_WRITE; \
34 } \
35} while (0)
36
37int lzss_decompress(struct mspack_system *system,
38 struct mspack_file *input,
39 struct mspack_file *output,
40 int input_buffer_size,
41 int mode)
42{
43 unsigned char *window, *inbuf, *i_ptr, *i_end;
44 unsigned int pos, i, c, invert, mpos, len;
45 int read;
46
47 /* check parameters */
48 if (!system || input_buffer_size < 1 || (mode != LZSS_MODE_EXPAND &&
49 mode != LZSS_MODE_MSHELP && mode != LZSS_MODE_QBASIC))
50 {
51 return MSPACK_ERR_ARGS;
52 }
53
54 /* allocate memory */
55 window = (unsigned char *) system->alloc(system, LZSS_WINDOW_SIZE + input_buffer_size);
56 if (!window) return MSPACK_ERR_NOMEMORY;
57
58 /* initialise decompression */
59 inbuf = &window[LZSS_WINDOW_SIZE];
60 memset(window, LZSS_WINDOW_FILL, (size_t) LZSS_WINDOW_SIZE);
61 pos = LZSS_WINDOW_SIZE - ((mode == LZSS_MODE_QBASIC) ? 18 : 16);
62 invert = (mode == LZSS_MODE_MSHELP) ? ~0 : 0;
63 i_ptr = i_end = &inbuf[0];
64
65 /* loop forever; exit condition is in ENSURE_BYTES macro */
66 for (;;) {
67 ENSURE_BYTES; c = *i_ptr++ ^ invert;
68 for (i = 0x01; i & 0xFF; i <<= 1) {
69 if (c & i) {
70 /* literal */
71 ENSURE_BYTES; window[pos] = *i_ptr++;
72 WRITE_BYTE;
73 pos++; pos &= LZSS_WINDOW_SIZE - 1;
74 }
75 else {
76 /* match */
77 ENSURE_BYTES; mpos = *i_ptr++;
78 ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4;
79 len = (*i_ptr++ & 0x0F) + 3;
80 while (len--) {
81 window[pos] = window[mpos];
82 WRITE_BYTE;
83 pos++; pos &= LZSS_WINDOW_SIZE - 1;
84 mpos++; mpos &= LZSS_WINDOW_SIZE - 1;
85 }
86 }
87 }
88 }
89
90 /* not reached */
91 system->free(window);
92 return MSPACK_ERR_OK;
93}
diff --git a/rbutil/rbutilqt/mspack/lzx.h b/rbutil/rbutilqt/mspack/lzx.h
new file mode 100644
index 0000000000..fc69928c96
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/lzx.h
@@ -0,0 +1,194 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
5 * by Microsoft Corporation.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13#ifndef MSPACK_LZX_H
14#define MSPACK_LZX_H 1
15
16#ifdef __cplusplus
17extern "C" {
18#endif
19
20/* LZX compression / decompression definitions */
21
22/* some constants defined by the LZX specification */
23#define LZX_MIN_MATCH (2)
24#define LZX_MAX_MATCH (257)
25#define LZX_NUM_CHARS (256)
26#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
27#define LZX_BLOCKTYPE_VERBATIM (1)
28#define LZX_BLOCKTYPE_ALIGNED (2)
29#define LZX_BLOCKTYPE_UNCOMPRESSED (3)
30#define LZX_PRETREE_NUM_ELEMENTS (20)
31#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
32#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
33#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
34
35/* LZX huffman defines: tweak tablebits as desired */
36#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
37#define LZX_PRETREE_TABLEBITS (6)
38#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
39#define LZX_MAINTREE_TABLEBITS (12)
40#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
41#define LZX_LENGTH_TABLEBITS (12)
42#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
43#define LZX_ALIGNED_TABLEBITS (7)
44#define LZX_LENTABLE_SAFETY (64) /* table decoding overruns are allowed */
45
46#define LZX_FRAME_SIZE (32768) /* the size of a frame in LZX */
47
48struct lzxd_stream {
49 struct mspack_system *sys; /* I/O routines */
50 struct mspack_file *input; /* input file handle */
51 struct mspack_file *output; /* output file handle */
52
53 off_t offset; /* number of bytes actually output */
54 off_t length; /* overall decompressed length of stream */
55
56 unsigned char *window; /* decoding window */
57 unsigned int window_size; /* window size */
58 unsigned int window_posn; /* decompression offset within window */
59 unsigned int frame_posn; /* current frame offset within in window */
60 unsigned int frame; /* the number of 32kb frames processed */
61 unsigned int reset_interval; /* which frame do we reset the compressor? */
62
63 unsigned int R0, R1, R2; /* for the LRU offset system */
64 unsigned int block_length; /* uncompressed length of this LZX block */
65 unsigned int block_remaining; /* uncompressed bytes still left to decode */
66
67 signed int intel_filesize; /* magic header value used for transform */
68 signed int intel_curpos; /* current offset in transform space */
69
70 unsigned char intel_started; /* has intel E8 decoding started? */
71 unsigned char block_type; /* type of the current block */
72 unsigned char header_read; /* have we started decoding at all yet? */
73 unsigned char posn_slots; /* how many posn slots in stream? */
74 unsigned char input_end; /* have we reached the end of input? */
75
76 int error;
77
78 /* I/O buffering */
79 unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
80 unsigned int bit_buffer, bits_left, inbuf_size;
81
82 /* huffman code lengths */
83 unsigned char PRETREE_len [LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
84 unsigned char MAINTREE_len [LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
85 unsigned char LENGTH_len [LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
86 unsigned char ALIGNED_len [LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
87
88 /* huffman decoding tables */
89 unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
90 (LZX_PRETREE_MAXSYMBOLS * 2)];
91 unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
92 (LZX_MAINTREE_MAXSYMBOLS * 2)];
93 unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
94 (LZX_LENGTH_MAXSYMBOLS * 2)];
95 unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
96 (LZX_ALIGNED_MAXSYMBOLS * 2)];
97 unsigned char LENGTH_empty;
98
99 /* this is used purely for doing the intel E8 transform */
100 unsigned char e8_buf[LZX_FRAME_SIZE];
101};
102
103/**
104 * Allocates and initialises LZX decompression state for decoding an LZX
105 * stream.
106 *
107 * This routine uses system->alloc() to allocate memory. If memory
108 * allocation fails, or the parameters to this function are invalid,
109 * NULL is returned.
110 *
111 * @param system an mspack_system structure used to read from
112 * the input stream and write to the output
113 * stream, also to allocate and free memory.
114 * @param input an input stream with the LZX data.
115 * @param output an output stream to write the decoded data to.
116 * @param window_bits the size of the decoding window, which must be
117 * between 15 and 21 inclusive.
118 * @param reset_interval the interval at which the LZX bitstream is
119 * reset, in multiples of LZX frames (32678
120 * bytes), e.g. a value of 2 indicates the input
121 * stream resets after every 65536 output bytes.
122 * A value of 0 indicates that the bistream never
123 * resets, such as in CAB LZX streams.
124 * @param input_buffer_size the number of bytes to use as an input
125 * bitstream buffer.
126 * @param output_length the length in bytes of the entirely
127 * decompressed output stream, if known in
128 * advance. It is used to correctly perform the
129 * Intel E8 transformation, which must stop 6
130 * bytes before the very end of the
131 * decompressed stream. It is not otherwise used
132 * or adhered to. If the full decompressed
133 * length is known in advance, set it here.
134 * If it is NOT known, use the value 0, and call
135 * lzxd_set_output_length() once it is
136 * known. If never set, 4 of the final 6 bytes
137 * of the output stream may be incorrect.
138 * @return a pointer to an initialised lzxd_stream structure, or NULL if
139 * there was not enough memory or parameters to the function were wrong.
140 */
141extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
142 struct mspack_file *input,
143 struct mspack_file *output,
144 int window_bits,
145 int reset_interval,
146 int input_buffer_size,
147 off_t output_length);
148
149/* see description of output_length in lzxd_init() */
150extern void lzxd_set_output_length(struct lzxd_stream *lzx,
151 off_t output_length);
152
153/**
154 * Decompresses entire or partial LZX streams.
155 *
156 * The number of bytes of data that should be decompressed is given as the
157 * out_bytes parameter. If more bytes are decoded than are needed, they
158 * will be kept over for a later invocation.
159 *
160 * The output bytes will be passed to the system->write() function given in
161 * lzxd_init(), using the output file handle given in lzxd_init(). More than
162 * one call may be made to system->write().
163
164 * Input bytes will be read in as necessary using the system->read()
165 * function given in lzxd_init(), using the input file handle given in
166 * lzxd_init(). This will continue until system->read() returns 0 bytes,
167 * or an error. Errors will be passed out of the function as
168 * MSPACK_ERR_READ errors. Input streams should convey an "end of input
169 * stream" by refusing to supply all the bytes that LZX asks for when they
170 * reach the end of the stream, rather than return an error code.
171 *
172 * If any error code other than MSPACK_ERR_OK is returned, the stream
173 * should be considered unusable and lzxd_decompress() should not be
174 * called again on this stream.
175 *
176 * @param lzx LZX decompression state, as allocated by lzxd_init().
177 * @param out_bytes the number of bytes of data to decompress.
178 * @return an error code, or MSPACK_ERR_OK if successful
179 */
180extern int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes);
181
182/**
183 * Frees all state associated with an LZX data stream. This will call
184 * system->free() using the system pointer given in lzxd_init().
185 *
186 * @param lzx LZX decompression state to free.
187 */
188void lzxd_free(struct lzxd_stream *lzx);
189
190#ifdef __cplusplus
191}
192#endif
193
194#endif
diff --git a/rbutil/rbutilqt/mspack/lzxc.c b/rbutil/rbutilqt/mspack/lzxc.c
new file mode 100644
index 0000000000..1207a0d747
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/lzxc.c
@@ -0,0 +1,18 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
5 * by Microsoft Corporation.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13/* LZX compression implementation */
14
15#include <system.h>
16#include <lzx.h>
17
18/* todo */
diff --git a/rbutil/rbutilqt/mspack/lzxd.c b/rbutil/rbutilqt/mspack/lzxd.c
new file mode 100644
index 0000000000..cebc4c23d3
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/lzxd.c
@@ -0,0 +1,738 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
5 * by Microsoft Corporation.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13/* LZX decompression implementation */
14
15#include <system.h>
16#include <lzx.h>
17
18/* Microsoft's LZX document (in cab-sdk.exe) and their implementation
19 * of the com.ms.util.cab Java package do not concur.
20 *
21 * In the LZX document, there is a table showing the correlation between
22 * window size and the number of position slots. It states that the 1MB
23 * window = 40 slots and the 2MB window = 42 slots. In the implementation,
24 * 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the
25 * first slot whose position base is equal to or more than the required
26 * window size'. This would explain why other tables in the document refer
27 * to 50 slots rather than 42.
28 *
29 * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
30 * is not defined in the specification.
31 *
32 * The LZX document does not state the uncompressed block has an
33 * uncompressed length field. Where does this length field come from, so
34 * we can know how large the block is? The implementation has it as the 24
35 * bits following after the 3 blocktype bits, before the alignment
36 * padding.
37 *
38 * The LZX document states that aligned offset blocks have their aligned
39 * offset huffman tree AFTER the main and length trees. The implementation
40 * suggests that the aligned offset tree is BEFORE the main and length
41 * trees.
42 *
43 * The LZX document decoding algorithm states that, in an aligned offset
44 * block, if an extra_bits value is 1, 2 or 3, then that number of bits
45 * should be read and the result added to the match offset. This is
46 * correct for 1 and 2, but not 3, where just a huffman symbol (using the
47 * aligned tree) should be read.
48 *
49 * Regarding the E8 preprocessing, the LZX document states 'No translation
50 * may be performed on the last 6 bytes of the input block'. This is
51 * correct. However, the pseudocode provided checks for the *E8 leader*
52 * up to the last 6 bytes. If the leader appears between -10 and -7 bytes
53 * from the end, this would cause the next four bytes to be modified, at
54 * least one of which would be in the last 6 bytes, which is not allowed
55 * according to the spec.
56 *
57 * The specification states that the huffman trees must always contain at
58 * least one element. However, many CAB files contain blocks where the
59 * length tree is completely empty (because there are no matches), and
60 * this is expected to succeed.
61 *
62 * The errors in LZX documentation appear have been corrected in the
63 * new documentation for the LZX DELTA format.
64 *
65 * http://msdn.microsoft.com/en-us/library/cc483133.aspx
66 *
67 * However, this is a different format, an extension of regular LZX.
68 * I have noticed the following differences, there may be more:
69 *
70 * The maximum window size has increased from 2MB to 32MB. This also
71 * increases the maximum number of position slots, etc.
72 *
73 * The format now allows for "reference data", supplied by the caller.
74 * If match offsets go further back than the number of bytes
75 * decompressed so far, that is them accessing the reference data.
76 */
77
78/* import bit-reading macros and code */
79#define BITS_TYPE struct lzxd_stream
80#define BITS_VAR lzx
81#define BITS_ORDER_MSB
82#define READ_BYTES do { \
83 unsigned char b0, b1; \
84 READ_IF_NEEDED; b0 = *i_ptr++; \
85 READ_IF_NEEDED; b1 = *i_ptr++; \
86 INJECT_BITS((b1 << 8) | b0, 16); \
87} while (0)
88#include <readbits.h>
89
90/* import huffman-reading macros and code */
91#define TABLEBITS(tbl) LZX_##tbl##_TABLEBITS
92#define MAXSYMBOLS(tbl) LZX_##tbl##_MAXSYMBOLS
93#define HUFF_TABLE(tbl,idx) lzx->tbl##_table[idx]
94#define HUFF_LEN(tbl,idx) lzx->tbl##_len[idx]
95#define HUFF_ERROR return lzx->error = MSPACK_ERR_DECRUNCH
96#include <readhuff.h>
97
98/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
99#define BUILD_TABLE(tbl) \
100 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
101 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
102 { \
103 D(("failed to build %s table", #tbl)) \
104 return lzx->error = MSPACK_ERR_DECRUNCH; \
105 }
106
107#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
108 lzx->tbl##_empty = 0; \
109 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
110 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
111 { \
112 for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
113 if (HUFF_LEN(tbl, i) > 0) { \
114 D(("failed to build %s table", #tbl)) \
115 return lzx->error = MSPACK_ERR_DECRUNCH; \
116 } \
117 } \
118 /* empty tree - allow it, but don't decode symbols with it */ \
119 lzx->tbl##_empty = 1; \
120 } \
121} while (0)
122
123/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
124 * first to last in the given table. The code lengths are stored in their
125 * own special LZX way.
126 */
127#define READ_LENGTHS(tbl, first, last) do { \
128 STORE_BITS; \
129 if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
130 (unsigned int)(last))) return lzx->error; \
131 RESTORE_BITS; \
132} while (0)
133
134static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
135 unsigned int first, unsigned int last)
136{
137 /* bit buffer and huffman symbol decode variables */
138 register unsigned int bit_buffer;
139 register int bits_left, i;
140 register unsigned short sym;
141 unsigned char *i_ptr, *i_end;
142
143 unsigned int x, y;
144 int z;
145
146 RESTORE_BITS;
147
148 /* read lengths for pretree (20 symbols, lengths stored in fixed 4 bits) */
149 for (x = 0; x < 20; x++) {
150 READ_BITS(y, 4);
151 lzx->PRETREE_len[x] = y;
152 }
153 BUILD_TABLE(PRETREE);
154
155 for (x = first; x < last; ) {
156 READ_HUFFSYM(PRETREE, z);
157 if (z == 17) {
158 /* code = 17, run of ([read 4 bits]+4) zeros */
159 READ_BITS(y, 4); y += 4;
160 while (y--) lens[x++] = 0;
161 }
162 else if (z == 18) {
163 /* code = 18, run of ([read 5 bits]+20) zeros */
164 READ_BITS(y, 5); y += 20;
165 while (y--) lens[x++] = 0;
166 }
167 else if (z == 19) {
168 /* code = 19, run of ([read 1 bit]+4) [read huffman symbol] */
169 READ_BITS(y, 1); y += 4;
170 READ_HUFFSYM(PRETREE, z);
171 z = lens[x] - z; if (z < 0) z += 17;
172 while (y--) lens[x++] = z;
173 }
174 else {
175 /* code = 0 to 16, delta current length entry */
176 z = lens[x] - z; if (z < 0) z += 17;
177 lens[x++] = z;
178 }
179 }
180
181 STORE_BITS;
182
183 return MSPACK_ERR_OK;
184}
185
186/* LZX static data tables:
187 *
188 * LZX uses 'position slots' to represent match offsets. For every match,
189 * a small 'position slot' number and a small offset from that slot are
190 * encoded instead of one large offset.
191 *
192 * position_base[] is an index to the position slot bases
193 *
194 * extra_bits[] states how many bits of offset-from-base data is needed.
195 *
196 * They are generated like so:
197 * for (i = 0; i < 4; i++) extra_bits[i] = 0;
198 * for (i = 4, j = 0; i < 36; i+=2) extra_bits[i] = extra_bits[i+1] = j++;
199 * for (i = 36; i < 51; i++) extra_bits[i] = 17;
200 * for (i = 0, j = 0; i < 51; j += 1 << extra_bits[i++]) position_base[i] = j;
201 */
202static const unsigned int position_base[51] = {
203 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256,
204 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288,
205 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144,
206 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720,
207 1441792, 1572864, 1703936, 1835008, 1966080, 2097152
208};
209static const unsigned char extra_bits[51] = {
210 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
211 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
212 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
213};
214
215static void lzxd_reset_state(struct lzxd_stream *lzx) {
216 int i;
217
218 lzx->R0 = 1;
219 lzx->R1 = 1;
220 lzx->R2 = 1;
221 lzx->header_read = 0;
222 lzx->block_remaining = 0;
223 lzx->block_type = LZX_BLOCKTYPE_INVALID;
224
225 /* initialise tables to 0 (because deltas will be applied to them) */
226 for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) lzx->MAINTREE_len[i] = 0;
227 for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) lzx->LENGTH_len[i] = 0;
228}
229
230/*-------- main LZX code --------*/
231
232struct lzxd_stream *lzxd_init(struct mspack_system *system,
233 struct mspack_file *input,
234 struct mspack_file *output,
235 int window_bits,
236 int reset_interval,
237 int input_buffer_size,
238 off_t output_length)
239{
240 unsigned int window_size = 1 << window_bits;
241 struct lzxd_stream *lzx;
242
243 if (!system) return NULL;
244
245 /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
246 if (window_bits < 15 || window_bits > 21) return NULL;
247
248 input_buffer_size = (input_buffer_size + 1) & -2;
249 if (!input_buffer_size) return NULL;
250
251 /* allocate decompression state */
252 if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) {
253 return NULL;
254 }
255
256 /* allocate decompression window and input buffer */
257 lzx->window = (unsigned char *) system->alloc(system, (size_t) window_size);
258 lzx->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
259 if (!lzx->window || !lzx->inbuf) {
260 system->free(lzx->window);
261 system->free(lzx->inbuf);
262 system->free(lzx);
263 return NULL;
264 }
265
266 /* initialise decompression state */
267 lzx->sys = system;
268 lzx->input = input;
269 lzx->output = output;
270 lzx->offset = 0;
271 lzx->length = output_length;
272
273 lzx->inbuf_size = input_buffer_size;
274 lzx->window_size = 1 << window_bits;
275 lzx->window_posn = 0;
276 lzx->frame_posn = 0;
277 lzx->frame = 0;
278 lzx->reset_interval = reset_interval;
279 lzx->intel_filesize = 0;
280 lzx->intel_curpos = 0;
281 lzx->intel_started = 0;
282 lzx->error = MSPACK_ERR_OK;
283
284 /* window bits: 15 16 17 18 19 20 21
285 * position slots: 30 32 34 36 38 42 50 */
286 lzx->posn_slots = ((window_bits == 21) ? 50 :
287 ((window_bits == 20) ? 42 : (window_bits << 1)));
288
289 lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
290 lzxd_reset_state(lzx);
291 INIT_BITS;
292 return lzx;
293}
294
295void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) {
296 if (lzx) lzx->length = out_bytes;
297}
298
299int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
300 /* bitstream and huffman reading variables */
301 register unsigned int bit_buffer;
302 register int bits_left, i=0;
303 unsigned char *i_ptr, *i_end;
304 register unsigned short sym;
305
306 int match_length, length_footer, extra, verbatim_bits, bytes_todo;
307 int this_run, main_element, aligned_bits, j;
308 unsigned char *window, *runsrc, *rundest, buf[12];
309 unsigned int frame_size=0, end_frame, match_offset, window_posn;
310 unsigned int R0, R1, R2;
311
312 /* easy answers */
313 if (!lzx || (out_bytes < 0)) return MSPACK_ERR_ARGS;
314 if (lzx->error) return lzx->error;
315
316 /* flush out any stored-up bytes before we begin */
317 i = lzx->o_end - lzx->o_ptr;
318 if ((off_t) i > out_bytes) i = (int) out_bytes;
319 if (i) {
320 if (lzx->sys->write(lzx->output, lzx->o_ptr, i) != i) {
321 return lzx->error = MSPACK_ERR_WRITE;
322 }
323 lzx->o_ptr += i;
324 lzx->offset += i;
325 out_bytes -= i;
326 }
327 if (out_bytes == 0) return MSPACK_ERR_OK;
328
329 /* restore local state */
330 RESTORE_BITS;
331 window = lzx->window;
332 window_posn = lzx->window_posn;
333 R0 = lzx->R0;
334 R1 = lzx->R1;
335 R2 = lzx->R2;
336
337 end_frame = (unsigned int)((lzx->offset + out_bytes) / LZX_FRAME_SIZE) + 1;
338
339 while (lzx->frame < end_frame) {
340 /* have we reached the reset interval? (if there is one?) */
341 if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
342 if (lzx->block_remaining) {
343 D(("%d bytes remaining at reset interval", lzx->block_remaining))
344 return lzx->error = MSPACK_ERR_DECRUNCH;
345 }
346
347 /* re-read the intel header and reset the huffman lengths */
348 lzxd_reset_state(lzx);
349 R0 = lzx->R0;
350 R1 = lzx->R1;
351 R2 = lzx->R2;
352 }
353
354 /* read header if necessary */
355 if (!lzx->header_read) {
356 /* read 1 bit. if bit=0, intel filesize = 0.
357 * if bit=1, read intel filesize (32 bits) */
358 j = 0; READ_BITS(i, 1); if (i) { READ_BITS(i, 16); READ_BITS(j, 16); }
359 lzx->intel_filesize = (i << 16) | j;
360 lzx->header_read = 1;
361 }
362
363 /* calculate size of frame: all frames are 32k except the final frame
364 * which is 32kb or less. this can only be calculated when lzx->length
365 * has been filled in. */
366 frame_size = LZX_FRAME_SIZE;
367 if (lzx->length && (lzx->length - lzx->offset) < (off_t)frame_size) {
368 frame_size = lzx->length - lzx->offset;
369 }
370
371 /* decode until one more frame is available */
372 bytes_todo = lzx->frame_posn + frame_size - window_posn;
373 while (bytes_todo > 0) {
374 /* initialise new block, if one is needed */
375 if (lzx->block_remaining == 0) {
376 /* realign if previous block was an odd-sized UNCOMPRESSED block */
377 if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
378 (lzx->block_length & 1))
379 {
380 READ_IF_NEEDED;
381 i_ptr++;
382 }
383
384 /* read block type (3 bits) and block length (24 bits) */
385 READ_BITS(lzx->block_type, 3);
386 READ_BITS(i, 16); READ_BITS(j, 8);
387 lzx->block_remaining = lzx->block_length = (i << 8) | j;
388 /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
389
390 /* read individual block headers */
391 switch (lzx->block_type) {
392 case LZX_BLOCKTYPE_ALIGNED:
393 /* read lengths of and build aligned huffman decoding tree */
394 for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
395 BUILD_TABLE(ALIGNED);
396 /* no break -- rest of aligned header is same as verbatim */
397 case LZX_BLOCKTYPE_VERBATIM:
398 /* read lengths of and build main huffman decoding tree */
399 READ_LENGTHS(MAINTREE, 0, 256);
400 READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3));
401 BUILD_TABLE(MAINTREE);
402 /* if the literal 0xE8 is anywhere in the block... */
403 if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
404 /* read lengths of and build lengths huffman decoding tree */
405 READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
406 BUILD_TABLE_MAYBE_EMPTY(LENGTH);
407 break;
408
409 case LZX_BLOCKTYPE_UNCOMPRESSED:
410 /* because we can't assume otherwise */
411 lzx->intel_started = 1;
412
413 /* read 1-16 (not 0-15) bits to align to bytes */
414 ENSURE_BITS(16);
415 if (bits_left > 16) i_ptr -= 2;
416 bits_left = 0; bit_buffer = 0;
417
418 /* read 12 bytes of stored R0 / R1 / R2 values */
419 for (rundest = &buf[0], i = 0; i < 12; i++) {
420 READ_IF_NEEDED;
421 *rundest++ = *i_ptr++;
422 }
423 R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
424 R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
425 R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
426 break;
427
428 default:
429 D(("bad block type"))
430 return lzx->error = MSPACK_ERR_DECRUNCH;
431 }
432 }
433
434 /* decode more of the block:
435 * run = min(what's available, what's needed) */
436 this_run = lzx->block_remaining;
437 if (this_run > bytes_todo) this_run = bytes_todo;
438
439 /* assume we decode exactly this_run bytes, for now */
440 bytes_todo -= this_run;
441 lzx->block_remaining -= this_run;
442
443 /* decode at least this_run bytes */
444 switch (lzx->block_type) {
445 case LZX_BLOCKTYPE_VERBATIM:
446 while (this_run > 0) {
447 READ_HUFFSYM(MAINTREE, main_element);
448 if (main_element < LZX_NUM_CHARS) {
449 /* literal: 0 to LZX_NUM_CHARS-1 */
450 window[window_posn++] = main_element;
451 this_run--;
452 }
453 else {
454 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
455 main_element -= LZX_NUM_CHARS;
456
457 /* get match length */
458 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
459 if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
460 if (lzx->LENGTH_empty) {
461 D(("LENGTH symbol needed but tree is empty"))
462 return lzx->error = MSPACK_ERR_DECRUNCH;
463 }
464 READ_HUFFSYM(LENGTH, length_footer);
465 match_length += length_footer;
466 }
467 match_length += LZX_MIN_MATCH;
468
469 /* get match offset */
470 switch ((match_offset = (main_element >> 3))) {
471 case 0: match_offset = R0; break;
472 case 1: match_offset = R1; R1=R0; R0 = match_offset; break;
473 case 2: match_offset = R2; R2=R0; R0 = match_offset; break;
474 case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break;
475 default:
476 extra = extra_bits[match_offset];
477 READ_BITS(verbatim_bits, extra);
478 match_offset = position_base[match_offset] - 2 + verbatim_bits;
479 R2 = R1; R1 = R0; R0 = match_offset;
480 }
481
482 if ((window_posn + match_length) > lzx->window_size) {
483 D(("match ran over window wrap"))
484 return lzx->error = MSPACK_ERR_DECRUNCH;
485 }
486
487 /* copy match */
488 rundest = &window[window_posn];
489 i = match_length;
490 /* does match offset wrap the window? */
491 if (match_offset > window_posn) {
492 /* j = length from match offset to end of window */
493 j = match_offset - window_posn;
494 if (j > (int) lzx->window_size) {
495 D(("match offset beyond window boundaries"))
496 return lzx->error = MSPACK_ERR_DECRUNCH;
497 }
498 runsrc = &window[lzx->window_size - j];
499 if (j < i) {
500 /* if match goes over the window edge, do two copy runs */
501 i -= j; while (j-- > 0) *rundest++ = *runsrc++;
502 runsrc = window;
503 }
504 while (i-- > 0) *rundest++ = *runsrc++;
505 }
506 else {
507 runsrc = rundest - match_offset;
508 while (i-- > 0) *rundest++ = *runsrc++;
509 }
510
511 this_run -= match_length;
512 window_posn += match_length;
513 }
514 } /* while (this_run > 0) */
515 break;
516
517 case LZX_BLOCKTYPE_ALIGNED:
518 while (this_run > 0) {
519 READ_HUFFSYM(MAINTREE, main_element);
520 if (main_element < LZX_NUM_CHARS) {
521 /* literal: 0 to LZX_NUM_CHARS-1 */
522 window[window_posn++] = main_element;
523 this_run--;
524 }
525 else {
526 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
527 main_element -= LZX_NUM_CHARS;
528
529 /* get match length */
530 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
531 if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
532 if (lzx->LENGTH_empty) {
533 D(("LENGTH symbol needed but tree is empty"))
534 return lzx->error = MSPACK_ERR_DECRUNCH;
535 }
536 READ_HUFFSYM(LENGTH, length_footer);
537 match_length += length_footer;
538 }
539 match_length += LZX_MIN_MATCH;
540
541 /* get match offset */
542 switch ((match_offset = (main_element >> 3))) {
543 case 0: match_offset = R0; break;
544 case 1: match_offset = R1; R1 = R0; R0 = match_offset; break;
545 case 2: match_offset = R2; R2 = R0; R0 = match_offset; break;
546 default:
547 extra = extra_bits[match_offset];
548 match_offset = position_base[match_offset] - 2;
549 if (extra > 3) {
550 /* verbatim and aligned bits */
551 extra -= 3;
552 READ_BITS(verbatim_bits, extra);
553 match_offset += (verbatim_bits << 3);
554 READ_HUFFSYM(ALIGNED, aligned_bits);
555 match_offset += aligned_bits;
556 }
557 else if (extra == 3) {
558 /* aligned bits only */
559 READ_HUFFSYM(ALIGNED, aligned_bits);
560 match_offset += aligned_bits;
561 }
562 else if (extra > 0) { /* extra==1, extra==2 */
563 /* verbatim bits only */
564 READ_BITS(verbatim_bits, extra);
565 match_offset += verbatim_bits;
566 }
567 else /* extra == 0 */ {
568 /* ??? not defined in LZX specification! */
569 match_offset = 1;
570 }
571 /* update repeated offset LRU queue */
572 R2 = R1; R1 = R0; R0 = match_offset;
573 }
574
575 if ((window_posn + match_length) > lzx->window_size) {
576 D(("match ran over window wrap"))
577 return lzx->error = MSPACK_ERR_DECRUNCH;
578 }
579
580 /* copy match */
581 rundest = &window[window_posn];
582 i = match_length;
583 /* does match offset wrap the window? */
584 if (match_offset > window_posn) {
585 /* j = length from match offset to end of window */
586 j = match_offset - window_posn;
587 if (j > (int) lzx->window_size) {
588 D(("match offset beyond window boundaries"))
589 return lzx->error = MSPACK_ERR_DECRUNCH;
590 }
591 runsrc = &window[lzx->window_size - j];
592 if (j < i) {
593 /* if match goes over the window edge, do two copy runs */
594 i -= j; while (j-- > 0) *rundest++ = *runsrc++;
595 runsrc = window;
596 }
597 while (i-- > 0) *rundest++ = *runsrc++;
598 }
599 else {
600 runsrc = rundest - match_offset;
601 while (i-- > 0) *rundest++ = *runsrc++;
602 }
603
604 this_run -= match_length;
605 window_posn += match_length;
606 }
607 } /* while (this_run > 0) */
608 break;
609
610 case LZX_BLOCKTYPE_UNCOMPRESSED:
611 /* as this_run is limited not to wrap a frame, this also means it
612 * won't wrap the window (as the window is a multiple of 32k) */
613 rundest = &window[window_posn];
614 window_posn += this_run;
615 while (this_run > 0) {
616 if ((i = i_end - i_ptr) == 0) {
617 READ_IF_NEEDED;
618 }
619 else {
620 if (i > this_run) i = this_run;
621 lzx->sys->copy(i_ptr, rundest, (size_t) i);
622 rundest += i;
623 i_ptr += i;
624 this_run -= i;
625 }
626 }
627 break;
628
629 default:
630 return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */
631 }
632
633 /* did the final match overrun our desired this_run length? */
634 if (this_run < 0) {
635 if ((unsigned int)(-this_run) > lzx->block_remaining) {
636 D(("overrun went past end of block by %d (%d remaining)",
637 -this_run, lzx->block_remaining ))
638 return lzx->error = MSPACK_ERR_DECRUNCH;
639 }
640 lzx->block_remaining -= -this_run;
641 }
642 } /* while (bytes_todo > 0) */
643
644 /* streams don't extend over frame boundaries */
645 if ((window_posn - lzx->frame_posn) != frame_size) {
646 D(("decode beyond output frame limits! %d != %d",
647 window_posn - lzx->frame_posn, frame_size))
648 return lzx->error = MSPACK_ERR_DECRUNCH;
649 }
650
651 /* re-align input bitstream */
652 if (bits_left > 0) ENSURE_BITS(16);
653 if (bits_left & 15) REMOVE_BITS(bits_left & 15);
654
655 /* check that we've used all of the previous frame first */
656 if (lzx->o_ptr != lzx->o_end) {
657 D(("%ld avail bytes, new %d frame", lzx->o_end-lzx->o_ptr, frame_size))
658 return lzx->error = MSPACK_ERR_DECRUNCH;
659 }
660
661 /* does this intel block _really_ need decoding? */
662 if (lzx->intel_started && lzx->intel_filesize &&
663 (lzx->frame <= 32768) && (frame_size > 10))
664 {
665 unsigned char *data = &lzx->e8_buf[0];
666 unsigned char *dataend = &lzx->e8_buf[frame_size - 10];
667 signed int curpos = lzx->intel_curpos;
668 signed int filesize = lzx->intel_filesize;
669 signed int abs_off, rel_off;
670
671 /* copy e8 block to the e8 buffer and tweak if needed */
672 lzx->o_ptr = data;
673 lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size);
674
675 while (data < dataend) {
676 if (*data++ != 0xE8) { curpos++; continue; }
677 abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
678 if ((abs_off >= -curpos) && (abs_off < filesize)) {
679 rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
680 data[0] = (unsigned char) rel_off;
681 data[1] = (unsigned char) (rel_off >> 8);
682 data[2] = (unsigned char) (rel_off >> 16);
683 data[3] = (unsigned char) (rel_off >> 24);
684 }
685 data += 4;
686 curpos += 5;
687 }
688 lzx->intel_curpos += frame_size;
689 }
690 else {
691 lzx->o_ptr = &lzx->window[lzx->frame_posn];
692 if (lzx->intel_filesize) lzx->intel_curpos += frame_size;
693 }
694 lzx->o_end = &lzx->o_ptr[frame_size];
695
696 /* write a frame */
697 i = (out_bytes < (off_t)frame_size) ? (unsigned int)out_bytes : frame_size;
698 if (lzx->sys->write(lzx->output, lzx->o_ptr, i) != i) {
699 return lzx->error = MSPACK_ERR_WRITE;
700 }
701 lzx->o_ptr += i;
702 lzx->offset += i;
703 out_bytes -= i;
704
705 /* advance frame start position */
706 lzx->frame_posn += frame_size;
707 lzx->frame++;
708
709 /* wrap window / frame position pointers */
710 if (window_posn == lzx->window_size) window_posn = 0;
711 if (lzx->frame_posn == lzx->window_size) lzx->frame_posn = 0;
712
713 } /* while (lzx->frame < end_frame) */
714
715 if (out_bytes) {
716 D(("bytes left to output"))
717 return lzx->error = MSPACK_ERR_DECRUNCH;
718 }
719
720 /* store local state */
721 STORE_BITS;
722 lzx->window_posn = window_posn;
723 lzx->R0 = R0;
724 lzx->R1 = R1;
725 lzx->R2 = R2;
726
727 return MSPACK_ERR_OK;
728}
729
730void lzxd_free(struct lzxd_stream *lzx) {
731 struct mspack_system *sys;
732 if (lzx) {
733 sys = lzx->sys;
734 sys->free(lzx->inbuf);
735 sys->free(lzx->window);
736 sys->free(lzx);
737 }
738}
diff --git a/rbutil/rbutilqt/mspack/mspack.h b/rbutil/rbutilqt/mspack/mspack.h
new file mode 100644
index 0000000000..7f6bdf1465
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/mspack.h
@@ -0,0 +1,2203 @@
1/* libmspack -- a library for working with Microsoft compression formats.
2 * (C) 2003-2011 Stuart Caie <kyzer@4u.net>
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/** \mainpage
18 *
19 * \section intro Introduction
20 *
21 * libmspack is a library which provides compressors and decompressors,
22 * archivers and dearchivers for Microsoft compression formats.
23 *
24 * \section formats Formats supported
25 *
26 * The following file formats are supported:
27 * - SZDD files, which use LZSS compression
28 * - KWAJ files, which use LZSS, LZSS+Huffman or deflate compression
29 * - .HLP (MS Help) files, which use LZSS compression
30 * - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression
31 * - .CHM (HTML Help) files, which use LZX compression
32 * - .LIT (MS EBook) files, which use LZX compression and DES encryption
33 *
34 * To determine the capabilities of the library, and the binary
35 * compatibility version of any particular compressor or decompressor, use
36 * the mspack_version() function. The UNIX library interface version is
37 * defined as the highest-versioned library component.
38 *
39 * \section starting Getting started
40 *
41 * The macro MSPACK_SYS_SELFTEST() should be used to ensure the library can
42 * be used. In particular, it checks if the caller is using 32-bit file I/O
43 * when the library is compiled for 64-bit file I/O and vice versa.
44 *
45 * If compiled normally, the library includes basic file I/O and memory
46 * management functionality using the standard C library. This can be
47 * customised and replaced entirely by creating a mspack_system structure.
48 *
49 * A compressor or decompressor for the required format must be
50 * instantiated before it can be used. Each construction function takes
51 * one parameter, which is either a pointer to a custom mspack_system
52 * structure, or NULL to use the default. The instantiation returned, if
53 * not NULL, contains function pointers (methods) to work with the given
54 * file format.
55 *
56 * For compression:
57 * - mspack_create_cab_compressor() creates a mscab_compressor
58 * - mspack_create_chm_compressor() creates a mschm_compressor
59 * - mspack_create_lit_compressor() creates a mslit_compressor
60 * - mspack_create_hlp_compressor() creates a mshlp_compressor
61 * - mspack_create_szdd_compressor() creates a msszdd_compressor
62 * - mspack_create_kwaj_compressor() creates a mskwaj_compressor
63 *
64 * For decompression:
65 * - mspack_create_cab_decompressor() creates a mscab_decompressor
66 * - mspack_create_chm_decompressor() creates a mschm_decompressor
67 * - mspack_create_lit_decompressor() creates a mslit_decompressor
68 * - mspack_create_hlp_decompressor() creates a mshlp_decompressor
69 * - mspack_create_szdd_decompressor() creates a msszdd_decompressor
70 * - mspack_create_kwaj_decompressor() creates a mskwaj_decompressor
71 *
72 * Once finished working with a format, each kind of
73 * compressor/decompressor has its own specific destructor:
74 * - mspack_destroy_cab_compressor()
75 * - mspack_destroy_cab_decompressor()
76 * - mspack_destroy_chm_compressor()
77 * - mspack_destroy_chm_decompressor()
78 * - mspack_destroy_lit_compressor()
79 * - mspack_destroy_lit_decompressor()
80 * - mspack_destroy_hlp_compressor()
81 * - mspack_destroy_hlp_decompressor()
82 * - mspack_destroy_szdd_compressor()
83 * - mspack_destroy_szdd_decompressor()
84 * - mspack_destroy_kwaj_compressor()
85 * - mspack_destroy_kwaj_decompressor()
86 *
87 * Destroying a compressor or decompressor does not destroy any objects,
88 * structures or handles that have been created using that compressor or
89 * decompressor. Ensure that everything created or opened is destroyed or
90 * closed before compressor/decompressor is itself destroyed.
91 *
92 * \section errors Error codes
93 *
94 * All compressors and decompressors use the same set of error codes. Most
95 * methods return an error code directly. For methods which do not
96 * return error codes directly, the error code can be obtained with the
97 * last_error() method.
98 *
99 * - #MSPACK_ERR_OK is used to indicate success. This error code is defined
100 * as zero, all other code are non-zero.
101 * - #MSPACK_ERR_ARGS indicates that a method was called with inappropriate
102 * arguments.
103 * - #MSPACK_ERR_OPEN indicates that mspack_system::open() failed.
104 * - #MSPACK_ERR_READ indicates that mspack_system::read() failed.
105 * - #MSPACK_ERR_WRITE indicates that mspack_system::write() failed.
106 * - #MSPACK_ERR_SEEK indicates that mspack_system::seek() failed.
107 * - #MSPACK_ERR_NOMEMORY indicates that mspack_system::alloc() failed.
108 * - #MSPACK_ERR_SIGNATURE indicates that the file being read does not
109 * have the correct "signature". It is probably not a valid file for
110 * whatever format is being read.
111 * - #MSPACK_ERR_DATAFORMAT indicates that the file being used or read
112 * is corrupt.
113 * - #MSPACK_ERR_CHECKSUM indicates that a data checksum has failed.
114 * - #MSPACK_ERR_CRUNCH indicates an error occured during compression.
115 * - #MSPACK_ERR_DECRUNCH indicates an error occured during decompression.
116 *
117 * \section threading Multi-threading
118 *
119 * libmspack methods are reentrant and multithreading-safe when each
120 * thread has its own compressor or decompressor.
121
122 * You should not call multiple methods simultaneously on a single
123 * compressor or decompressor instance.
124 *
125 * If this may happen, you can either use one compressor or
126 * decompressor per thread, or you can use your preferred lock,
127 * semaphore or mutex library to ensure no more than one method on a
128 * compressor/decompressor is called simultaneously. libmspack will
129 * not do this locking for you.
130 *
131 * Example of incorrect behaviour:
132 * - thread 1 calls mspack_create_cab_decompressor()
133 * - thread 1 calls open()
134 * - thread 1 calls extract() for one file
135 * - thread 2 simultaneously calls extract() for another file
136 *
137 * Correct behaviour:
138 * - thread 1 calls mspack_create_cab_decompressor()
139 * - thread 2 calls mspack_create_cab_decompressor()
140 * - thread 1 calls its own open() / extract()
141 * - thread 2 simultaneously calls its own open() / extract()
142 *
143 * Also correct behaviour:
144 * - thread 1 calls mspack_create_cab_decompressor()
145 * - thread 1 locks a mutex for with the decompressor before
146 * calling any methods on it, and unlocks the mutex after each
147 * method returns.
148 * - thread 1 can share the results of open() with thread 2, and both
149 * can call extract(), provided they both guard against simultaneous
150 * use of extract(), and any other methods, with the mutex
151 */
152
153#ifndef LIB_MSPACK_H
154#define LIB_MSPACK_H 1
155
156#ifdef __cplusplus
157extern "C" {
158#endif
159
160#include <sys/types.h>
161#include <stdlib.h>
162
163/**
164 * System self-test function, to ensure both library and calling program
165 * can use one another.
166 *
167 * A result of MSPACK_ERR_OK means the library and caller are
168 * compatible. Any other result indicates that the library and caller are
169 * not compatible and should not be used. In particular, a value of
170 * MSPACK_ERR_SEEK means the library and caller use different off_t
171 * datatypes.
172 *
173 * It should be used like so:
174 *
175 * @code
176 * int selftest_result;
177 * MSPACK_SYS_SELFTEST(selftest_result);
178 * if (selftest_result != MSPACK_ERR_OK) {
179 * fprintf(stderr, "incompatible with this build of libmspack\n");
180 * exit(0);
181 * }
182 * @endcode
183 *
184 * @param result an int variable to store the result of the self-test
185 */
186#define MSPACK_SYS_SELFTEST(result) do { \
187 (result) = mspack_sys_selftest_internal(sizeof(off_t)); \
188} while (0)
189
190/** Part of the MSPACK_SYS_SELFTEST() macro, must not be used directly. */
191extern int mspack_sys_selftest_internal(int);
192
193/**
194 * Enquire about the binary compatibility version of a specific interface in
195 * the library. Currently, the following interfaces are defined:
196 *
197 * - #MSPACK_VER_LIBRARY: the overall library
198 * - #MSPACK_VER_SYSTEM: the mspack_system interface
199 * - #MSPACK_VER_MSCABD: the mscab_decompressor interface
200 * - #MSPACK_VER_MSCABC: the mscab_compressor interface
201 * - #MSPACK_VER_MSCHMD: the mschm_decompressor interface
202 * - #MSPACK_VER_MSCHMC: the mschm_compressor interface
203 * - #MSPACK_VER_MSLITD: the mslit_decompressor interface
204 * - #MSPACK_VER_MSLITC: the mslit_compressor interface
205 * - #MSPACK_VER_MSHLPD: the mshlp_decompressor interface
206 * - #MSPACK_VER_MSHLPC: the mshlp_compressor interface
207 * - #MSPACK_VER_MSSZDDD: the msszdd_decompressor interface
208 * - #MSPACK_VER_MSSZDDC: the msszdd_compressor interface
209 * - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface
210 * - #MSPACK_VER_MSKWAJC: the mskwaj_compressor interface
211 *
212 * The result of the function should be interpreted as follows:
213 * - -1: this interface is completely unknown to the library
214 * - 0: this interface is known, but non-functioning
215 * - 1: this interface has all basic functionality
216 * - 2, 3, ...: this interface has additional functionality, clearly marked
217 * in the documentation as "version 2", "version 3" and so on.
218 *
219 * @param entity the interface to request current version of
220 * @return the version of the requested interface
221 */
222extern int mspack_version(int entity);
223
224/** Pass to mspack_version() to get the overall library version */
225#define MSPACK_VER_LIBRARY (0)
226/** Pass to mspack_version() to get the mspack_system version */
227#define MSPACK_VER_SYSTEM (1)
228/** Pass to mspack_version() to get the mscab_decompressor version */
229#define MSPACK_VER_MSCABD (2)
230/** Pass to mspack_version() to get the mscab_compressor version */
231#define MSPACK_VER_MSCABC (3)
232/** Pass to mspack_version() to get the mschm_decompressor version */
233#define MSPACK_VER_MSCHMD (4)
234/** Pass to mspack_version() to get the mschm_compressor version */
235#define MSPACK_VER_MSCHMC (5)
236/** Pass to mspack_version() to get the mslit_decompressor version */
237#define MSPACK_VER_MSLITD (6)
238/** Pass to mspack_version() to get the mslit_compressor version */
239#define MSPACK_VER_MSLITC (7)
240/** Pass to mspack_version() to get the mshlp_decompressor version */
241#define MSPACK_VER_MSHLPD (8)
242/** Pass to mspack_version() to get the mshlp_compressor version */
243#define MSPACK_VER_MSHLPC (9)
244/** Pass to mspack_version() to get the msszdd_decompressor version */
245#define MSPACK_VER_MSSZDDD (10)
246/** Pass to mspack_version() to get the msszdd_compressor version */
247#define MSPACK_VER_MSSZDDC (11)
248/** Pass to mspack_version() to get the mskwaj_decompressor version */
249#define MSPACK_VER_MSKWAJD (12)
250/** Pass to mspack_version() to get the mskwaj_compressor version */
251#define MSPACK_VER_MSKWAJC (13)
252
253/* --- file I/O abstraction ------------------------------------------------ */
254
255/**
256 * A structure which abstracts file I/O and memory management.
257 *
258 * The library always uses the mspack_system structure for interaction
259 * with the file system and to allocate, free and copy all memory. It also
260 * uses it to send literal messages to the library user.
261 *
262 * When the library is compiled normally, passing NULL to a compressor or
263 * decompressor constructor will result in a default mspack_system being
264 * used, where all methods are implemented with the standard C library.
265 * However, all constructors support being given a custom created
266 * mspack_system structure, with the library user's own methods. This
267 * allows for more abstract interaction, such as reading and writing files
268 * directly to memory, or from a network socket or pipe.
269 *
270 * Implementors of an mspack_system structure should read all
271 * documentation entries for every structure member, and write methods
272 * which conform to those standards.
273 */
274struct mspack_system {
275 /**
276 * Opens a file for reading, writing, appending or updating.
277 *
278 * @param self a self-referential pointer to the mspack_system
279 * structure whose open() method is being called. If
280 * this pointer is required by close(), read(), write(),
281 * seek() or tell(), it should be stored in the result
282 * structure at this time.
283 * @param filename the file to be opened. It is passed directly from the
284 * library caller without being modified, so it is up to
285 * the caller what this parameter actually represents.
286 * @param mode one of #MSPACK_SYS_OPEN_READ (open an existing file
287 * for reading), #MSPACK_SYS_OPEN_WRITE (open a new file
288 * for writing), #MSPACK_SYS_OPEN_UPDATE (open an existing
289 * file for reading/writing from the start of the file) or
290 * #MSPACK_SYS_OPEN_APPEND (open an existing file for
291 * reading/writing from the end of the file)
292 * @return a pointer to a mspack_file structure. This structure officially
293 * contains no members, its true contents are up to the
294 * mspack_system implementor. It should contain whatever is needed
295 * for other mspack_system methods to operate. Returning the NULL
296 * pointer indicates an error condition.
297 * @see close(), read(), write(), seek(), tell(), message()
298 */
299 struct mspack_file * (*open)(struct mspack_system *self,
300 const char *filename,
301 int mode);
302
303 /**
304 * Closes a previously opened file. If any memory was allocated for this
305 * particular file handle, it should be freed at this time.
306 *
307 * @param file the file to close
308 * @see open()
309 */
310 void (*close)(struct mspack_file *file);
311
312 /**
313 * Reads a given number of bytes from an open file.
314 *
315 * @param file the file to read from
316 * @param buffer the location where the read bytes should be stored
317 * @param bytes the number of bytes to read from the file.
318 * @return the number of bytes successfully read (this can be less than
319 * the number requested), zero to mark the end of file, or less
320 * than zero to indicate an error.
321 * @see open(), write()
322 */
323 int (*read)(struct mspack_file *file,
324 void *buffer,
325 int bytes);
326
327 /**
328 * Writes a given number of bytes to an open file.
329 *
330 * @param file the file to write to
331 * @param buffer the location where the written bytes should be read from
332 * @param bytes the number of bytes to write to the file.
333 * @return the number of bytes successfully written, this can be less
334 * than the number requested. Zero or less can indicate an error
335 * where no bytes at all could be written. All cases where less
336 * bytes were written than requested are considered by the library
337 * to be an error.
338 * @see open(), read()
339 */
340 int (*write)(struct mspack_file *file,
341 void *buffer,
342 int bytes);
343
344 /**
345 * Seeks to a specific file offset within an open file.
346 *
347 * Sometimes the library needs to know the length of a file. It does
348 * this by seeking to the end of the file with seek(file, 0,
349 * MSPACK_SYS_SEEK_END), then calling tell(). Implementations may want
350 * to make a special case for this.
351 *
352 * Due to the potentially varying 32/64 bit datatype off_t on some
353 * architectures, the #MSPACK_SYS_SELFTEST macro MUST be used before
354 * using the library. If not, the error caused by the library passing an
355 * inappropriate stackframe to seek() is subtle and hard to trace.
356 *
357 * @param file the file to be seeked
358 * @param offset an offset to seek, measured in bytes
359 * @param mode one of #MSPACK_SYS_SEEK_START (the offset should be
360 * measured from the start of the file), #MSPACK_SYS_SEEK_CUR
361 * (the offset should be measured from the current file offset)
362 * or #MSPACK_SYS_SEEK_END (the offset should be measured from
363 * the end of the file)
364 * @return zero for success, non-zero for an error
365 * @see open(), tell()
366 */
367 int (*seek)(struct mspack_file *file,
368 off_t offset,
369 int mode);
370
371 /**
372 * Returns the current file position (in bytes) of the given file.
373 *
374 * @param file the file whose file position is wanted
375 * @return the current file position of the file
376 * @see open(), seek()
377 */
378 off_t (*tell)(struct mspack_file *file);
379
380 /**
381 * Used to send messages from the library to the user.
382 *
383 * Occasionally, the library generates warnings or other messages in
384 * plain english to inform the human user. These are informational only
385 * and can be ignored if not wanted.
386 *
387 * @param file may be a file handle returned from open() if this message
388 * pertains to a specific open file, or NULL if not related to
389 * a specific file.
390 * @param format a printf() style format string. It does NOT include a
391 * trailing newline.
392 * @see open()
393 */
394 void (*message)(struct mspack_file *file,
395 const char *format,
396 ...);
397
398 /**
399 * Allocates memory.
400 *
401 * @param self a self-referential pointer to the mspack_system
402 * structure whose alloc() method is being called.
403 * @param bytes the number of bytes to allocate
404 * @result a pointer to the requested number of bytes, or NULL if
405 * not enough memory is available
406 * @see free()
407 */
408 void * (*alloc)(struct mspack_system *self,
409 size_t bytes);
410
411 /**
412 * Frees memory.
413 *
414 * @param ptr the memory to be freed.
415 * @see alloc()
416 */
417 void (*free)(void *ptr);
418
419 /**
420 * Copies from one region of memory to another.
421 *
422 * The regions of memory are guaranteed not to overlap, are usually less
423 * than 256 bytes, and may not be aligned. Please note that the source
424 * parameter comes before the destination parameter, unlike the standard
425 * C function memcpy().
426 *
427 * @param src the region of memory to copy from
428 * @param dest the region of memory to copy to
429 * @param bytes the size of the memory region, in bytes
430 */
431 void (*copy)(void *src,
432 void *dest,
433 size_t bytes);
434
435 /**
436 * A null pointer to mark the end of mspack_system. It must equal NULL.
437 *
438 * Should the mspack_system structure extend in the future, this NULL
439 * will be seen, rather than have an invalid method pointer called.
440 */
441 void *null_ptr;
442};
443
444/** mspack_system::open() mode: open existing file for reading. */
445#define MSPACK_SYS_OPEN_READ (0)
446/** mspack_system::open() mode: open new file for writing */
447#define MSPACK_SYS_OPEN_WRITE (1)
448/** mspack_system::open() mode: open existing file for writing */
449#define MSPACK_SYS_OPEN_UPDATE (2)
450/** mspack_system::open() mode: open existing file for writing */
451#define MSPACK_SYS_OPEN_APPEND (3)
452
453/** mspack_system::seek() mode: seek relative to start of file */
454#define MSPACK_SYS_SEEK_START (0)
455/** mspack_system::seek() mode: seek relative to current offset */
456#define MSPACK_SYS_SEEK_CUR (1)
457/** mspack_system::seek() mode: seek relative to end of file */
458#define MSPACK_SYS_SEEK_END (2)
459
460/**
461 * A structure which represents an open file handle. The contents of this
462 * structure are determined by the implementation of the
463 * mspack_system::open() method.
464 */
465struct mspack_file {
466 int dummy;
467};
468
469/* --- error codes --------------------------------------------------------- */
470
471/** Error code: no error */
472#define MSPACK_ERR_OK (0)
473/** Error code: bad arguments to method */
474#define MSPACK_ERR_ARGS (1)
475/** Error code: error opening file */
476#define MSPACK_ERR_OPEN (2)
477/** Error code: error reading file */
478#define MSPACK_ERR_READ (3)
479/** Error code: error writing file */
480#define MSPACK_ERR_WRITE (4)
481/** Error code: seek error */
482#define MSPACK_ERR_SEEK (5)
483/** Error code: out of memory */
484#define MSPACK_ERR_NOMEMORY (6)
485/** Error code: bad "magic id" in file */
486#define MSPACK_ERR_SIGNATURE (7)
487/** Error code: bad or corrupt file format */
488#define MSPACK_ERR_DATAFORMAT (8)
489/** Error code: bad checksum or CRC */
490#define MSPACK_ERR_CHECKSUM (9)
491/** Error code: error during compression */
492#define MSPACK_ERR_CRUNCH (10)
493/** Error code: error during decompression */
494#define MSPACK_ERR_DECRUNCH (11)
495
496/* --- functions available in library -------------------------------------- */
497
498/** Creates a new CAB compressor.
499 * @param sys a custom mspack_system structure, or NULL to use the default
500 * @return a #mscab_compressor or NULL
501 */
502extern struct mscab_compressor *
503 mspack_create_cab_compressor(struct mspack_system *sys);
504
505/** Creates a new CAB decompressor.
506 * @param sys a custom mspack_system structure, or NULL to use the default
507 * @return a #mscab_decompressor or NULL
508 */
509extern struct mscab_decompressor *
510 mspack_create_cab_decompressor(struct mspack_system *sys);
511
512/** Destroys an existing CAB compressor.
513 * @param self the #mscab_compressor to destroy
514 */
515extern void mspack_destroy_cab_compressor(struct mscab_compressor *self);
516
517/** Destroys an existing CAB decompressor.
518 * @param self the #mscab_decompressor to destroy
519 */
520extern void mspack_destroy_cab_decompressor(struct mscab_decompressor *self);
521
522
523/** Creates a new CHM compressor.
524 * @param sys a custom mspack_system structure, or NULL to use the default
525 * @return a #mschm_compressor or NULL
526 */
527extern struct mschm_compressor *
528 mspack_create_chm_compressor(struct mspack_system *sys);
529
530/** Creates a new CHM decompressor.
531 * @param sys a custom mspack_system structure, or NULL to use the default
532 * @return a #mschm_decompressor or NULL
533 */
534extern struct mschm_decompressor *
535 mspack_create_chm_decompressor(struct mspack_system *sys);
536
537/** Destroys an existing CHM compressor.
538 * @param self the #mschm_compressor to destroy
539 */
540extern void mspack_destroy_chm_compressor(struct mschm_compressor *self);
541
542/** Destroys an existing CHM decompressor.
543 * @param self the #mschm_decompressor to destroy
544 */
545extern void mspack_destroy_chm_decompressor(struct mschm_decompressor *self);
546
547
548/** Creates a new LIT compressor.
549 * @param sys a custom mspack_system structure, or NULL to use the default
550 * @return a #mslit_compressor or NULL
551 */
552extern struct mslit_compressor *
553 mspack_create_lit_compressor(struct mspack_system *sys);
554
555/** Creates a new LIT decompressor.
556 * @param sys a custom mspack_system structure, or NULL to use the default
557 * @return a #mslit_decompressor or NULL
558 */
559extern struct mslit_decompressor *
560 mspack_create_lit_decompressor(struct mspack_system *sys);
561
562/** Destroys an existing LIT compressor.
563 * @param self the #mslit_compressor to destroy
564 */
565extern void mspack_destroy_lit_compressor(struct mslit_compressor *self);
566
567/** Destroys an existing LIT decompressor.
568 * @param self the #mslit_decompressor to destroy
569 */
570extern void mspack_destroy_lit_decompressor(struct mslit_decompressor *self);
571
572
573/** Creates a new HLP compressor.
574 * @param sys a custom mspack_system structure, or NULL to use the default
575 * @return a #mshlp_compressor or NULL
576 */
577extern struct mshlp_compressor *
578 mspack_create_hlp_compressor(struct mspack_system *sys);
579
580/** Creates a new HLP decompressor.
581 * @param sys a custom mspack_system structure, or NULL to use the default
582 * @return a #mshlp_decompressor or NULL
583 */
584extern struct mshlp_decompressor *
585 mspack_create_hlp_decompressor(struct mspack_system *sys);
586
587/** Destroys an existing hlp compressor.
588 * @param self the #mshlp_compressor to destroy
589 */
590extern void mspack_destroy_hlp_compressor(struct mshlp_compressor *self);
591
592/** Destroys an existing hlp decompressor.
593 * @param self the #mshlp_decompressor to destroy
594 */
595extern void mspack_destroy_hlp_decompressor(struct mshlp_decompressor *self);
596
597
598/** Creates a new SZDD compressor.
599 * @param sys a custom mspack_system structure, or NULL to use the default
600 * @return a #msszdd_compressor or NULL
601 */
602extern struct msszdd_compressor *
603 mspack_create_szdd_compressor(struct mspack_system *sys);
604
605/** Creates a new SZDD decompressor.
606 * @param sys a custom mspack_system structure, or NULL to use the default
607 * @return a #msszdd_decompressor or NULL
608 */
609extern struct msszdd_decompressor *
610 mspack_create_szdd_decompressor(struct mspack_system *sys);
611
612/** Destroys an existing SZDD compressor.
613 * @param self the #msszdd_compressor to destroy
614 */
615extern void mspack_destroy_szdd_compressor(struct msszdd_compressor *self);
616
617/** Destroys an existing SZDD decompressor.
618 * @param self the #msszdd_decompressor to destroy
619 */
620extern void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *self);
621
622
623/** Creates a new KWAJ compressor.
624 * @param sys a custom mspack_system structure, or NULL to use the default
625 * @return a #mskwaj_compressor or NULL
626 */
627extern struct mskwaj_compressor *
628 mspack_create_kwaj_compressor(struct mspack_system *sys);
629
630/** Creates a new KWAJ decompressor.
631 * @param sys a custom mspack_system structure, or NULL to use the default
632 * @return a #mskwaj_decompressor or NULL
633 */
634extern struct mskwaj_decompressor *
635 mspack_create_kwaj_decompressor(struct mspack_system *sys);
636
637/** Destroys an existing KWAJ compressor.
638 * @param self the #mskwaj_compressor to destroy
639 */
640extern void mspack_destroy_kwaj_compressor(struct mskwaj_compressor *self);
641
642/** Destroys an existing KWAJ decompressor.
643 * @param self the #mskwaj_decompressor to destroy
644 */
645extern void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *self);
646
647
648/* --- support for .CAB (MS Cabinet) file format --------------------------- */
649
650/**
651 * A structure which represents a single cabinet file.
652 *
653 * All fields are READ ONLY.
654 *
655 * If this cabinet is part of a merged cabinet set, the #files and #folders
656 * fields are common to all cabinets in the set, and will be identical.
657 *
658 * @see mscab_decompressor::open(), mscab_decompressor::close(),
659 * mscab_decompressor::search()
660 */
661struct mscabd_cabinet {
662 /**
663 * The next cabinet in a chained list, if this cabinet was opened with
664 * mscab_decompressor::search(). May be NULL to mark the end of the
665 * list.
666 */
667 struct mscabd_cabinet *next;
668
669 /**
670 * The filename of the cabinet. More correctly, the filename of the
671 * physical file that the cabinet resides in. This is given by the
672 * library user and may be in any format.
673 */
674 const char *filename;
675
676 /** The file offset of cabinet within the physical file it resides in. */
677 off_t base_offset;
678
679 /** The length of the cabinet file in bytes. */
680 unsigned int length;
681
682 /** The previous cabinet in a cabinet set, or NULL. */
683 struct mscabd_cabinet *prevcab;
684
685 /** The next cabinet in a cabinet set, or NULL. */
686 struct mscabd_cabinet *nextcab;
687
688 /** The filename of the previous cabinet in a cabinet set, or NULL. */
689 char *prevname;
690
691 /** The filename of the next cabinet in a cabinet set, or NULL. */
692 char *nextname;
693
694 /** The name of the disk containing the previous cabinet in a cabinet
695 * set, or NULL.
696 */
697 char *previnfo;
698
699 /** The name of the disk containing the next cabinet in a cabinet set,
700 * or NULL.
701 */
702 char *nextinfo;
703
704 /** A list of all files in the cabinet or cabinet set. */
705 struct mscabd_file *files;
706
707 /** A list of all folders in the cabinet or cabinet set. */
708 struct mscabd_folder *folders;
709
710 /**
711 * The set ID of the cabinet. All cabinets in the same set should have
712 * the same set ID.
713 */
714 unsigned short set_id;
715
716 /**
717 * The index number of the cabinet within the set. Numbering should
718 * start from 0 for the first cabinet in the set, and increment by 1 for
719 * each following cabinet.
720 */
721 unsigned short set_index;
722
723 /**
724 * The number of bytes reserved in the header area of the cabinet.
725 *
726 * If this is non-zero and flags has MSCAB_HDR_RESV set, this data can
727 * be read by the calling application. It is of the given length,
728 * located at offset (base_offset + MSCAB_HDR_RESV_OFFSET) in the
729 * cabinet file.
730 *
731 * @see flags
732 */
733 unsigned short header_resv;
734
735 /**
736 * Header flags.
737 *
738 * - MSCAB_HDR_PREVCAB indicates the cabinet is part of a cabinet set, and
739 * has a predecessor cabinet.
740 * - MSCAB_HDR_NEXTCAB indicates the cabinet is part of a cabinet set, and
741 * has a successor cabinet.
742 * - MSCAB_HDR_RESV indicates the cabinet has reserved header space.
743 *
744 * @see prevname, previnfo, nextname, nextinfo, header_resv
745 */
746 int flags;
747};
748
749/** Offset from start of cabinet to the reserved header data (if present). */
750#define MSCAB_HDR_RESV_OFFSET (0x28)
751
752/** Cabinet header flag: cabinet has a predecessor */
753#define MSCAB_HDR_PREVCAB (0x01)
754/** Cabinet header flag: cabinet has a successor */
755#define MSCAB_HDR_NEXTCAB (0x02)
756/** Cabinet header flag: cabinet has reserved header space */
757#define MSCAB_HDR_RESV (0x04)
758
759/**
760 * A structure which represents a single folder in a cabinet or cabinet set.
761 *
762 * All fields are READ ONLY.
763 *
764 * A folder is a single compressed stream of data. When uncompressed, it
765 * holds the data of one or more files. A folder may be split across more
766 * than one cabinet.
767 */
768struct mscabd_folder {
769 /**
770 * A pointer to the next folder in this cabinet or cabinet set, or NULL
771 * if this is the final folder.
772 */
773 struct mscabd_folder *next;
774
775 /**
776 * The compression format used by this folder.
777 *
778 * The macro MSCABD_COMP_METHOD() should be used on this field to get
779 * the algorithm used. The macro MSCABD_COMP_LEVEL() should be used to get
780 * the "compression level".
781 *
782 * @see MSCABD_COMP_METHOD(), MSCABD_COMP_LEVEL()
783 */
784 int comp_type;
785
786 /**
787 * The total number of data blocks used by this folder. This includes
788 * data blocks present in other files, if this folder spans more than
789 * one cabinet.
790 */
791 unsigned int num_blocks;
792};
793
794/**
795 * Returns the compression method used by a folder.
796 *
797 * @param comp_type a mscabd_folder::comp_type value
798 * @return one of #MSCAB_COMP_NONE, #MSCAB_COMP_MSZIP, #MSCAB_COMP_QUANTUM
799 * or #MSCAB_COMP_LZX
800 */
801#define MSCABD_COMP_METHOD(comp_type) ((comp_type) & 0x0F)
802/**
803 * Returns the compression level used by a folder.
804 *
805 * @param comp_type a mscabd_folder::comp_type value
806 * @return the compression level. This is only defined by LZX and Quantum
807 * compression
808 */
809#define MSCABD_COMP_LEVEL(comp_type) (((comp_type) >> 8) & 0x1F)
810
811/** Compression mode: no compression. */
812#define MSCAB_COMP_NONE (0)
813/** Compression mode: MSZIP (deflate) compression. */
814#define MSCAB_COMP_MSZIP (1)
815/** Compression mode: Quantum compression */
816#define MSCAB_COMP_QUANTUM (2)
817/** Compression mode: LZX compression */
818#define MSCAB_COMP_LZX (3)
819
820/**
821 * A structure which represents a single file in a cabinet or cabinet set.
822 *
823 * All fields are READ ONLY.
824 */
825struct mscabd_file {
826 /**
827 * The next file in the cabinet or cabinet set, or NULL if this is the
828 * final file.
829 */
830 struct mscabd_file *next;
831
832 /**
833 * The filename of the file.
834 *
835 * A null terminated string of up to 255 bytes in length, it may be in
836 * either ISO-8859-1 or UTF8 format, depending on the file attributes.
837 *
838 * @see attribs
839 */
840 char *filename;
841
842 /** The uncompressed length of the file, in bytes. */
843 unsigned int length;
844
845 /**
846 * File attributes.
847 *
848 * The following attributes are defined:
849 * - #MSCAB_ATTRIB_RDONLY indicates the file is write protected.
850 * - #MSCAB_ATTRIB_HIDDEN indicates the file is hidden.
851 * - #MSCAB_ATTRIB_SYSTEM indicates the file is a operating system file.
852 * - #MSCAB_ATTRIB_ARCH indicates the file is "archived".
853 * - #MSCAB_ATTRIB_EXEC indicates the file is an executable program.
854 * - #MSCAB_ATTRIB_UTF_NAME indicates the filename is in UTF8 format rather
855 * than ISO-8859-1.
856 */
857 int attribs;
858
859 /** File's last modified time, hour field. */
860 char time_h;
861 /** File's last modified time, minute field. */
862 char time_m;
863 /** File's last modified time, second field. */
864 char time_s;
865
866 /** File's last modified date, day field. */
867 char date_d;
868 /** File's last modified date, month field. */
869 char date_m;
870 /** File's last modified date, year field. */
871 int date_y;
872
873 /** A pointer to the folder that contains this file. */
874 struct mscabd_folder *folder;
875
876 /** The uncompressed offset of this file in its folder. */
877 unsigned int offset;
878};
879
880/** mscabd_file::attribs attribute: file is read-only. */
881#define MSCAB_ATTRIB_RDONLY (0x01)
882/** mscabd_file::attribs attribute: file is hidden. */
883#define MSCAB_ATTRIB_HIDDEN (0x02)
884/** mscabd_file::attribs attribute: file is an operating system file. */
885#define MSCAB_ATTRIB_SYSTEM (0x04)
886/** mscabd_file::attribs attribute: file is "archived". */
887#define MSCAB_ATTRIB_ARCH (0x20)
888/** mscabd_file::attribs attribute: file is an executable program. */
889#define MSCAB_ATTRIB_EXEC (0x40)
890/** mscabd_file::attribs attribute: filename is UTF8, not ISO-8859-1. */
891#define MSCAB_ATTRIB_UTF_NAME (0x80)
892
893/** mscab_decompressor::set_param() parameter: search buffer size. */
894#define MSCABD_PARAM_SEARCHBUF (0)
895/** mscab_decompressor::set_param() parameter: repair MS-ZIP streams? */
896#define MSCABD_PARAM_FIXMSZIP (1)
897/** mscab_decompressor::set_param() parameter: size of decompression buffer */
898#define MSCABD_PARAM_DECOMPBUF (2)
899
900/** TODO */
901struct mscab_compressor {
902 int dummy;
903};
904
905/**
906 * A decompressor for .CAB (Microsoft Cabinet) files
907 *
908 * All fields are READ ONLY.
909 *
910 * @see mspack_create_cab_decompressor(), mspack_destroy_cab_decompressor()
911 */
912struct mscab_decompressor {
913 /**
914 * Opens a cabinet file and reads its contents.
915 *
916 * If the file opened is a valid cabinet file, all headers will be read
917 * and a mscabd_cabinet structure will be returned, with a full list of
918 * folders and files.
919 *
920 * In the case of an error occuring, NULL is returned and the error code
921 * is available from last_error().
922 *
923 * The filename pointer should be considered "in use" until close() is
924 * called on the cabinet.
925 *
926 * @param self a self-referential pointer to the mscab_decompressor
927 * instance being called
928 * @param filename the filename of the cabinet file. This is passed
929 * directly to mspack_system::open().
930 * @return a pointer to a mscabd_cabinet structure, or NULL on failure
931 * @see close(), search(), last_error()
932 */
933 struct mscabd_cabinet * (*open) (struct mscab_decompressor *self,
934 const char *filename);
935
936 /**
937 * Closes a previously opened cabinet or cabinet set.
938 *
939 * This closes a cabinet, all cabinets associated with it via the
940 * mscabd_cabinet::next, mscabd_cabinet::prevcab and
941 * mscabd_cabinet::nextcab pointers, and all folders and files. All
942 * memory used by these entities is freed.
943 *
944 * The cabinet pointer is now invalid and cannot be used again. All
945 * mscabd_folder and mscabd_file pointers from that cabinet or cabinet
946 * set are also now invalid, and cannot be used again.
947 *
948 * If the cabinet pointer given was created using search(), it MUST be
949 * the cabinet pointer returned by search() and not one of the later
950 * cabinet pointers further along the mscabd_cabinet::next chain.
951
952 * If extra cabinets have been added using append() or prepend(), these
953 * will all be freed, even if the cabinet pointer given is not the first
954 * cabinet in the set. Do NOT close() more than one cabinet in the set.
955 *
956 * The mscabd_cabinet::filename is not freed by the library, as it is
957 * not allocated by the library. The caller should free this itself if
958 * necessary, before it is lost forever.
959 *
960 * @param self a self-referential pointer to the mscab_decompressor
961 * instance being called
962 * @param cab the cabinet to close
963 * @see open(), search(), append(), prepend()
964 */
965 void (*close)(struct mscab_decompressor *self,
966 struct mscabd_cabinet *cab);
967
968 /**
969 * Searches a regular file for embedded cabinets.
970 *
971 * This opens a normal file with the given filename and will search the
972 * entire file for embedded cabinet files
973 *
974 * If any cabinets are found, the equivalent of open() is called on each
975 * potential cabinet file at the offset it was found. All successfully
976 * open()ed cabinets are kept in a list.
977 *
978 * The first cabinet found will be returned directly as the result of
979 * this method. Any further cabinets found will be chained in a list
980 * using the mscabd_cabinet::next field.
981 *
982 * In the case of an error occuring anywhere other than the simulated
983 * open(), NULL is returned and the error code is available from
984 * last_error().
985 *
986 * If no error occurs, but no cabinets can be found in the file, NULL is
987 * returned and last_error() returns MSPACK_ERR_OK.
988 *
989 * The filename pointer should be considered in use until close() is
990 * called on the cabinet.
991 *
992 * close() should only be called on the result of search(), not on any
993 * subsequent cabinets in the mscabd_cabinet::next chain.
994 *
995 * @param self a self-referential pointer to the mscab_decompressor
996 * instance being called
997 * @param filename the filename of the file to search for cabinets. This
998 * is passed directly to mspack_system::open().
999 * @return a pointer to a mscabd_cabinet structure, or NULL
1000 * @see close(), open(), last_error()
1001 */
1002 struct mscabd_cabinet * (*search) (struct mscab_decompressor *self,
1003 const char *filename);
1004
1005 /**
1006 * Appends one mscabd_cabinet to another, forming or extending a cabinet
1007 * set.
1008 *
1009 * This will attempt to append one cabinet to another such that
1010 * <tt>(cab->nextcab == nextcab) && (nextcab->prevcab == cab)</tt> and
1011 * any folders split between the two cabinets are merged.
1012 *
1013 * The cabinets MUST be part of a cabinet set -- a cabinet set is a
1014 * cabinet that spans more than one physical cabinet file on disk -- and
1015 * must be appropriately matched.
1016 *
1017 * It can be determined if a cabinet has further parts to load by
1018 * examining the mscabd_cabinet::flags field:
1019 *
1020 * - if <tt>(flags & MSCAB_HDR_PREVCAB)</tt> is non-zero, there is a
1021 * predecessor cabinet to open() and prepend(). Its MS-DOS
1022 * case-insensitive filename is mscabd_cabinet::prevname
1023 * - if <tt>(flags & MSCAB_HDR_NEXTCAB)</tt> is non-zero, there is a
1024 * successor cabinet to open() and append(). Its MS-DOS case-insensitive
1025 * filename is mscabd_cabinet::nextname
1026 *
1027 * If the cabinets do not match, an error code will be returned. Neither
1028 * cabinet has been altered, and both should be closed seperately.
1029 *
1030 * Files and folders in a cabinet set are a single entity. All cabinets
1031 * in a set use the same file list, which is updated as cabinets in the
1032 * set are added. All pointers to mscabd_folder and mscabd_file
1033 * structures in either cabinet must be discarded and re-obtained after
1034 * merging.
1035 *
1036 * @param self a self-referential pointer to the mscab_decompressor
1037 * instance being called
1038 * @param cab the cabinet which will be appended to,
1039 * predecessor of nextcab
1040 * @param nextcab the cabinet which will be appended,
1041 * successor of cab
1042 * @return an error code, or MSPACK_ERR_OK if successful
1043 * @see prepend(), open(), close()
1044 */
1045 int (*append) (struct mscab_decompressor *self,
1046 struct mscabd_cabinet *cab,
1047 struct mscabd_cabinet *nextcab);
1048
1049 /**
1050 * Prepends one mscabd_cabinet to another, forming or extending a
1051 * cabinet set.
1052 *
1053 * This will attempt to prepend one cabinet to another, such that
1054 * <tt>(cab->prevcab == prevcab) && (prevcab->nextcab == cab)</tt>. In
1055 * all other respects, it is identical to append(). See append() for the
1056 * full documentation.
1057 *
1058 * @param self a self-referential pointer to the mscab_decompressor
1059 * instance being called
1060 * @param cab the cabinet which will be prepended to,
1061 * successor of prevcab
1062 * @param prevcab the cabinet which will be prepended,
1063 * predecessor of cab
1064 * @return an error code, or MSPACK_ERR_OK if successful
1065 * @see append(), open(), close()
1066 */
1067 int (*prepend) (struct mscab_decompressor *self,
1068 struct mscabd_cabinet *cab,
1069 struct mscabd_cabinet *prevcab);
1070
1071 /**
1072 * Extracts a file from a cabinet or cabinet set.
1073 *
1074 * This extracts a compressed file in a cabinet and writes it to the given
1075 * filename.
1076 *
1077 * The MS-DOS filename of the file, mscabd_file::filename, is NOT USED
1078 * by extract(). The caller must examine this MS-DOS filename, copy and
1079 * change it as necessary, create directories as necessary, and provide
1080 * the correct filename as a parameter, which will be passed unchanged
1081 * to the decompressor's mspack_system::open()
1082 *
1083 * If the file belongs to a split folder in a multi-part cabinet set,
1084 * and not enough parts of the cabinet set have been loaded and appended
1085 * or prepended, an error will be returned immediately.
1086 *
1087 * @param self a self-referential pointer to the mscab_decompressor
1088 * instance being called
1089 * @param file the file to be decompressed
1090 * @param filename the filename of the file being written to
1091 * @return an error code, or MSPACK_ERR_OK if successful
1092 */
1093 int (*extract)(struct mscab_decompressor *self,
1094 struct mscabd_file *file,
1095 const char *filename);
1096
1097 /**
1098 * Sets a CAB decompression engine parameter.
1099 *
1100 * The following parameters are defined:
1101 * - #MSCABD_PARAM_SEARCHBUF: How many bytes should be allocated as a
1102 * buffer when using search()? The minimum value is 4. The default
1103 * value is 32768.
1104 * - #MSCABD_PARAM_FIXMSZIP: If non-zero, extract() will ignore bad
1105 * checksums and recover from decompression errors in MS-ZIP
1106 * compressed folders. The default value is 0 (don't recover).
1107 * - #MSCABD_PARAM_DECOMPBUF: How many bytes should be used as an input
1108 * bit buffer by decompressors? The minimum value is 4. The default
1109 * value is 4096.
1110 *
1111 * @param self a self-referential pointer to the mscab_decompressor
1112 * instance being called
1113 * @param param the parameter to set
1114 * @param value the value to set the parameter to
1115 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
1116 * is a problem with either parameter or value.
1117 * @see search(), extract()
1118 */
1119 int (*set_param)(struct mscab_decompressor *self,
1120 int param,
1121 int value);
1122
1123 /**
1124 * Returns the error code set by the most recently called method.
1125 *
1126 * This is useful for open() and search(), which do not return an error
1127 * code directly.
1128 *
1129 * @param self a self-referential pointer to the mscab_decompressor
1130 * instance being called
1131 * @return the most recent error code
1132 * @see open(), search()
1133 */
1134 int (*last_error)(struct mscab_decompressor *self);
1135};
1136
1137/* --- support for .CHM (HTMLHelp) file format ----------------------------- */
1138
1139/**
1140 * A structure which represents a file to be placed in a CHM helpfile.
1141 *
1142 * A contiguous array of these structures should be passed to
1143 * mschm_compressor::generate(). The array list is terminated with an
1144 * entry whose mschmc_file::section field is set to #MSCHMC_ENDLIST, the
1145 * other fields in this entry are ignored.
1146 */
1147struct mschmc_file {
1148 /** One of #MSCHMC_ENDLIST, #MSCHMC_UNCOMP or #MSCHMC_MSCOMP. */
1149 int section;
1150
1151 /** The filename of the source file that will be added to the CHM. This
1152 * is passed directly to mspack_system::open(). */
1153 const char *filename;
1154
1155 /** The full path and filename of the file within the CHM helpfile, a
1156 * UTF-1 encoded null-terminated string. */
1157 char *chm_filename;
1158
1159 /** The length of the file, in bytes. This will be adhered to strictly
1160 * and a read error will be issued if this many bytes cannot be read
1161 * from the real file at CHM generation time. */
1162 off_t length;
1163};
1164
1165/**
1166 * A structure which represents a section of a CHM helpfile.
1167 *
1168 * All fields are READ ONLY.
1169 *
1170 * Not used directly, but used as a generic base type for
1171 * mschmd_sec_uncompressed and mschmd_sec_mscompressed.
1172 */
1173struct mschmd_section {
1174 /** A pointer to the CHM helpfile that contains this section. */
1175 struct mschmd_header *chm;
1176
1177 /**
1178 * The section ID. Either 0 for the uncompressed section
1179 * mschmd_sec_uncompressed, or 1 for the LZX compressed section
1180 * mschmd_sec_mscompressed. No other section IDs are known.
1181 */
1182 unsigned int id;
1183};
1184
1185/**
1186 * A structure which represents the uncompressed section of a CHM helpfile.
1187 *
1188 * All fields are READ ONLY.
1189 */
1190struct mschmd_sec_uncompressed {
1191 /** Generic section data. */
1192 struct mschmd_section base;
1193
1194 /** The file offset of where this section begins in the CHM helpfile. */
1195 off_t offset;
1196};
1197
1198/**
1199 * A structure which represents the LZX compressed section of a CHM helpfile.
1200 *
1201 * All fields are READ ONLY.
1202 */
1203struct mschmd_sec_mscompressed {
1204 /** Generic section data. */
1205 struct mschmd_section base;
1206
1207 /** A pointer to the meta-file which represents all LZX compressed data. */
1208 struct mschmd_file *content;
1209
1210 /** A pointer to the file which contains the LZX control data. */
1211 struct mschmd_file *control;
1212
1213 /** A pointer to the file which contains the LZX reset table. */
1214 struct mschmd_file *rtable;
1215
1216 /** A pointer to the file which contains the LZX span information.
1217 * Available only in CHM decoder version 2 and above.
1218 */
1219 struct mschmd_file *spaninfo;
1220};
1221
1222/**
1223 * A structure which represents a CHM helpfile.
1224 *
1225 * All fields are READ ONLY.
1226 */
1227struct mschmd_header {
1228 /** The version of the CHM file format used in this file. */
1229 unsigned int version;
1230
1231 /**
1232 * The "timestamp" of the CHM helpfile.
1233 *
1234 * It is the lower 32 bits of a 64-bit value representing the number of
1235 * centiseconds since 1601-01-01 00:00:00 UTC, plus 42. It is not useful
1236 * as a timestamp, but it is useful as a semi-unique ID.
1237 */
1238 unsigned int timestamp;
1239
1240 /**
1241 * The default Language and Country ID (LCID) of the user who ran the
1242 * HTMLHelp Compiler. This is not the language of the CHM file itself.
1243 */
1244 unsigned int language;
1245
1246 /**
1247 * The filename of the CHM helpfile. This is given by the library user
1248 * and may be in any format.
1249 */
1250 const char *filename;
1251
1252 /** The length of the CHM helpfile, in bytes. */
1253 off_t length;
1254
1255 /** A list of all non-system files in the CHM helpfile. */
1256 struct mschmd_file *files;
1257
1258 /**
1259 * A list of all system files in the CHM helpfile.
1260 *
1261 * System files are files which begin with "::". They are meta-files
1262 * generated by the CHM creation process.
1263 */
1264 struct mschmd_file *sysfiles;
1265
1266 /** The section 0 (uncompressed) data in this CHM helpfile. */
1267 struct mschmd_sec_uncompressed sec0;
1268
1269 /** The section 1 (MSCompressed) data in this CHM helpfile. */
1270 struct mschmd_sec_mscompressed sec1;
1271
1272 /** The file offset of the first PMGL/PMGI directory chunk. */
1273 off_t dir_offset;
1274
1275 /** The number of PMGL/PMGI directory chunks in this CHM helpfile. */
1276 unsigned int num_chunks;
1277
1278 /** The size of each PMGL/PMGI chunk, in bytes. */
1279 unsigned int chunk_size;
1280
1281 /** The "density" of the quick-reference section in PMGL/PMGI chunks. */
1282 unsigned int density;
1283
1284 /** The depth of the index tree.
1285 *
1286 * - if 1, there are no PMGI chunks, only PMGL chunks.
1287 * - if 2, there is 1 PMGI chunk. All chunk indices point to PMGL chunks.
1288 * - if 3, the root PMGI chunk points to secondary PMGI chunks, which in
1289 * turn point to PMGL chunks.
1290 * - and so on...
1291 */
1292 unsigned int depth;
1293
1294 /**
1295 * The number of the root PMGI chunk.
1296 *
1297 * If there is no index in the CHM helpfile, this will be 0xFFFFFFFF.
1298 */
1299 unsigned int index_root;
1300
1301 /**
1302 * The number of the first PMGL chunk. Usually zero.
1303 * Available only in CHM decoder version 2 and above.
1304 */
1305 unsigned int first_pmgl;
1306
1307 /**
1308 * The number of the last PMGL chunk. Usually num_chunks-1.
1309 * Available only in CHM decoder version 2 and above.
1310 */
1311 unsigned int last_pmgl;
1312
1313 /**
1314 * A cache of loaded chunks, filled in by mschm_decoder::fast_find().
1315 * Available only in CHM decoder version 2 and above.
1316 */
1317 unsigned char **chunk_cache;
1318};
1319
1320/**
1321 * A structure which represents a file stored in a CHM helpfile.
1322 *
1323 * All fields are READ ONLY.
1324 */
1325struct mschmd_file {
1326 /**
1327 * A pointer to the next file in the list, or NULL if this is the final
1328 * file.
1329 */
1330 struct mschmd_file *next;
1331
1332 /**
1333 * A pointer to the section that this file is located in. Indirectly,
1334 * it also points to the CHM helpfile the file is located in.
1335 */
1336 struct mschmd_section *section;
1337
1338 /** The offset within the section data that this file is located at. */
1339 off_t offset;
1340
1341 /** The length of this file, in bytes */
1342 off_t length;
1343
1344 /** The filename of this file -- a null terminated string in UTF-8. */
1345 char *filename;
1346};
1347
1348/** mschmc_file::section value: end of CHM file list */
1349#define MSCHMC_ENDLIST (0)
1350/** mschmc_file::section value: this file is in the Uncompressed section */
1351#define MSCHMC_UNCOMP (1)
1352/** mschmc_file::section value: this file is in the MSCompressed section */
1353#define MSCHMC_MSCOMP (2)
1354
1355/** mschm_compressor::set_param() parameter: "timestamp" header */
1356#define MSCHMC_PARAM_TIMESTAMP (0)
1357/** mschm_compressor::set_param() parameter: "language" header */
1358#define MSCHMC_PARAM_LANGUAGE (1)
1359/** mschm_compressor::set_param() parameter: LZX window size */
1360#define MSCHMC_PARAM_LZXWINDOW (2)
1361/** mschm_compressor::set_param() parameter: intra-chunk quickref density */
1362#define MSCHMC_PARAM_DENSITY (3)
1363/** mschm_compressor::set_param() parameter: whether to create indices */
1364#define MSCHMC_PARAM_INDEX (4)
1365
1366/**
1367 * A compressor for .CHM (Microsoft HTMLHelp) files.
1368 *
1369 * All fields are READ ONLY.
1370 *
1371 * @see mspack_create_chm_compressor(), mspack_destroy_chm_compressor()
1372 */
1373struct mschm_compressor {
1374 /**
1375 * Generates a CHM help file.
1376 *
1377 * The help file will contain up to two sections, an Uncompressed
1378 * section and potentially an MSCompressed (LZX compressed)
1379 * section.
1380 *
1381 * While the contents listing of a CHM file is always in lexical order,
1382 * the file list passed in will be taken as the correct order for files
1383 * within the sections. It is in your interest to place similar files
1384 * together for better compression.
1385 *
1386 * There are two modes of generation, to use a temporary file or not to
1387 * use one. See use_temporary_file() for the behaviour of generate() in
1388 * these two different modes.
1389 *
1390 * @param self a self-referential pointer to the mschm_compressor
1391 * instance being called
1392 * @param file_list an array of mschmc_file structures, terminated
1393 * with an entry whose mschmc_file::section field is
1394 * #MSCHMC_ENDLIST. The order of the list is
1395 * preserved within each section. The length of any
1396 * mschmc_file::chm_filename string cannot exceed
1397 * roughly 4096 bytes. Each source file must be able
1398 * to supply as many bytes as given in the
1399 * mschmc_file::length field.
1400 * @param output_file the file to write the generated CHM helpfile to.
1401 * This is passed directly to mspack_system::open()
1402 * @return an error code, or MSPACK_ERR_OK if successful
1403 * @see use_temporary_file() set_param()
1404 */
1405 int (*generate)(struct mschm_compressor *self,
1406 struct mschmc_file file_list[],
1407 const char *output_file);
1408
1409 /**
1410 * Specifies whether a temporary file is used during CHM generation.
1411 *
1412 * The CHM file format includes data about the compressed section (such
1413 * as its overall size) that is stored in the output CHM file prior to
1414 * the compressed section itself. This unavoidably requires that the
1415 * compressed section has to be generated, before these details can be
1416 * set. There are several ways this can be handled. Firstly, the
1417 * compressed section could be generated entirely in memory before
1418 * writing any of the output CHM file. This approach is not used in
1419 * libmspack, as the compressed section can exceed the addressable
1420 * memory space on most architectures.
1421 *
1422 * libmspack has two options, either to write these unknowable sections
1423 * with blank data, generate the compressed section, then re-open the
1424 * output file for update once the compressed section has been
1425 * completed, or to write the compressed section to a temporary file,
1426 * then write the entire output file at once, performing a simple
1427 * file-to-file copy for the compressed section.
1428 *
1429 * The simple solution of buffering the entire compressed section in
1430 * memory can still be used, if desired. As the temporary file's
1431 * filename is passed directly to mspack_system::open(), it is possible
1432 * for a custom mspack_system implementation to hold this file in memory,
1433 * without writing to a disk.
1434 *
1435 * If a temporary file is set, generate() performs the following
1436 * sequence of events: the temporary file is opened for writing, the
1437 * compression algorithm writes to the temporary file, the temporary
1438 * file is closed. Then the output file is opened for writing and the
1439 * temporary file is re-opened for reading. The output file is written
1440 * and the temporary file is read from. Both files are then closed. The
1441 * temporary file itself is not deleted. If that is desired, the
1442 * temporary file should be deleted after the completion of generate(),
1443 * if it exists.
1444 *
1445 * If a temporary file is set not to be used, generate() performs the
1446 * following sequence of events: the output file is opened for writing,
1447 * then it is written and closed. The output file is then re-opened for
1448 * update, the appropriate sections are seek()ed to and re-written, then
1449 * the output file is closed.
1450 *
1451 * @param self a self-referential pointer to the
1452 * mschm_compressor instance being called
1453 * @param use_temp_file non-zero if the temporary file should be used,
1454 * zero if the temporary file should not be used.
1455 * @param temp_file a file to temporarily write compressed data to,
1456 * before opening it for reading and copying the
1457 * contents to the output file. This is passed
1458 * directly to mspack_system::open().
1459 * @return an error code, or MSPACK_ERR_OK if successful
1460 * @see generate()
1461 */
1462 int (*use_temporary_file)(struct mschm_compressor *self,
1463 int use_temp_file,
1464 const char *temp_file);
1465 /**
1466 * Sets a CHM compression engine parameter.
1467 *
1468 * The following parameters are defined:
1469
1470 * - #MSCHMC_PARAM_TIMESTAMP: Sets the "timestamp" of the CHM file
1471 * generated. This is not a timestamp, see mschmd_header::timestamp
1472 * for a description. If this timestamp is 0, generate() will use its
1473 * own algorithm for making a unique ID, based on the lengths and
1474 * names of files in the CHM itself. Defaults to 0, any value between
1475 * 0 and (2^32)-1 is valid.
1476 * - #MSCHMC_PARAM_LANGUAGE: Sets the "language" of the CHM file
1477 * generated. This is not the language used in the CHM file, but the
1478 * language setting of the user who ran the HTMLHelp compiler. It
1479 * defaults to 0x0409. The valid range is between 0x0000 and 0x7F7F.
1480 * - #MSCHMC_PARAM_LZXWINDOW: Sets the size of the LZX history window,
1481 * which is also the interval at which the compressed data stream can be
1482 * randomly accessed. The value is not a size in bytes, but a power of
1483 * two. The default value is 16 (which makes the window 2^16 bytes, or
1484 * 64 kilobytes), the valid range is from 15 (32 kilobytes) to 21 (2
1485 * megabytes).
1486 * - #MSCHMC_PARAM_DENSITY: Sets the "density" of quick reference
1487 * entries stored at the end of directory listing chunk. Each chunk is
1488 * 4096 bytes in size, and contains as many file entries as there is
1489 * room for. At the other end of the chunk, a list of "quick reference"
1490 * pointers is included. The offset of every 'N'th file entry is given a
1491 * quick reference, where N = (2^density) + 1. The default density is
1492 * 2. The smallest density is 0 (N=2), the maximum is 10 (N=1025). As
1493 * each file entry requires at least 5 bytes, the maximum number of
1494 * entries in a single chunk is roughly 800, so the maximum value 10
1495 * can be used to indicate there are no quickrefs at all.
1496 * - #MSCHMC_PARAM_INDEX: Sets whether or not to include quick lookup
1497 * index chunk(s), in addition to normal directory listing chunks. A
1498 * value of zero means no index chunks will be created, a non-zero value
1499 * means index chunks will be created. The default is zero, "don't
1500 * create an index".
1501 *
1502 * @param self a self-referential pointer to the mschm_compressor
1503 * instance being called
1504 * @param param the parameter to set
1505 * @param value the value to set the parameter to
1506 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
1507 * is a problem with either parameter or value.
1508 * @see generate()
1509 */
1510 int (*set_param)(struct mschm_compressor *self,
1511 int param,
1512 unsigned int value);
1513
1514 /**
1515 * Returns the error code set by the most recently called method.
1516 *
1517 * @param self a self-referential pointer to the mschm_compressor
1518 * instance being called
1519 * @return the most recent error code
1520 * @see set_param(), generate()
1521 */
1522 int (*last_error)(struct mschm_compressor *self);
1523};
1524
1525/**
1526 * A decompressor for .CHM (Microsoft HTMLHelp) files
1527 *
1528 * All fields are READ ONLY.
1529 *
1530 * @see mspack_create_chm_decompressor(), mspack_destroy_chm_decompressor()
1531 */
1532struct mschm_decompressor {
1533 /**
1534 * Opens a CHM helpfile and reads its contents.
1535 *
1536 * If the file opened is a valid CHM helpfile, all headers will be read
1537 * and a mschmd_header structure will be returned, with a full list of
1538 * files.
1539 *
1540 * In the case of an error occuring, NULL is returned and the error code
1541 * is available from last_error().
1542 *
1543 * The filename pointer should be considered "in use" until close() is
1544 * called on the CHM helpfile.
1545 *
1546 * @param self a self-referential pointer to the mschm_decompressor
1547 * instance being called
1548 * @param filename the filename of the CHM helpfile. This is passed
1549 * directly to mspack_system::open().
1550 * @return a pointer to a mschmd_header structure, or NULL on failure
1551 * @see close()
1552 */
1553 struct mschmd_header *(*open)(struct mschm_decompressor *self,
1554 const char *filename);
1555
1556 /**
1557 * Closes a previously opened CHM helpfile.
1558 *
1559 * This closes a CHM helpfile, frees the mschmd_header and all
1560 * mschmd_file structures associated with it (if any). This works on
1561 * both helpfiles opened with open() and helpfiles opened with
1562 * fast_open().
1563 *
1564 * The CHM header pointer is now invalid and cannot be used again. All
1565 * mschmd_file pointers referencing that CHM are also now invalid, and
1566 * cannot be used again.
1567 *
1568 * @param self a self-referential pointer to the mschm_decompressor
1569 * instance being called
1570 * @param chm the CHM helpfile to close
1571 * @see open(), fast_open()
1572 */
1573 void (*close)(struct mschm_decompressor *self,
1574 struct mschmd_header *chm);
1575
1576 /**
1577 * Extracts a file from a CHM helpfile.
1578 *
1579 * This extracts a file from a CHM helpfile and writes it to the given
1580 * filename. The filename of the file, mscabd_file::filename, is not
1581 * used by extract(), but can be used by the caller as a guide for
1582 * constructing an appropriate filename.
1583 *
1584 * This method works both with files found in the mschmd_header::files
1585 * and mschmd_header::sysfiles list and mschmd_file structures generated
1586 * on the fly by fast_find().
1587 *
1588 * @param self a self-referential pointer to the mschm_decompressor
1589 * instance being called
1590 * @param file the file to be decompressed
1591 * @param filename the filename of the file being written to
1592 * @return an error code, or MSPACK_ERR_OK if successful
1593 */
1594 int (*extract)(struct mschm_decompressor *self,
1595 struct mschmd_file *file,
1596 const char *filename);
1597
1598 /**
1599 * Returns the error code set by the most recently called method.
1600 *
1601 * This is useful for open() and fast_open(), which do not return an
1602 * error code directly.
1603 *
1604 * @param self a self-referential pointer to the mschm_decompressor
1605 * instance being called
1606 * @return the most recent error code
1607 * @see open(), extract()
1608 */
1609 int (*last_error)(struct mschm_decompressor *self);
1610
1611 /**
1612 * Opens a CHM helpfile quickly.
1613 *
1614 * If the file opened is a valid CHM helpfile, only essential headers
1615 * will be read. A mschmd_header structure will be still be returned, as
1616 * with open(), but the mschmd_header::files field will be NULL. No
1617 * files details will be automatically read. The fast_find() method
1618 * must be used to obtain file details.
1619 *
1620 * In the case of an error occuring, NULL is returned and the error code
1621 * is available from last_error().
1622 *
1623 * The filename pointer should be considered "in use" until close() is
1624 * called on the CHM helpfile.
1625 *
1626 * @param self a self-referential pointer to the mschm_decompressor
1627 * instance being called
1628 * @param filename the filename of the CHM helpfile. This is passed
1629 * directly to mspack_system::open().
1630 * @return a pointer to a mschmd_header structure, or NULL on failure
1631 * @see open(), close(), fast_find(), extract()
1632 */
1633 struct mschmd_header *(*fast_open)(struct mschm_decompressor *self,
1634 const char *filename);
1635
1636 /**
1637 * Finds file details quickly.
1638 *
1639 * Instead of reading all CHM helpfile headers and building a list of
1640 * files, fast_open() and fast_find() are intended for finding file
1641 * details only when they are needed. The CHM file format includes an
1642 * on-disk file index to allow this.
1643 *
1644 * Given a case-sensitive filename, fast_find() will search the on-disk
1645 * index for that file.
1646 *
1647 * If the file was found, the caller-provided mschmd_file structure will
1648 * be filled out like so:
1649 * - section: the correct value for the found file
1650 * - offset: the correct value for the found file
1651 * - length: the correct value for the found file
1652 * - all other structure elements: NULL or 0
1653 *
1654 * If the file was not found, MSPACK_ERR_OK will still be returned as the
1655 * result, but the caller-provided structure will be filled out like so:
1656 * - section: NULL
1657 * - offset: 0
1658 * - length: 0
1659 * - all other structure elements: NULL or 0
1660 *
1661 * This method is intended to be used in conjunction with CHM helpfiles
1662 * opened with fast_open(), but it also works with helpfiles opened
1663 * using the regular open().
1664 *
1665 * @param self a self-referential pointer to the mschm_decompressor
1666 * instance being called
1667 * @param chm the CHM helpfile to search for the file
1668 * @param filename the filename of the file to search for
1669 * @param f_ptr a pointer to a caller-provded mschmd_file structure
1670 * @param f_size <tt>sizeof(struct mschmd_file)</tt>
1671 * @return an error code, or MSPACK_ERR_OK if successful
1672 * @see open(), close(), fast_find(), extract()
1673 */
1674 int (*fast_find)(struct mschm_decompressor *self,
1675 struct mschmd_header *chm,
1676 const char *filename,
1677 struct mschmd_file *f_ptr,
1678 int f_size);
1679};
1680
1681/* --- support for .LIT (EBook) file format -------------------------------- */
1682
1683/** TODO */
1684struct mslit_compressor {
1685 int dummy;
1686};
1687
1688/** TODO */
1689struct mslit_decompressor {
1690 int dummy;
1691};
1692
1693
1694/* --- support for .HLP (MS Help) file format ------------------------------ */
1695
1696/** TODO */
1697struct mshlp_compressor {
1698 int dummy;
1699};
1700
1701/** TODO */
1702struct mshlp_decompressor {
1703 int dummy;
1704};
1705
1706
1707/* --- support for SZDD file format ---------------------------------------- */
1708
1709/** msszdd_compressor::set_param() parameter: the missing character */
1710#define MSSZDDC_PARAM_MISSINGCHAR (0)
1711
1712/** msszddd_header::format value - a regular SZDD file */
1713#define MSSZDD_FMT_NORMAL (0)
1714
1715/** msszddd_header::format value - a special QBasic SZDD file */
1716#define MSSZDD_FMT_QBASIC (1)
1717
1718/**
1719 * A structure which represents an SZDD compressed file.
1720 *
1721 * All fields are READ ONLY.
1722 */
1723struct msszddd_header {
1724 /** The file format; either #MSSZDD_FMT_NORMAL or #MSSZDD_FMT_QBASIC */
1725 int format;
1726
1727 /** The amount of data in the SZDD file once uncompressed. */
1728 off_t length;
1729
1730 /**
1731 * The last character in the filename, traditionally replaced with an
1732 * underscore to show the file is compressed. The null character is used
1733 * to show that this character has not been stored (e.g. because the
1734 * filename is not known). Generally, only characters that may appear in
1735 * an MS-DOS filename (except ".") are valid.
1736 */
1737 char missing_char;
1738};
1739
1740/**
1741 * A compressor for the SZDD file format.
1742 *
1743 * All fields are READ ONLY.
1744 *
1745 * @see mspack_create_szdd_compressor(), mspack_destroy_szdd_compressor()
1746 */
1747struct msszdd_compressor {
1748 /**
1749 * Reads an input file and creates a compressed output file in the
1750 * SZDD compressed file format. The SZDD compression format is quick
1751 * but gives poor compression. It is possible for the compressed output
1752 * file to be larger than the input file.
1753 *
1754 * Conventionally, SZDD compressed files have the final character in
1755 * their filename replaced with an underscore, to show they are
1756 * compressed. The missing character is stored in the compressed file
1757 * itself. This is due to the restricted filename conventions of MS-DOS,
1758 * most operating systems, such as UNIX, simply append another file
1759 * extension to the existing filename. As mspack does not deal with
1760 * filenames, this is left up to you. If you wish to set the missing
1761 * character stored in the file header, use set_param() with the
1762 * #MSSZDDC_PARAM_MISSINGCHAR parameter.
1763 *
1764 * "Stream" compression (where the length of the input data is not
1765 * known) is not possible. The length of the input data is stored in the
1766 * header of the SZDD file and must therefore be known before any data
1767 * is compressed. Due to technical limitations of the file format, the
1768 * maximum size of uncompressed file that will be accepted is 2147483647
1769 * bytes.
1770 *
1771 * @param self a self-referential pointer to the msszdd_compressor
1772 * instance being called
1773 * @param input the name of the file to compressed. This is passed
1774 * passed directly to mspack_system::open()
1775 * @param output the name of the file to write compressed data to.
1776 * This is passed directly to mspack_system::open().
1777 * @param length the length of the uncompressed file, or -1 to indicate
1778 * that this should be determined automatically by using
1779 * mspack_system::seek() on the input file.
1780 * @return an error code, or MSPACK_ERR_OK if successful
1781 * @see set_param()
1782 */
1783 int (*compress)(struct msszdd_compressor *self,
1784 const char *input,
1785 const char *output,
1786 off_t length);
1787
1788 /**
1789 * Sets an SZDD compression engine parameter.
1790 *
1791 * The following parameters are defined:
1792
1793 * - #MSSZDDC_PARAM_CHARACTER: the "missing character", the last character
1794 * in the uncompressed file's filename, which is traditionally replaced
1795 * with an underscore to show the file is compressed. Traditionally,
1796 * this can only be a character that is a valid part of an MS-DOS,
1797 * filename, but libmspack permits any character between 0x00 and 0xFF
1798 * to be stored. 0x00 is the default, and it represents "no character
1799 * stored".
1800 *
1801 * @param self a self-referential pointer to the msszdd_compressor
1802 * instance being called
1803 * @param param the parameter to set
1804 * @param value the value to set the parameter to
1805 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
1806 * is a problem with either parameter or value.
1807 * @see compress()
1808 */
1809 int (*set_param)(struct msszdd_compressor *self,
1810 int param,
1811 unsigned int value);
1812
1813 /**
1814 * Returns the error code set by the most recently called method.
1815 *
1816 * @param self a self-referential pointer to the msszdd_compressor
1817 * instance being called
1818 * @return the most recent error code
1819 * @see compress()
1820 */
1821 int (*last_error)(struct mschm_decompressor *self);
1822};
1823
1824/**
1825 * A decompressor for SZDD compressed files.
1826 *
1827 * All fields are READ ONLY.
1828 *
1829 * @see mspack_create_szdd_decompressor(), mspack_destroy_szdd_decompressor()
1830 */
1831struct msszdd_decompressor {
1832 /**
1833 * Opens a SZDD file and reads the header.
1834 *
1835 * If the file opened is a valid SZDD file, all headers will be read and
1836 * a msszddd_header structure will be returned.
1837 *
1838 * In the case of an error occuring, NULL is returned and the error code
1839 * is available from last_error().
1840 *
1841 * The filename pointer should be considered "in use" until close() is
1842 * called on the SZDD file.
1843 *
1844 * @param self a self-referential pointer to the msszdd_decompressor
1845 * instance being called
1846 * @param filename the filename of the SZDD compressed file. This is
1847 * passed directly to mspack_system::open().
1848 * @return a pointer to a msszddd_header structure, or NULL on failure
1849 * @see close()
1850 */
1851 struct msszddd_header *(*open)(struct msszdd_decompressor *self,
1852 const char *filename);
1853
1854 /**
1855 * Closes a previously opened SZDD file.
1856 *
1857 * This closes a SZDD file and frees the msszddd_header associated with
1858 * it.
1859 *
1860 * The SZDD header pointer is now invalid and cannot be used again.
1861 *
1862 * @param self a self-referential pointer to the msszdd_decompressor
1863 * instance being called
1864 * @param szdd the SZDD file to close
1865 * @see open()
1866 */
1867 void (*close)(struct msszdd_decompressor *self,
1868 struct msszddd_header *szdd);
1869
1870 /**
1871 * Extracts the compressed data from a SZDD file.
1872 *
1873 * This decompresses the compressed SZDD data stream and writes it to
1874 * an output file.
1875 *
1876 * @param self a self-referential pointer to the msszdd_decompressor
1877 * instance being called
1878 * @param szdd the SZDD file to extract data from
1879 * @param filename the filename to write the decompressed data to. This
1880 * is passed directly to mspack_system::open().
1881 * @return an error code, or MSPACK_ERR_OK if successful
1882 */
1883 int (*extract)(struct msszdd_decompressor *self,
1884 struct msszddd_header *szdd,
1885 const char *filename);
1886
1887 /**
1888 * Decompresses an SZDD file to an output file in one step.
1889 *
1890 * This opens an SZDD file as input, reads the header, then decompresses
1891 * the compressed data immediately to an output file, finally closing
1892 * both the input and output file. It is more convenient to use than
1893 * open() then extract() then close(), if you do not need to know the
1894 * SZDD output size or missing character.
1895 *
1896 * @param self a self-referential pointer to the msszdd_decompressor
1897 * instance being called
1898 * @param input the filename of the input SZDD file. This is passed
1899 * directly to mspack_system::open().
1900 * @param output the filename to write the decompressed data to. This
1901 * is passed directly to mspack_system::open().
1902 * @return an error code, or MSPACK_ERR_OK if successful
1903 */
1904 int (*decompress)(struct msszdd_decompressor *self,
1905 const char *input,
1906 const char *output);
1907
1908 /**
1909 * Returns the error code set by the most recently called method.
1910 *
1911 * This is useful for open() which does not return an
1912 * error code directly.
1913 *
1914 * @param self a self-referential pointer to the msszdd_decompressor
1915 * instance being called
1916 * @return the most recent error code
1917 * @see open(), extract(), decompress()
1918 */
1919 int (*last_error)(struct msszdd_decompressor *self);
1920};
1921
1922/* --- support for KWAJ file format ---------------------------------------- */
1923
1924/** mskwaj_compressor::set_param() parameter: compression type */
1925#define MSKWAJC_PARAM_COMP_TYPE (0)
1926
1927/** mskwaj_compressor::set_param() parameter: include the length of the
1928 * uncompressed file in the header?
1929 */
1930#define MSKWAJC_PARAM_INCLUDE_LENGTH (1)
1931
1932/** KWAJ compression type: no compression. */
1933#define MSKWAJ_COMP_NONE (0)
1934/** KWAJ compression type: no compression, 0xFF XOR "encryption". */
1935#define MSKWAJ_COMP_XOR (1)
1936/** KWAJ compression type: LZSS (same method as SZDD) */
1937#define MSKWAJ_COMP_SZDD (2)
1938/** KWAJ compression type: LZ+Huffman compression */
1939#define MSKWAJ_COMP_LZH (3)
1940
1941/** KWAJ optional header flag: decompressed file length is included */
1942#define MSKWAJ_HDR_HASLENGTH (0x01)
1943
1944/** KWAJ optional header flag: unknown 2-byte structure is included */
1945#define MSKWAJ_HDR_HASUNKNOWN1 (0x02)
1946
1947/** KWAJ optional header flag: unknown multi-sized structure is included */
1948#define MSKWAJ_HDR_HASUNKNOWN2 (0x04)
1949
1950/** KWAJ optional header flag: file name (no extension) is included */
1951#define MSKWAJ_HDR_HASFILENAME (0x08)
1952
1953/** KWAJ optional header flag: file extension is included */
1954#define MSKWAJ_HDR_HASFILEEXT (0x10)
1955
1956/** KWAJ optional header flag: extra text is included */
1957#define MSKWAJ_HDR_HASEXTRATEXT (0x20)
1958
1959/**
1960 * A structure which represents an KWAJ compressed file.
1961 *
1962 * All fields are READ ONLY.
1963 */
1964struct mskwajd_header {
1965 /** The compression type; should be one of #MSKWAJ_COMP_NONE,
1966 * #MSKWAJ_COMP_XOR, #MSKWAJ_COMP_SZDD or #MSKWAJ_COMP_LZH
1967 */
1968 unsigned short comp_type;
1969
1970 /** The offset in the file where the compressed data stream begins */
1971 off_t data_offset;
1972
1973 /** Flags indicating which optional headers were included. */
1974 int headers;
1975
1976 /** The amount of uncompressed data in the file, or 0 if not present. */
1977 off_t length;
1978
1979 /** output filename, or NULL if not present */
1980 char *filename;
1981
1982 /** extra uncompressed data (usually text) in the header.
1983 * This data can contain nulls so use extra_length to get the size.
1984 */
1985 char *extra;
1986
1987 /** length of extra uncompressed data in the header */
1988 unsigned short extra_length;
1989};
1990
1991/**
1992 * A compressor for the KWAJ file format.
1993 *
1994 * All fields are READ ONLY.
1995 *
1996 * @see mspack_create_kwaj_compressor(), mspack_destroy_kwaj_compressor()
1997 */
1998struct mskwaj_compressor {
1999 /**
2000 * Reads an input file and creates a compressed output file in the
2001 * KWAJ compressed file format. The KWAJ compression format is quick
2002 * but gives poor compression. It is possible for the compressed output
2003 * file to be larger than the input file.
2004 *
2005 * @param self a self-referential pointer to the mskwaj_compressor
2006 * instance being called
2007 * @param input the name of the file to compressed. This is passed
2008 * passed directly to mspack_system::open()
2009 * @param output the name of the file to write compressed data to.
2010 * This is passed directly to mspack_system::open().
2011 * @param length the length of the uncompressed file, or -1 to indicate
2012 * that this should be determined automatically by using
2013 * mspack_system::seek() on the input file.
2014 * @return an error code, or MSPACK_ERR_OK if successful
2015 * @see set_param()
2016 */
2017 int (*compress)(struct mskwaj_compressor *self,
2018 const char *input,
2019 const char *output,
2020 off_t length);
2021
2022 /**
2023 * Sets an KWAJ compression engine parameter.
2024 *
2025 * The following parameters are defined:
2026 *
2027 * - #MSKWAJC_PARAM_COMP_TYPE: the compression method to use. Must
2028 * be one of #MSKWAJC_COMP_NONE, #MSKWAJC_COMP_XOR, #MSKWAJ_COMP_SZDD
2029 * or #MSKWAJ_COMP_LZH. The default is #MSKWAJ_COMP_LZH.
2030 *
2031 * - #MSKWAJC_PARAM_INCLUDE_LENGTH: a boolean; should the compressed
2032 * output file should include the uncompressed length of the input
2033 * file in the header? This adds 4 bytes to the size of the output
2034 * file. A value of zero says "no", non-zero says "yes". The default
2035 * is "no".
2036 *
2037 * @param self a self-referential pointer to the mskwaj_compressor
2038 * instance being called
2039 * @param param the parameter to set
2040 * @param value the value to set the parameter to
2041 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
2042 * is a problem with either parameter or value.
2043 * @see generate()
2044 */
2045 int (*set_param)(struct mskwaj_compressor *self,
2046 int param,
2047 unsigned int value);
2048
2049
2050 /**
2051 * Sets the original filename of the file before compression,
2052 * which will be stored in the header of the output file.
2053 *
2054 * The filename should be a null-terminated string, it must be an
2055 * MS-DOS "8.3" type filename (up to 8 bytes for the filename, then
2056 * optionally a "." and up to 3 bytes for a filename extension).
2057 *
2058 * If NULL is passed as the filename, no filename is included in the
2059 * header. This is the default.
2060 *
2061 * @param self a self-referential pointer to the mskwaj_compressor
2062 * instance being called
2063 * @param filename the original filename to use
2064 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if the
2065 * filename is too long
2066 */
2067 int (*set_filename)(struct mskwaj_compressor *self,
2068 const char *filename);
2069
2070 /**
2071 * Sets arbitrary data that will be stored in the header of the
2072 * output file, uncompressed. It can be up to roughly 64 kilobytes,
2073 * as the overall size of the header must not exceed 65535 bytes.
2074 * The data can contain null bytes if desired.
2075 *
2076 * If NULL is passed as the data pointer, or zero is passed as the
2077 * length, no extra data is included in the header. This is the
2078 * default.
2079 *
2080 * @param self a self-referential pointer to the mskwaj_compressor
2081 * instance being called
2082 * @param data a pointer to the data to be stored in the header
2083 * @param bytes the length of the data in bytes
2084 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS extra data
2085 * is too long
2086 */
2087 int (*set_extra_data)(struct mskwaj_compressor *self,
2088 void *data,
2089 size_t bytes);
2090
2091 /**
2092 * Returns the error code set by the most recently called method.
2093 *
2094 * @param self a self-referential pointer to the mskwaj_compressor
2095 * instance being called
2096 * @return the most recent error code
2097 * @see compress()
2098 */
2099 int (*last_error)(struct mschm_decompressor *self);
2100};
2101
2102/**
2103 * A decompressor for KWAJ compressed files.
2104 *
2105 * All fields are READ ONLY.
2106 *
2107 * @see mspack_create_kwaj_decompressor(), mspack_destroy_kwaj_decompressor()
2108 */
2109struct mskwaj_decompressor {
2110 /**
2111 * Opens a KWAJ file and reads the header.
2112 *
2113 * If the file opened is a valid KWAJ file, all headers will be read and
2114 * a mskwajd_header structure will be returned.
2115 *
2116 * In the case of an error occuring, NULL is returned and the error code
2117 * is available from last_error().
2118 *
2119 * The filename pointer should be considered "in use" until close() is
2120 * called on the KWAJ file.
2121 *
2122 * @param self a self-referential pointer to the mskwaj_decompressor
2123 * instance being called
2124 * @param filename the filename of the KWAJ compressed file. This is
2125 * passed directly to mspack_system::open().
2126 * @return a pointer to a mskwajd_header structure, or NULL on failure
2127 * @see close()
2128 */
2129 struct mskwajd_header *(*open)(struct mskwaj_decompressor *self,
2130 const char *filename);
2131
2132 /**
2133 * Closes a previously opened KWAJ file.
2134 *
2135 * This closes a KWAJ file and frees the mskwajd_header associated
2136 * with it. The KWAJ header pointer is now invalid and cannot be
2137 * used again.
2138 *
2139 * @param self a self-referential pointer to the mskwaj_decompressor
2140 * instance being called
2141 * @param kwaj the KWAJ file to close
2142 * @see open()
2143 */
2144 void (*close)(struct mskwaj_decompressor *self,
2145 struct mskwajd_header *kwaj);
2146
2147 /**
2148 * Extracts the compressed data from a KWAJ file.
2149 *
2150 * This decompresses the compressed KWAJ data stream and writes it to
2151 * an output file.
2152 *
2153 * @param self a self-referential pointer to the mskwaj_decompressor
2154 * instance being called
2155 * @param kwaj the KWAJ file to extract data from
2156 * @param filename the filename to write the decompressed data to. This
2157 * is passed directly to mspack_system::open().
2158 * @return an error code, or MSPACK_ERR_OK if successful
2159 */
2160 int (*extract)(struct mskwaj_decompressor *self,
2161 struct mskwajd_header *kwaj,
2162 const char *filename);
2163
2164 /**
2165 * Decompresses an KWAJ file to an output file in one step.
2166 *
2167 * This opens an KWAJ file as input, reads the header, then decompresses
2168 * the compressed data immediately to an output file, finally closing
2169 * both the input and output file. It is more convenient to use than
2170 * open() then extract() then close(), if you do not need to know the
2171 * KWAJ output size or output filename.
2172 *
2173 * @param self a self-referential pointer to the mskwaj_decompressor
2174 * instance being called
2175 * @param input the filename of the input KWAJ file. This is passed
2176 * directly to mspack_system::open().
2177 * @param output the filename to write the decompressed data to. This
2178 * is passed directly to mspack_system::open().
2179 * @return an error code, or MSPACK_ERR_OK if successful
2180 */
2181 int (*decompress)(struct mskwaj_decompressor *self,
2182 const char *input,
2183 const char *output);
2184
2185 /**
2186 * Returns the error code set by the most recently called method.
2187 *
2188 * This is useful for open() which does not return an
2189 * error code directly.
2190 *
2191 * @param self a self-referential pointer to the mskwaj_decompressor
2192 * instance being called
2193 * @return the most recent error code
2194 * @see open(), search()
2195 */
2196 int (*last_error)(struct mskwaj_decompressor *self);
2197};
2198
2199#ifdef __cplusplus
2200}
2201#endif
2202
2203#endif
diff --git a/rbutil/rbutilqt/mspack/mszip.h b/rbutil/rbutilqt/mspack/mszip.h
new file mode 100644
index 0000000000..13c9542ee6
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/mszip.h
@@ -0,0 +1,121 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The deflate method was created by Phil Katz. MSZIP is equivalent to the
5 * deflate method.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13#ifndef MSPACK_MSZIP_H
14#define MSPACK_MSZIP_H 1
15
16#ifdef __cplusplus
17extern "C" {
18#endif
19
20/* MSZIP (deflate) compression / (inflate) decompression definitions */
21
22#define MSZIP_FRAME_SIZE (32768) /* size of LZ history window */
23#define MSZIP_LITERAL_MAXSYMBOLS (288) /* literal/length huffman tree */
24#define MSZIP_LITERAL_TABLEBITS (9)
25#define MSZIP_DISTANCE_MAXSYMBOLS (32) /* distance huffman tree */
26#define MSZIP_DISTANCE_TABLEBITS (6)
27
28/* if there are less direct lookup entries than symbols, the longer
29 * code pointers will be <= maxsymbols. This must not happen, or we
30 * will decode entries badly */
31#if (1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2)
32# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
33#else
34# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
35 (MSZIP_LITERAL_MAXSYMBOLS * 2))
36#endif
37
38#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
39# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
40#else
41# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
42 (MSZIP_DISTANCE_MAXSYMBOLS * 2))
43#endif
44
45struct mszipd_stream {
46 struct mspack_system *sys; /* I/O routines */
47 struct mspack_file *input; /* input file handle */
48 struct mspack_file *output; /* output file handle */
49 unsigned int window_posn; /* offset within window */
50
51 /* inflate() will call this whenever the window should be emptied. */
52 int (*flush_window)(struct mszipd_stream *, unsigned int);
53
54 int error, repair_mode, bytes_output;
55
56 /* I/O buffering */
57 unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end, input_end;
58 unsigned int bit_buffer, bits_left, inbuf_size;
59
60
61 /* huffman code lengths */
62 unsigned char LITERAL_len[MSZIP_LITERAL_MAXSYMBOLS];
63 unsigned char DISTANCE_len[MSZIP_DISTANCE_MAXSYMBOLS];
64
65 /* huffman decoding tables */
66 unsigned short LITERAL_table [MSZIP_LITERAL_TABLESIZE];
67 unsigned short DISTANCE_table[MSZIP_DISTANCE_TABLESIZE];
68
69 /* 32kb history window */
70 unsigned char window[MSZIP_FRAME_SIZE];
71};
72
73/* allocates MS-ZIP decompression stream for decoding the given stream.
74 *
75 * - uses system->alloc() to allocate memory
76 *
77 * - returns NULL if not enough memory
78 *
79 * - input_buffer_size is how many bytes to use as an input bitstream buffer
80 *
81 * - if repair_mode is non-zero, errors in decompression will be skipped
82 * and 'holes' left will be filled with zero bytes. This allows at least
83 * a partial recovery of erroneous data.
84 */
85extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
86 struct mspack_file *input,
87 struct mspack_file *output,
88 int input_buffer_size,
89 int repair_mode);
90
91/* decompresses, or decompresses more of, an MS-ZIP stream.
92 *
93 * - out_bytes of data will be decompressed and the function will return
94 * with an MSPACK_ERR_OK return code.
95 *
96 * - decompressing will stop as soon as out_bytes is reached. if the true
97 * amount of bytes decoded spills over that amount, they will be kept for
98 * a later invocation of mszipd_decompress().
99 *
100 * - the output bytes will be passed to the system->write() function given in
101 * mszipd_init(), using the output file handle given in mszipd_init(). More
102 * than one call may be made to system->write()
103 *
104 * - MS-ZIP will read input bytes as necessary using the system->read()
105 * function given in mszipd_init(), using the input file handle given in
106 * mszipd_init(). This will continue until system->read() returns 0 bytes,
107 * or an error.
108 */
109extern int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes);
110
111/* frees all stream associated with an MS-ZIP data stream
112 *
113 * - calls system->free() using the system pointer given in mszipd_init()
114 */
115void mszipd_free(struct mszipd_stream *zip);
116
117#ifdef __cplusplus
118}
119#endif
120
121#endif
diff --git a/rbutil/rbutilqt/mspack/mszipc.c b/rbutil/rbutilqt/mspack/mszipc.c
new file mode 100644
index 0000000000..2f1ecb2e87
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/mszipc.c
@@ -0,0 +1,18 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The deflate method was created by Phil Katz. MSZIP is equivalent to the
5 * deflate method.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13/* MS-ZIP compression implementation */
14
15#include <system.h>
16#include <mszip.h>
17
18/* todo */
diff --git a/rbutil/rbutilqt/mspack/mszipd.c b/rbutil/rbutilqt/mspack/mszipd.c
new file mode 100644
index 0000000000..5b7ef4ff4d
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/mszipd.c
@@ -0,0 +1,475 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * The deflate method was created by Phil Katz. MSZIP is equivalent to the
5 * deflate method.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13/* MS-ZIP decompression implementation. */
14
15#include <system.h>
16#include <mszip.h>
17
18/* import bit-reading macros and code */
19#define BITS_TYPE struct mszipd_stream
20#define BITS_VAR zip
21#define BITS_ORDER_LSB
22#define BITS_LSB_TABLE
23#define READ_BYTES do { \
24 READ_IF_NEEDED; \
25 INJECT_BITS(*i_ptr++, 8); \
26} while (0)
27#include <readbits.h>
28
29/* import huffman macros and code */
30#define TABLEBITS(tbl) MSZIP_##tbl##_TABLEBITS
31#define MAXSYMBOLS(tbl) MSZIP_##tbl##_MAXSYMBOLS
32#define HUFF_TABLE(tbl,idx) zip->tbl##_table[idx]
33#define HUFF_LEN(tbl,idx) zip->tbl##_len[idx]
34#define HUFF_ERROR return INF_ERR_HUFFSYM
35#include <readhuff.h>
36
37#define FLUSH_IF_NEEDED do { \
38 if (zip->window_posn == MSZIP_FRAME_SIZE) { \
39 if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \
40 return INF_ERR_FLUSH; \
41 } \
42 zip->window_posn = 0; \
43 } \
44} while (0)
45
46/* match lengths for literal codes 257.. 285 */
47static const unsigned short lit_lengths[29] = {
48 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
49 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
50};
51
52/* match offsets for distance codes 0 .. 29 */
53static const unsigned short dist_offsets[30] = {
54 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
55 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
56};
57
58/* extra bits required for literal codes 257.. 285 */
59static const unsigned char lit_extrabits[29] = {
60 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
61 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
62};
63
64/* extra bits required for distance codes 0 .. 29 */
65static const unsigned char dist_extrabits[30] = {
66 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
67 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
68};
69
70/* the order of the bit length Huffman code lengths */
71static const unsigned char bitlen_order[19] = {
72 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
73};
74
75/* inflate() error codes */
76#define INF_ERR_BLOCKTYPE (-1) /* unknown block type */
77#define INF_ERR_COMPLEMENT (-2) /* block size complement mismatch */
78#define INF_ERR_FLUSH (-3) /* error from flush_window() callback */
79#define INF_ERR_BITBUF (-4) /* too many bits in bit buffer */
80#define INF_ERR_SYMLENS (-5) /* too many symbols in blocktype 2 header */
81#define INF_ERR_BITLENTBL (-6) /* failed to build bitlens huffman table */
82#define INF_ERR_LITERALTBL (-7) /* failed to build literals huffman table */
83#define INF_ERR_DISTANCETBL (-8) /* failed to build distance huffman table */
84#define INF_ERR_BITOVERRUN (-9) /* bitlen RLE code goes over table size */
85#define INF_ERR_BADBITLEN (-10) /* invalid bit-length code */
86#define INF_ERR_LITCODE (-11) /* out-of-range literal code */
87#define INF_ERR_DISTCODE (-12) /* out-of-range distance code */
88#define INF_ERR_DISTANCE (-13) /* somehow, distance is beyond 32k */
89#define INF_ERR_HUFFSYM (-14) /* out of bits decoding huffman symbol */
90
91static int zip_read_lens(struct mszipd_stream *zip) {
92 /* for the bit buffer and huffman decoding */
93 register unsigned int bit_buffer;
94 register int bits_left;
95 unsigned char *i_ptr, *i_end;
96
97 /* bitlen Huffman codes -- immediate lookup, 7 bit max code length */
98 unsigned short bl_table[(1 << 7)];
99 unsigned char bl_len[19];
100
101 unsigned char lens[MSZIP_LITERAL_MAXSYMBOLS + MSZIP_DISTANCE_MAXSYMBOLS];
102 unsigned int lit_codes, dist_codes, code, last_code=0, bitlen_codes, i, run;
103
104 RESTORE_BITS;
105
106 /* read the number of codes */
107 READ_BITS(lit_codes, 5); lit_codes += 257;
108 READ_BITS(dist_codes, 5); dist_codes += 1;
109 READ_BITS(bitlen_codes, 4); bitlen_codes += 4;
110 if (lit_codes > MSZIP_LITERAL_MAXSYMBOLS) return INF_ERR_SYMLENS;
111 if (dist_codes > MSZIP_DISTANCE_MAXSYMBOLS) return INF_ERR_SYMLENS;
112
113 /* read in the bit lengths in their unusual order */
114 for (i = 0; i < bitlen_codes; i++) READ_BITS(bl_len[bitlen_order[i]], 3);
115 while (i < 19) bl_len[bitlen_order[i++]] = 0;
116
117 /* create decoding table with an immediate lookup */
118 if (make_decode_table(19, 7, &bl_len[0], &bl_table[0])) {
119 return INF_ERR_BITLENTBL;
120 }
121
122 /* read literal / distance code lengths */
123 for (i = 0; i < (lit_codes + dist_codes); i++) {
124 /* single-level huffman lookup */
125 ENSURE_BITS(7);
126 code = bl_table[PEEK_BITS(7)];
127 REMOVE_BITS(bl_len[code]);
128
129 if (code < 16) lens[i] = last_code = code;
130 else {
131 switch (code) {
132 case 16: READ_BITS(run, 2); run += 3; code = last_code; break;
133 case 17: READ_BITS(run, 3); run += 3; code = 0; break;
134 case 18: READ_BITS(run, 7); run += 11; code = 0; break;
135 default: D(("bad code!: %u", code)) return INF_ERR_BADBITLEN;
136 }
137 if ((i + run) > (lit_codes + dist_codes)) return INF_ERR_BITOVERRUN;
138 while (run--) lens[i++] = code;
139 i--;
140 }
141 }
142
143 /* copy LITERAL code lengths and clear any remaining */
144 i = lit_codes;
145 zip->sys->copy(&lens[0], &zip->LITERAL_len[0], i);
146 while (i < MSZIP_LITERAL_MAXSYMBOLS) zip->LITERAL_len[i++] = 0;
147
148 i = dist_codes;
149 zip->sys->copy(&lens[lit_codes], &zip->DISTANCE_len[0], i);
150 while (i < MSZIP_DISTANCE_MAXSYMBOLS) zip->DISTANCE_len[i++] = 0;
151
152 STORE_BITS;
153 return 0;
154}
155
156/* a clean implementation of RFC 1951 / inflate */
157static int inflate(struct mszipd_stream *zip) {
158 unsigned int last_block, block_type, distance, length, this_run, i;
159
160 /* for the bit buffer and huffman decoding */
161 register unsigned int bit_buffer;
162 register int bits_left;
163 register unsigned short sym;
164 unsigned char *i_ptr, *i_end;
165
166 RESTORE_BITS;
167
168 do {
169 /* read in last block bit */
170 READ_BITS(last_block, 1);
171
172 /* read in block type */
173 READ_BITS(block_type, 2);
174
175 if (block_type == 0) {
176 /* uncompressed block */
177 unsigned char lens_buf[4];
178
179 /* go to byte boundary */
180 i = bits_left & 7; REMOVE_BITS(i);
181
182 /* read 4 bytes of data, emptying the bit-buffer if necessary */
183 for (i = 0; (bits_left >= 8); i++) {
184 if (i == 4) return INF_ERR_BITBUF;
185 lens_buf[i] = PEEK_BITS(8);
186 REMOVE_BITS(8);
187 }
188 if (bits_left != 0) return INF_ERR_BITBUF;
189 while (i < 4) {
190 READ_IF_NEEDED;
191 lens_buf[i++] = *i_ptr++;
192 }
193
194 /* get the length and its complement */
195 length = lens_buf[0] | (lens_buf[1] << 8);
196 i = lens_buf[2] | (lens_buf[3] << 8);
197 if (length != (~i & 0xFFFF)) return INF_ERR_COMPLEMENT;
198
199 /* read and copy the uncompressed data into the window */
200 while (length > 0) {
201 READ_IF_NEEDED;
202
203 this_run = length;
204 if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
205 if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
206 this_run = MSZIP_FRAME_SIZE - zip->window_posn;
207
208 zip->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run);
209 zip->window_posn += this_run;
210 i_ptr += this_run;
211 length -= this_run;
212 FLUSH_IF_NEEDED;
213 }
214 }
215 else if ((block_type == 1) || (block_type == 2)) {
216 /* Huffman-compressed LZ77 block */
217 unsigned int match_posn, code;
218
219 if (block_type == 1) {
220 /* block with fixed Huffman codes */
221 i = 0;
222 while (i < 144) zip->LITERAL_len[i++] = 8;
223 while (i < 256) zip->LITERAL_len[i++] = 9;
224 while (i < 280) zip->LITERAL_len[i++] = 7;
225 while (i < 288) zip->LITERAL_len[i++] = 8;
226 for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
227 }
228 else {
229 /* block with dynamic Huffman codes */
230 STORE_BITS;
231 if ((i = zip_read_lens(zip))) return i;
232 RESTORE_BITS;
233 }
234
235 /* now huffman lengths are read for either kind of block,
236 * create huffman decoding tables */
237 if (make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS,
238 &zip->LITERAL_len[0], &zip->LITERAL_table[0]))
239 {
240 return INF_ERR_LITERALTBL;
241 }
242
243 if (make_decode_table(MSZIP_DISTANCE_MAXSYMBOLS,MSZIP_DISTANCE_TABLEBITS,
244 &zip->DISTANCE_len[0], &zip->DISTANCE_table[0]))
245 {
246 return INF_ERR_DISTANCETBL;
247 }
248
249 /* decode forever until end of block code */
250 for (;;) {
251 READ_HUFFSYM(LITERAL, code);
252 if (code < 256) {
253 zip->window[zip->window_posn++] = (unsigned char) code;
254 FLUSH_IF_NEEDED;
255 }
256 else if (code == 256) {
257 /* END OF BLOCK CODE: loop break point */
258 break;
259 }
260 else {
261 code -= 257; /* codes 257-285 are matches */
262 if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */
263 READ_BITS_T(length, lit_extrabits[code]);
264 length += lit_lengths[code];
265
266 READ_HUFFSYM(DISTANCE, code);
267 if (code > 30) return INF_ERR_DISTCODE;
268 READ_BITS_T(distance, dist_extrabits[code]);
269 distance += dist_offsets[code];
270
271 /* match position is window position minus distance. If distance
272 * is more than window position numerically, it must 'wrap
273 * around' the frame size. */
274 match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0)
275 + zip->window_posn - distance;
276
277 /* copy match */
278 if (length < 12) {
279 /* short match, use slower loop but no loop setup code */
280 while (length--) {
281 zip->window[zip->window_posn++] = zip->window[match_posn++];
282 match_posn &= MSZIP_FRAME_SIZE - 1;
283 FLUSH_IF_NEEDED;
284 }
285 }
286 else {
287 /* longer match, use faster loop but with setup expense */
288 unsigned char *runsrc, *rundest;
289 do {
290 this_run = length;
291 if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
292 this_run = MSZIP_FRAME_SIZE - match_posn;
293 if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE)
294 this_run = MSZIP_FRAME_SIZE - zip->window_posn;
295
296 rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run;
297 runsrc = &zip->window[match_posn]; match_posn += this_run;
298 length -= this_run;
299 while (this_run--) *rundest++ = *runsrc++;
300 if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
301 FLUSH_IF_NEEDED;
302 } while (length > 0);
303 }
304
305 } /* else (code >= 257) */
306
307 } /* for(;;) -- break point at 'code == 256' */
308 }
309 else {
310 /* block_type == 3 -- bad block type */
311 return INF_ERR_BLOCKTYPE;
312 }
313 } while (!last_block);
314
315 /* flush the remaining data */
316 if (zip->window_posn) {
317 if (zip->flush_window(zip, zip->window_posn)) return INF_ERR_FLUSH;
318 }
319 STORE_BITS;
320
321 /* return success */
322 return 0;
323}
324
325/* inflate() calls this whenever the window should be flushed. As
326 * MSZIP only expands to the size of the window, the implementation used
327 * simply keeps track of the amount of data flushed, and if more than 32k
328 * is flushed, an error is raised.
329 */
330static int mszipd_flush_window(struct mszipd_stream *zip,
331 unsigned int data_flushed)
332{
333 zip->bytes_output += data_flushed;
334 if (zip->bytes_output > MSZIP_FRAME_SIZE) {
335 D(("overflow: %u bytes flushed, total is now %u",
336 data_flushed, zip->bytes_output))
337 return 1;
338 }
339 return 0;
340}
341
342struct mszipd_stream *mszipd_init(struct mspack_system *system,
343 struct mspack_file *input,
344 struct mspack_file *output,
345 int input_buffer_size,
346 int repair_mode)
347{
348 struct mszipd_stream *zip;
349
350 if (!system) return NULL;
351
352 input_buffer_size = (input_buffer_size + 1) & -2;
353 if (!input_buffer_size) return NULL;
354
355 /* allocate decompression state */
356 if (!(zip = (struct mszipd_stream *) system->alloc(system, sizeof(struct mszipd_stream)))) {
357 return NULL;
358 }
359
360 /* allocate input buffer */
361 zip->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
362 if (!zip->inbuf) {
363 system->free(zip);
364 return NULL;
365 }
366
367 /* initialise decompression state */
368 zip->sys = system;
369 zip->input = input;
370 zip->output = output;
371 zip->inbuf_size = input_buffer_size;
372 zip->input_end = 0;
373 zip->error = MSPACK_ERR_OK;
374 zip->repair_mode = repair_mode;
375 zip->flush_window = &mszipd_flush_window;
376
377 zip->i_ptr = zip->i_end = &zip->inbuf[0];
378 zip->o_ptr = zip->o_end = NULL;
379 zip->bit_buffer = 0; zip->bits_left = 0;
380 return zip;
381}
382
383int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes) {
384 /* for the bit buffer */
385 register unsigned int bit_buffer;
386 register int bits_left;
387 unsigned char *i_ptr, *i_end;
388
389 int i, state, error;
390
391 /* easy answers */
392 if (!zip || (out_bytes < 0)) return MSPACK_ERR_ARGS;
393 if (zip->error) return zip->error;
394
395 /* flush out any stored-up bytes before we begin */
396 i = zip->o_end - zip->o_ptr;
397 if ((off_t) i > out_bytes) i = (int) out_bytes;
398 if (i) {
399 if (zip->sys->write(zip->output, zip->o_ptr, i) != i) {
400 return zip->error = MSPACK_ERR_WRITE;
401 }
402 zip->o_ptr += i;
403 out_bytes -= i;
404 }
405 if (out_bytes == 0) return MSPACK_ERR_OK;
406
407
408 while (out_bytes > 0) {
409 /* unpack another block */
410 RESTORE_BITS;
411
412 /* skip to next read 'CK' header */
413 i = bits_left & 7; REMOVE_BITS(i); /* align to bytestream */
414 state = 0;
415 do {
416 READ_BITS(i, 8);
417 if (i == 'C') state = 1;
418 else if ((state == 1) && (i == 'K')) state = 2;
419 else state = 0;
420 } while (state != 2);
421
422 /* inflate a block, repair and realign if necessary */
423 zip->window_posn = 0;
424 zip->bytes_output = 0;
425 STORE_BITS;
426 if ((error = inflate(zip))) {
427 D(("inflate error %d", error))
428 if (zip->repair_mode) {
429 /* recover partially-inflated buffers */
430 if (zip->bytes_output == 0 && zip->window_posn > 0) {
431 zip->flush_window(zip, zip->window_posn);
432 }
433 zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
434 MSZIP_FRAME_SIZE - zip->bytes_output);
435 for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
436 zip->window[i] = '\0';
437 }
438 zip->bytes_output = MSZIP_FRAME_SIZE;
439 }
440 else {
441 return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
442 }
443 }
444 zip->o_ptr = &zip->window[0];
445 zip->o_end = &zip->o_ptr[zip->bytes_output];
446
447 /* write a frame */
448 i = (out_bytes < (off_t)zip->bytes_output) ?
449 (int)out_bytes : zip->bytes_output;
450 if (zip->sys->write(zip->output, zip->o_ptr, i) != i) {
451 return zip->error = MSPACK_ERR_WRITE;
452 }
453
454 /* mspack errors (i.e. read errors) are fatal and can't be recovered */
455 if ((error > 0) && zip->repair_mode) return error;
456
457 zip->o_ptr += i;
458 out_bytes -= i;
459 }
460
461 if (out_bytes) {
462 D(("bytes left to output"))
463 return zip->error = MSPACK_ERR_DECRUNCH;
464 }
465 return MSPACK_ERR_OK;
466}
467
468void mszipd_free(struct mszipd_stream *zip) {
469 struct mspack_system *sys;
470 if (zip) {
471 sys = zip->sys;
472 sys->free(zip->inbuf);
473 sys->free(zip);
474 }
475}
diff --git a/rbutil/rbutilqt/mspack/qtm.h b/rbutil/rbutilqt/mspack/qtm.h
new file mode 100644
index 0000000000..ab0bb4c32c
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/qtm.h
@@ -0,0 +1,128 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The Quantum method was created by David Stafford, adapted by Microsoft
5 * Corporation.
6 *
7 * libmspack is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
9 *
10 * For further details, see the file COPYING.LIB distributed with libmspack
11 */
12
13#ifndef MSPACK_QTM_H
14#define MSPACK_QTM_H 1
15
16#ifdef __cplusplus
17extern "C" {
18#endif
19
20/* Quantum compression / decompression definitions */
21
22#define QTM_FRAME_SIZE (32768)
23
24struct qtmd_modelsym {
25 unsigned short sym, cumfreq;
26};
27
28struct qtmd_model {
29 int shiftsleft, entries;
30 struct qtmd_modelsym *syms;
31};
32
33struct qtmd_stream {
34 struct mspack_system *sys; /* I/O routines */
35 struct mspack_file *input; /* input file handle */
36 struct mspack_file *output; /* output file handle */
37
38 unsigned char *window; /* decoding window */
39 unsigned int window_size; /* window size */
40 unsigned int window_posn; /* decompression offset within window */
41 unsigned int frame_todo; /* bytes remaining for current frame */
42
43 unsigned short H, L, C; /* high/low/current: arith coding state */
44 unsigned char header_read; /* have we started decoding a new frame? */
45
46 int error;
47
48 /* I/O buffers */
49 unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
50 unsigned int bit_buffer, inbuf_size;
51 unsigned char bits_left, input_end;
52
53 /* four literal models, each representing 64 symbols
54 * model0 for literals from 0 to 63 (selector = 0)
55 * model1 for literals from 64 to 127 (selector = 1)
56 * model2 for literals from 128 to 191 (selector = 2)
57 * model3 for literals from 129 to 255 (selector = 3) */
58 struct qtmd_model model0, model1, model2, model3;
59
60 /* three match models.
61 * model4 for match with fixed length of 3 bytes
62 * model5 for match with fixed length of 4 bytes
63 * model6 for variable length match, encoded with model6len model */
64 struct qtmd_model model4, model5, model6, model6len;
65
66 /* selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6) */
67 struct qtmd_model model7;
68
69 /* symbol arrays for all models */
70 struct qtmd_modelsym m0sym[64 + 1];
71 struct qtmd_modelsym m1sym[64 + 1];
72 struct qtmd_modelsym m2sym[64 + 1];
73 struct qtmd_modelsym m3sym[64 + 1];
74 struct qtmd_modelsym m4sym[24 + 1];
75 struct qtmd_modelsym m5sym[36 + 1];
76 struct qtmd_modelsym m6sym[42 + 1], m6lsym[27 + 1];
77 struct qtmd_modelsym m7sym[7 + 1];
78};
79
80/* allocates Quantum decompression state for decoding the given stream.
81 *
82 * - returns NULL if window_bits is outwith the range 10 to 21 (inclusive).
83 *
84 * - uses system->alloc() to allocate memory
85 *
86 * - returns NULL if not enough memory
87 *
88 * - window_bits is the size of the Quantum window, from 1Kb (10) to 2Mb (21).
89 *
90 * - input_buffer_size is the number of bytes to use to store bitstream data.
91 */
92extern struct qtmd_stream *qtmd_init(struct mspack_system *system,
93 struct mspack_file *input,
94 struct mspack_file *output,
95 int window_bits,
96 int input_buffer_size);
97
98/* decompresses, or decompresses more of, a Quantum stream.
99 *
100 * - out_bytes of data will be decompressed and the function will return
101 * with an MSPACK_ERR_OK return code.
102 *
103 * - decompressing will stop as soon as out_bytes is reached. if the true
104 * amount of bytes decoded spills over that amount, they will be kept for
105 * a later invocation of qtmd_decompress().
106 *
107 * - the output bytes will be passed to the system->write() function given in
108 * qtmd_init(), using the output file handle given in qtmd_init(). More
109 * than one call may be made to system->write()
110 *
111 * - Quantum will read input bytes as necessary using the system->read()
112 * function given in qtmd_init(), using the input file handle given in
113 * qtmd_init(). This will continue until system->read() returns 0 bytes,
114 * or an error.
115 */
116extern int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes);
117
118/* frees all state associated with a Quantum data stream
119 *
120 * - calls system->free() using the system pointer given in qtmd_init()
121 */
122void qtmd_free(struct qtmd_stream *qtm);
123
124#ifdef __cplusplus
125}
126#endif
127
128#endif
diff --git a/rbutil/rbutilqt/mspack/qtmd.c b/rbutil/rbutilqt/mspack/qtmd.c
new file mode 100644
index 0000000000..12b27f5608
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/qtmd.c
@@ -0,0 +1,489 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * The Quantum method was created by David Stafford, adapted by Microsoft
5 * Corporation.
6 *
7 * This decompressor is based on an implementation by Matthew Russotto, used
8 * with permission.
9 *
10 * libmspack is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
12 *
13 * For further details, see the file COPYING.LIB distributed with libmspack
14 */
15
16/* Quantum decompression implementation */
17
18/* This decompressor was researched and implemented by Matthew Russotto. It
19 * has since been tidied up by Stuart Caie. More information can be found at
20 * http://www.speakeasy.org/~russotto/quantumcomp.html
21 */
22
23#include <system.h>
24#include <qtm.h>
25
26/* import bit-reading macros and code */
27#define BITS_TYPE struct qtmd_stream
28#define BITS_VAR qtm
29#define BITS_ORDER_MSB
30#define READ_BYTES do { \
31 unsigned char b0, b1; \
32 READ_IF_NEEDED; b0 = *i_ptr++; \
33 READ_IF_NEEDED; b1 = *i_ptr++; \
34 INJECT_BITS((b0 << 8) | b1, 16); \
35} while (0)
36#include <readbits.h>
37
38/* Quantum static data tables:
39 *
40 * Quantum uses 'position slots' to represent match offsets. For every
41 * match, a small 'position slot' number and a small offset from that slot
42 * are encoded instead of one large offset.
43 *
44 * position_base[] is an index to the position slot bases
45 *
46 * extra_bits[] states how many bits of offset-from-base data is needed.
47 *
48 * length_base[] and length_extra[] are equivalent in function, but are
49 * used for encoding selector 6 (variable length match) match lengths,
50 * instead of match offsets.
51 *
52 * They are generated with the following code:
53 * unsigned int i, offset;
54 * for (i = 0, offset = 0; i < 42; i++) {
55 * position_base[i] = offset;
56 * extra_bits[i] = ((i < 2) ? 0 : (i - 2)) >> 1;
57 * offset += 1 << extra_bits[i];
58 * }
59 * for (i = 0, offset = 0; i < 26; i++) {
60 * length_base[i] = offset;
61 * length_extra[i] = (i < 2 ? 0 : i - 2) >> 2;
62 * offset += 1 << length_extra[i];
63 * }
64 * length_base[26] = 254; length_extra[26] = 0;
65 */
66static const unsigned int position_base[42] = {
67 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
68 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
69 65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864
70};
71static const unsigned char extra_bits[42] = {
72 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
73 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19
74};
75static const unsigned char length_base[27] = {
76 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 18, 22, 26,
77 30, 38, 46, 54, 62, 78, 94, 110, 126, 158, 190, 222, 254
78};
79static const unsigned char length_extra[27] = {
80 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
81 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
82};
83
84
85/* Arithmetic decoder:
86 *
87 * GET_SYMBOL(model, var) fetches the next symbol from the stated model
88 * and puts it in var.
89 *
90 * If necessary, qtmd_update_model() is called.
91 */
92#define GET_SYMBOL(model, var) do { \
93 range = ((H - L) & 0xFFFF) + 1; \
94 symf = ((((C - L + 1) * model.syms[0].cumfreq)-1) / range) & 0xFFFF; \
95 \
96 for (i = 1; i < model.entries; i++) { \
97 if (model.syms[i].cumfreq <= symf) break; \
98 } \
99 (var) = model.syms[i-1].sym; \
100 \
101 range = (H - L) + 1; \
102 symf = model.syms[0].cumfreq; \
103 H = L + ((model.syms[i-1].cumfreq * range) / symf) - 1; \
104 L = L + ((model.syms[i].cumfreq * range) / symf); \
105 \
106 do { model.syms[--i].cumfreq += 8; } while (i > 0); \
107 if (model.syms[0].cumfreq > 3800) qtmd_update_model(&model); \
108 \
109 while (1) { \
110 if ((L & 0x8000) != (H & 0x8000)) { \
111 if ((L & 0x4000) && !(H & 0x4000)) { \
112 /* underflow case */ \
113 C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \
114 } \
115 else break; \
116 } \
117 L <<= 1; H = (H << 1) | 1; \
118 ENSURE_BITS(1); \
119 C = (C << 1) | PEEK_BITS(1); \
120 REMOVE_BITS(1); \
121 } \
122} while (0)
123
124static void qtmd_update_model(struct qtmd_model *model) {
125 struct qtmd_modelsym tmp;
126 int i, j;
127
128 if (--model->shiftsleft) {
129 for (i = model->entries - 1; i >= 0; i--) {
130 /* -1, not -2; the 0 entry saves this */
131 model->syms[i].cumfreq >>= 1;
132 if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
133 model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
134 }
135 }
136 }
137 else {
138 model->shiftsleft = 50;
139 for (i = 0; i < model->entries; i++) {
140 /* no -1, want to include the 0 entry */
141 /* this converts cumfreqs into frequencies, then shifts right */
142 model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
143 model->syms[i].cumfreq++; /* avoid losing things entirely */
144 model->syms[i].cumfreq >>= 1;
145 }
146
147 /* now sort by frequencies, decreasing order -- this must be an
148 * inplace selection sort, or a sort with the same (in)stability
149 * characteristics */
150 for (i = 0; i < model->entries - 1; i++) {
151 for (j = i + 1; j < model->entries; j++) {
152 if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
153 tmp = model->syms[i];
154 model->syms[i] = model->syms[j];
155 model->syms[j] = tmp;
156 }
157 }
158 }
159
160 /* then convert frequencies back to cumfreq */
161 for (i = model->entries - 1; i >= 0; i--) {
162 model->syms[i].cumfreq += model->syms[i+1].cumfreq;
163 }
164 }
165}
166
167/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */
168static void qtmd_init_model(struct qtmd_model *model,
169 struct qtmd_modelsym *syms, int start, int len)
170{
171 int i;
172
173 model->shiftsleft = 4;
174 model->entries = len;
175 model->syms = syms;
176
177 for (i = 0; i <= len; i++) {
178 syms[i].sym = start + i; /* actual symbol */
179 syms[i].cumfreq = len - i; /* current frequency of that symbol */
180 }
181}
182
183
184/*-------- main Quantum code --------*/
185
186struct qtmd_stream *qtmd_init(struct mspack_system *system,
187 struct mspack_file *input,
188 struct mspack_file *output,
189 int window_bits, int input_buffer_size)
190{
191 unsigned int window_size = 1 << window_bits;
192 struct qtmd_stream *qtm;
193 int i;
194
195 if (!system) return NULL;
196
197 /* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
198 if (window_bits < 10 || window_bits > 21) return NULL;
199
200 input_buffer_size = (input_buffer_size + 1) & -2;
201 if (input_buffer_size < 2) return NULL;
202
203 /* allocate decompression state */
204 if (!(qtm = (struct qtmd_stream *) system->alloc(system, sizeof(struct qtmd_stream)))) {
205 return NULL;
206 }
207
208 /* allocate decompression window and input buffer */
209 qtm->window = (unsigned char *) system->alloc(system, (size_t) window_size);
210 qtm->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
211 if (!qtm->window || !qtm->inbuf) {
212 system->free(qtm->window);
213 system->free(qtm->inbuf);
214 system->free(qtm);
215 return NULL;
216 }
217
218 /* initialise decompression state */
219 qtm->sys = system;
220 qtm->input = input;
221 qtm->output = output;
222 qtm->inbuf_size = input_buffer_size;
223 qtm->window_size = window_size;
224 qtm->window_posn = 0;
225 qtm->frame_todo = QTM_FRAME_SIZE;
226 qtm->header_read = 0;
227 qtm->error = MSPACK_ERR_OK;
228
229 qtm->i_ptr = qtm->i_end = &qtm->inbuf[0];
230 qtm->o_ptr = qtm->o_end = &qtm->window[0];
231 qtm->input_end = 0;
232 qtm->bits_left = 0;
233 qtm->bit_buffer = 0;
234
235 /* initialise arithmetic coding models
236 * - model 4 depends on window size, ranges from 20 to 24
237 * - model 5 depends on window size, ranges from 20 to 36
238 * - model 6pos depends on window size, ranges from 20 to 42
239 */
240 i = window_bits * 2;
241 qtmd_init_model(&qtm->model0, &qtm->m0sym[0], 0, 64);
242 qtmd_init_model(&qtm->model1, &qtm->m1sym[0], 64, 64);
243 qtmd_init_model(&qtm->model2, &qtm->m2sym[0], 128, 64);
244 qtmd_init_model(&qtm->model3, &qtm->m3sym[0], 192, 64);
245 qtmd_init_model(&qtm->model4, &qtm->m4sym[0], 0, (i > 24) ? 24 : i);
246 qtmd_init_model(&qtm->model5, &qtm->m5sym[0], 0, (i > 36) ? 36 : i);
247 qtmd_init_model(&qtm->model6, &qtm->m6sym[0], 0, i);
248 qtmd_init_model(&qtm->model6len, &qtm->m6lsym[0], 0, 27);
249 qtmd_init_model(&qtm->model7, &qtm->m7sym[0], 0, 7);
250
251 /* all ok */
252 return qtm;
253}
254
255int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
256 unsigned int frame_todo, frame_end, window_posn, match_offset, range;
257 unsigned char *window, *i_ptr, *i_end, *runsrc, *rundest;
258 int i, j, selector, extra, sym, match_length;
259 unsigned short H, L, C, symf;
260
261 register unsigned int bit_buffer;
262 register unsigned char bits_left;
263
264 /* easy answers */
265 if (!qtm || (out_bytes < 0)) return MSPACK_ERR_ARGS;
266 if (qtm->error) return qtm->error;
267
268 /* flush out any stored-up bytes before we begin */
269 i = qtm->o_end - qtm->o_ptr;
270 if ((off_t) i > out_bytes) i = (int) out_bytes;
271 if (i) {
272 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
273 return qtm->error = MSPACK_ERR_WRITE;
274 }
275 qtm->o_ptr += i;
276 out_bytes -= i;
277 }
278 if (out_bytes == 0) return MSPACK_ERR_OK;
279
280 /* restore local state */
281 RESTORE_BITS;
282 window = qtm->window;
283 window_posn = qtm->window_posn;
284 frame_todo = qtm->frame_todo;
285 H = qtm->H;
286 L = qtm->L;
287 C = qtm->C;
288
289 /* while we do not have enough decoded bytes in reserve: */
290 while ((qtm->o_end - qtm->o_ptr) < out_bytes) {
291 /* read header if necessary. Initialises H, L and C */
292 if (!qtm->header_read) {
293 H = 0xFFFF; L = 0; READ_BITS(C, 16);
294 qtm->header_read = 1;
295 }
296
297 /* decode more, up to the number of bytes needed, the frame boundary,
298 * or the window boundary, whichever comes first */
299 frame_end = window_posn + (out_bytes - (qtm->o_end - qtm->o_ptr));
300 if ((window_posn + frame_todo) < frame_end) {
301 frame_end = window_posn + frame_todo;
302 }
303 if (frame_end > qtm->window_size) {
304 frame_end = qtm->window_size;
305 }
306
307 while (window_posn < frame_end) {
308 GET_SYMBOL(qtm->model7, selector);
309 if (selector < 4) {
310 /* literal byte */
311 struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
312 ((selector == 1) ? &qtm->model1 :
313 ((selector == 2) ? &qtm->model2 :
314 &qtm->model3));
315 GET_SYMBOL((*mdl), sym);
316 window[window_posn++] = sym;
317 frame_todo--;
318 }
319 else {
320 /* match repeated string */
321 switch (selector) {
322 case 4: /* selector 4 = fixed length match (3 bytes) */
323 GET_SYMBOL(qtm->model4, sym);
324 READ_MANY_BITS(extra, extra_bits[sym]);
325 match_offset = position_base[sym] + extra + 1;
326 match_length = 3;
327 break;
328
329 case 5: /* selector 5 = fixed length match (4 bytes) */
330 GET_SYMBOL(qtm->model5, sym);
331 READ_MANY_BITS(extra, extra_bits[sym]);
332 match_offset = position_base[sym] + extra + 1;
333 match_length = 4;
334 break;
335
336 case 6: /* selector 6 = variable length match */
337 GET_SYMBOL(qtm->model6len, sym);
338 READ_MANY_BITS(extra, length_extra[sym]);
339 match_length = length_base[sym] + extra + 5;
340
341 GET_SYMBOL(qtm->model6, sym);
342 READ_MANY_BITS(extra, extra_bits[sym]);
343 match_offset = position_base[sym] + extra + 1;
344 break;
345
346 default:
347 /* should be impossible, model7 can only return 0-6 */
348 D(("got %d from selector", selector))
349 return qtm->error = MSPACK_ERR_DECRUNCH;
350 }
351
352 rundest = &window[window_posn];
353 frame_todo -= match_length;
354
355 /* does match destination wrap the window? This situation is possible
356 * where the window size is less than the 32k frame size, but matches
357 * must not go beyond a frame boundary */
358 if ((window_posn + match_length) > qtm->window_size) {
359 /* copy first part of match, before window end */
360 i = qtm->window_size - window_posn;
361 j = window_posn - match_offset;
362 while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
363
364 /* flush currently stored data */
365 i = (&window[qtm->window_size] - qtm->o_ptr);
366
367 /* this should not happen, but if it does then this code
368 * can't handle the situation (can't flush up to the end of
369 * the window, but can't break out either because we haven't
370 * finished writing the match). bail out in this case */
371 if (i > out_bytes) {
372 D(("during window-wrap match; %d bytes to flush but only need %d",
373 i, (int) out_bytes))
374 return qtm->error = MSPACK_ERR_DECRUNCH;
375 }
376 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
377 return qtm->error = MSPACK_ERR_WRITE;
378 }
379 out_bytes -= i;
380 qtm->o_ptr = &window[0];
381 qtm->o_end = &window[0];
382
383 /* copy second part of match, after window wrap */
384 rundest = &window[0];
385 i = match_length - (qtm->window_size - window_posn);
386 while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
387 window_posn = window_posn + match_length - qtm->window_size;
388
389 break; /* because "window_posn < frame_end" has now failed */
390 }
391 else {
392 /* normal match - output won't wrap window or frame end */
393 i = match_length;
394
395 /* does match _offset_ wrap the window? */
396 if (match_offset > window_posn) {
397 /* j = length from match offset to end of window */
398 j = match_offset - window_posn;
399 if (j > (int) qtm->window_size) {
400 D(("match offset beyond window boundaries"))
401 return qtm->error = MSPACK_ERR_DECRUNCH;
402 }
403 runsrc = &window[qtm->window_size - j];
404 if (j < i) {
405 /* if match goes over the window edge, do two copy runs */
406 i -= j; while (j-- > 0) *rundest++ = *runsrc++;
407 runsrc = window;
408 }
409 while (i-- > 0) *rundest++ = *runsrc++;
410 }
411 else {
412 runsrc = rundest - match_offset;
413 while (i-- > 0) *rundest++ = *runsrc++;
414 }
415 window_posn += match_length;
416 }
417 } /* if (window_posn+match_length > frame_end) */
418 } /* while (window_posn < frame_end) */
419
420 qtm->o_end = &window[window_posn];
421
422 /* if we subtracted too much from frame_todo, it will
423 * wrap around past zero and go above its max value */
424 if (frame_todo > QTM_FRAME_SIZE) {
425 D(("overshot frame alignment"))
426 return qtm->error = MSPACK_ERR_DECRUNCH;
427 }
428
429 /* another frame completed? */
430 if (frame_todo == 0) {
431 /* re-align input */
432 if (bits_left & 7) REMOVE_BITS(bits_left & 7);
433
434 /* special Quantum hack -- cabd.c injects a trailer byte to allow the
435 * decompressor to realign itself. CAB Quantum blocks, unlike LZX
436 * blocks, can have anything from 0 to 4 trailing null bytes. */
437 do { READ_BITS(i, 8); } while (i != 0xFF);
438
439 qtm->header_read = 0;
440
441 frame_todo = QTM_FRAME_SIZE;
442 }
443
444 /* window wrap? */
445 if (window_posn == qtm->window_size) {
446 /* flush all currently stored data */
447 i = (qtm->o_end - qtm->o_ptr);
448 /* break out if we have more than enough to finish this request */
449 if (i >= out_bytes) break;
450 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
451 return qtm->error = MSPACK_ERR_WRITE;
452 }
453 out_bytes -= i;
454 qtm->o_ptr = &window[0];
455 qtm->o_end = &window[0];
456 window_posn = 0;
457 }
458
459 } /* while (more bytes needed) */
460
461 if (out_bytes) {
462 i = (int) out_bytes;
463 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
464 return qtm->error = MSPACK_ERR_WRITE;
465 }
466 qtm->o_ptr += i;
467 }
468
469 /* store local state */
470
471 STORE_BITS;
472 qtm->window_posn = window_posn;
473 qtm->frame_todo = frame_todo;
474 qtm->H = H;
475 qtm->L = L;
476 qtm->C = C;
477
478 return MSPACK_ERR_OK;
479}
480
481void qtmd_free(struct qtmd_stream *qtm) {
482 struct mspack_system *sys;
483 if (qtm) {
484 sys = qtm->sys;
485 sys->free(qtm->window);
486 sys->free(qtm->inbuf);
487 sys->free(qtm);
488 }
489}
diff --git a/rbutil/rbutilqt/mspack/readbits.h b/rbutil/rbutilqt/mspack/readbits.h
new file mode 100644
index 0000000000..457cbdd7d4
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/readbits.h
@@ -0,0 +1,207 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_READBITS_H
11#define MSPACK_READBITS_H 1
12
13/* this header defines macros that read data streams by
14 * the individual bits
15 *
16 * INIT_BITS initialises bitstream state in state structure
17 * STORE_BITS stores bitstream state in state structure
18 * RESTORE_BITS restores bitstream state from state structure
19 * ENSURE_BITS(n) ensure there are at least N bits in the bit buffer
20 * READ_BITS(var,n) takes N bits from the buffer and puts them in var
21 * PEEK_BITS(n) extracts without removing N bits from the bit buffer
22 * REMOVE_BITS(n) removes N bits from the bit buffer
23 *
24 * READ_BITS simply calls ENSURE_BITS, PEEK_BITS and REMOVE_BITS,
25 * which means it's limited to reading the number of bits you can
26 * ensure at any one time. It also fails if asked to read zero bits.
27 * If you need to read zero bits, or more bits than can be ensured in
28 * one go, use READ_MANY_BITS instead.
29 *
30 * These macros have variable names baked into them, so to use them
31 * you have to define some macros:
32 * - BITS_TYPE: the type name of your state structure
33 * - BITS_VAR: the variable that points to your state structure
34 * - define BITS_ORDER_MSB if bits are read from the MSB, or
35 * define BITS_ORDER_LSB if bits are read from the LSB
36 * - READ_BYTES: some code that reads more data into the bit buffer,
37 * it should use READ_IF_NEEDED (calls read_input if the byte buffer
38 * is empty), then INJECT_BITS(data,n) to put data from the byte
39 * buffer into the bit buffer.
40 *
41 * You also need to define some variables and structure members:
42 * - unsigned char *i_ptr; // current position in the byte buffer
43 * - unsigned char *i_end; // end of the byte buffer
44 * - unsigned int bit_buffer; // the bit buffer itself
45 * - unsigned int bits_left; // number of bits remaining
46 *
47 * If you use read_input() and READ_IF_NEEDED, they also expect these
48 * structure members:
49 * - struct mspack_system *sys; // to access sys->read()
50 * - unsigned int error; // to record/return read errors
51 * - unsigned char input_end; // to mark reaching the EOF
52 * - unsigned char *inbuf; // the input byte buffer
53 * - unsigned int inbuf_size; // the size of the input byte buffer
54 *
55 * Your READ_BYTES implementation should read data from *i_ptr and
56 * put them in the bit buffer. READ_IF_NEEDED will call read_input()
57 * if i_ptr reaches i_end, and will fill up inbuf and set i_ptr to
58 * the start of inbuf and i_end to the end of inbuf.
59 *
60 * If you're reading in MSB order, the routines work by using the area
61 * beyond the MSB and the LSB of the bit buffer as a free source of
62 * zeroes when shifting. This avoids having to mask any bits. So we
63 * have to know the bit width of the bit buffer variable. We use
64 * <limits.h> and CHAR_BIT to find the size of the bit buffer in bits.
65 *
66 * If you are reading in LSB order, bits need to be masked. Normally
67 * this is done by computing the mask: N bits are masked by the value
68 * (1<<N)-1). However, you can define BITS_LSB_TABLE to use a lookup
69 * table instead of computing this. This adds two new macros,
70 * PEEK_BITS_T and READ_BITS_T which work the same way as PEEK_BITS
71 * and READ_BITS, except they use this lookup table. This is useful if
72 * you need to look up a number of bits that are only known at
73 * runtime, so the bit mask can't be turned into a constant by the
74 * compiler.
75
76 * The bit buffer datatype should be at least 32 bits wide: it must be
77 * possible to ENSURE_BITS(17), so it must be possible to add 16 new bits
78 * to the bit buffer when the bit buffer already has 1 to 15 bits left.
79 */
80
81#ifndef BITS_VAR
82# error "define BITS_VAR as the state structure poiner variable name"
83#endif
84#ifndef BITS_TYPE
85# error "define BITS_TYPE as the state structure type"
86#endif
87#if defined(BITS_ORDER_MSB) && defined(BITS_ORDER_LSB)
88# error "you must define either BITS_ORDER_MSB or BITS_ORDER_LSB"
89#else
90# if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
91# error "you must define BITS_ORDER_MSB or BITS_ORDER_LSB"
92# endif
93#endif
94
95#if HAVE_LIMITS_H
96# include <limits.h>
97#endif
98#ifndef CHAR_BIT
99# define CHAR_BIT (8)
100#endif
101#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
102
103#define INIT_BITS do { \
104 BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
105 BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
106 BITS_VAR->bit_buffer = 0; \
107 BITS_VAR->bits_left = 0; \
108 BITS_VAR->input_end = 0; \
109} while (0)
110
111#define STORE_BITS do { \
112 BITS_VAR->i_ptr = i_ptr; \
113 BITS_VAR->i_end = i_end; \
114 BITS_VAR->bit_buffer = bit_buffer; \
115 BITS_VAR->bits_left = bits_left; \
116} while (0)
117
118#define RESTORE_BITS do { \
119 i_ptr = BITS_VAR->i_ptr; \
120 i_end = BITS_VAR->i_end; \
121 bit_buffer = BITS_VAR->bit_buffer; \
122 bits_left = BITS_VAR->bits_left; \
123} while (0)
124
125#define ENSURE_BITS(nbits) do { \
126 while (bits_left < (nbits)) READ_BYTES; \
127} while (0)
128
129#define READ_BITS(val, nbits) do { \
130 ENSURE_BITS(nbits); \
131 (val) = PEEK_BITS(nbits); \
132 REMOVE_BITS(nbits); \
133} while (0)
134
135#define READ_MANY_BITS(val, bits) do { \
136 unsigned char needed = (bits), bitrun; \
137 (val) = 0; \
138 while (needed > 0) { \
139 if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
140 bitrun = (bits_left < needed) ? bits_left : needed; \
141 (val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
142 REMOVE_BITS(bitrun); \
143 needed -= bitrun; \
144 } \
145} while (0)
146
147#ifdef BITS_ORDER_MSB
148# define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits)))
149# define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits)))
150# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
151 (bitdata) << (BITBUF_WIDTH - (nbits) - bits_left)), (bits_left += (nbits)))
152#else /* BITS_ORDER_LSB */
153# define PEEK_BITS(nbits) (bit_buffer & ((1 << (nbits))-1))
154# define REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits)))
155# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
156 (bitdata) << bits_left), (bits_left += (nbits)))
157#endif
158
159#ifdef BITS_LSB_TABLE
160/* lsb_bit_mask[n] = (1 << n) - 1 */
161static const unsigned short lsb_bit_mask[17] = {
162 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
163 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
164};
165# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
166# define READ_BITS_T(val, nbits) do { \
167 ENSURE_BITS(nbits); \
168 (val) = PEEK_BITS_T(nbits); \
169 REMOVE_BITS(nbits); \
170} while (0)
171#endif
172
173#ifndef BITS_NO_READ_INPUT
174# define READ_IF_NEEDED do { \
175 if (i_ptr >= i_end) { \
176 if (read_input(BITS_VAR)) \
177 return BITS_VAR->error; \
178 i_ptr = BITS_VAR->i_ptr; \
179 i_end = BITS_VAR->i_end; \
180 } \
181} while (0)
182
183static int read_input(BITS_TYPE *p) {
184 int read = p->sys->read(p->input, &p->inbuf[0], (int)p->inbuf_size);
185 if (read < 0) return p->error = MSPACK_ERR_READ;
186
187 /* we might overrun the input stream by asking for bits we don't use,
188 * so fake 2 more bytes at the end of input */
189 if (read == 0) {
190 if (p->input_end) {
191 D(("out of input bytes"))
192 return p->error = MSPACK_ERR_READ;
193 }
194 else {
195 read = 2;
196 p->inbuf[0] = p->inbuf[1] = 0;
197 p->input_end = 1;
198 }
199 }
200
201 /* update i_ptr and i_end */
202 p->i_ptr = &p->inbuf[0];
203 p->i_end = &p->inbuf[read];
204 return MSPACK_ERR_OK;
205}
206#endif
207#endif
diff --git a/rbutil/rbutilqt/mspack/readhuff.h b/rbutil/rbutilqt/mspack/readhuff.h
new file mode 100644
index 0000000000..bb15c0a123
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/readhuff.h
@@ -0,0 +1,173 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_READHUFF_H
11#define MSPACK_READHUFF_H 1
12
13/* This implements a fast Huffman tree decoding system.
14 */
15
16#if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
17# error "readhuff.h is used in conjunction with readbits.h, include that first"
18#endif
19#if !(defined(TABLEBITS) && defined(MAXSYMBOLS))
20# error "define TABLEBITS(tbl) and MAXSYMBOLS(tbl) before using readhuff.h"
21#endif
22#if !(defined(HUFF_TABLE) && defined(HUFF_LEN))
23# error "define HUFF_TABLE(tbl) and HUFF_LEN(tbl) before using readhuff.h"
24#endif
25#ifndef HUFF_ERROR
26# error "define HUFF_ERROR before using readhuff.h"
27#endif
28#ifndef HUFF_MAXBITS
29# define HUFF_MAXBITS 16
30#endif
31
32/* Decodes the next huffman symbol from the input bitstream into var.
33 * Do not use this macro on a table unless build_decode_table() succeeded.
34 */
35#define READ_HUFFSYM(tbl, var) do { \
36 ENSURE_BITS(HUFF_MAXBITS); \
37 sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
38 if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
39 (var) = sym; \
40 i = HUFF_LEN(tbl, sym); \
41 REMOVE_BITS(i); \
42} while (0)
43
44#ifdef BITS_ORDER_LSB
45# define HUFF_TRAVERSE(tbl) do { \
46 i = TABLEBITS(tbl) - 1; \
47 do { \
48 if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
49 sym = HUFF_TABLE(tbl, \
50 (sym << 1) | ((bit_buffer >> i) & 1)); \
51 } while (sym >= MAXSYMBOLS(tbl)); \
52} while (0)
53#else
54#define HUFF_TRAVERSE(tbl) do { \
55 i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
56 do { \
57 if ((i >>= 1) == 0) HUFF_ERROR; \
58 sym = HUFF_TABLE(tbl, \
59 (sym << 1) | ((bit_buffer & i) ? 1 : 0)); \
60 } while (sym >= MAXSYMBOLS(tbl)); \
61} while (0)
62#endif
63
64/* make_decode_table(nsyms, nbits, length[], table[])
65 *
66 * This function was originally coded by David Tritscher.
67 * It builds a fast huffman decoding table from
68 * a canonical huffman code lengths table.
69 *
70 * nsyms = total number of symbols in this huffman tree.
71 * nbits = any symbols with a code length of nbits or less can be decoded
72 * in one lookup of the table.
73 * length = A table to get code lengths from [0 to nsyms-1]
74 * table = The table to fill up with decoded symbols and pointers.
75 * Should be ((1<<nbits) + (nsyms*2)) in length.
76 *
77 * Returns 0 for OK or 1 for error
78 */
79static int make_decode_table(unsigned int nsyms, unsigned int nbits,
80 unsigned char *length, unsigned short *table)
81{
82 register unsigned short sym, next_symbol;
83 register unsigned int leaf, fill;
84#ifdef BITS_ORDER_LSB
85 register unsigned int reverse;
86#endif
87 register unsigned char bit_num;
88 unsigned int pos = 0; /* the current position in the decode table */
89 unsigned int table_mask = 1 << nbits;
90 unsigned int bit_mask = table_mask >> 1; /* don't do 0 length codes */
91
92 /* fill entries for codes short enough for a direct mapping */
93 for (bit_num = 1; bit_num <= nbits; bit_num++) {
94 for (sym = 0; sym < nsyms; sym++) {
95 if (length[sym] != bit_num) continue;
96#ifdef BITS_ORDER_MSB
97 leaf = pos;
98#else
99 /* reverse the significant bits */
100 fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
101 do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
102#endif
103
104 if((pos += bit_mask) > table_mask) return 1; /* table overrun */
105
106 /* fill all possible lookups of this symbol with the symbol itself */
107#ifdef BITS_ORDER_MSB
108 for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
109#else
110 fill = bit_mask; next_symbol = 1 << bit_num;
111 do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
112#endif
113 }
114 bit_mask >>= 1;
115 }
116
117 /* exit with success if table is now complete */
118 if (pos == table_mask) return 0;
119
120 /* mark all remaining table entries as unused */
121 for (sym = pos; sym < table_mask; sym++) {
122#ifdef BITS_ORDER_MSB
123 table[sym] = 0xFFFF;
124#else
125 reverse = sym; leaf = 0; fill = nbits;
126 do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
127 table[leaf] = 0xFFFF;
128#endif
129 }
130
131 /* next_symbol = base of allocation for long codes */
132 next_symbol = ((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1);
133
134 /* give ourselves room for codes to grow by up to 16 more bits.
135 * codes now start at bit nbits+16 and end at (nbits+16-codelength) */
136 pos <<= 16;
137 table_mask <<= 16;
138 bit_mask = 1 << 15;
139
140 for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) {
141 for (sym = 0; sym < nsyms; sym++) {
142 if (length[sym] != bit_num) continue;
143
144#ifdef BITS_ORDER_MSB
145 leaf = pos >> 16;
146#else
147 /* leaf = the first nbits of the code, reversed */
148 reverse = pos >> 16; leaf = 0; fill = nbits;
149 do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
150#endif
151 for (fill = 0; fill < (bit_num - nbits); fill++) {
152 /* if this path hasn't been taken yet, 'allocate' two entries */
153 if (table[leaf] == 0xFFFF) {
154 table[(next_symbol << 1) ] = 0xFFFF;
155 table[(next_symbol << 1) + 1 ] = 0xFFFF;
156 table[leaf] = next_symbol++;
157 }
158
159 /* follow the path and select either left or right for next bit */
160 leaf = table[leaf] << 1;
161 if ((pos >> (15-fill)) & 1) leaf++;
162 }
163 table[leaf] = sym;
164
165 if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
166 }
167 bit_mask >>= 1;
168 }
169
170 /* full table? */
171 return (pos == table_mask) ? 0 : 1;
172}
173#endif
diff --git a/rbutil/rbutilqt/mspack/sha.h b/rbutil/rbutilqt/mspack/sha.h
new file mode 100644
index 0000000000..360521519b
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/sha.h
@@ -0,0 +1,15 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_LZSS_H
11#define MSPACK_LZSS_H 1
12
13/* SHA-1 message digest definitions */
14
15#endif
diff --git a/rbutil/rbutilqt/mspack/system.c b/rbutil/rbutilqt/mspack/system.c
new file mode 100644
index 0000000000..f3f0019f5e
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/system.c
@@ -0,0 +1,237 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifdef HAVE_CONFIG_H
11# include <config.h>
12#endif
13
14#include <system.h>
15
16#ifndef LARGEFILE_SUPPORT
17const char *largefile_msg = "library not compiled to support large files.";
18#endif
19
20
21int mspack_version(int entity) {
22 switch (entity) {
23 /* CHM decoder version 1 -> 2 changes:
24 * - added mschmd_sec_mscompressed::spaninfo
25 * - added mschmd_header::first_pmgl
26 * - added mschmd_header::last_pmgl
27 * - added mschmd_header::chunk_cache;
28 */
29 case MSPACK_VER_MSCHMD:
30 return 2;
31 case MSPACK_VER_LIBRARY:
32 case MSPACK_VER_SYSTEM:
33 case MSPACK_VER_MSCABD:
34 case MSPACK_VER_MSSZDDD:
35 case MSPACK_VER_MSKWAJD:
36 return 1;
37 case MSPACK_VER_MSCABC:
38 case MSPACK_VER_MSCHMC:
39 case MSPACK_VER_MSLITD:
40 case MSPACK_VER_MSLITC:
41 case MSPACK_VER_MSHLPD:
42 case MSPACK_VER_MSHLPC:
43 case MSPACK_VER_MSSZDDC:
44 case MSPACK_VER_MSKWAJC:
45 return 0;
46 }
47 return -1;
48}
49
50int mspack_sys_selftest_internal(int offt_size) {
51 return (sizeof(off_t) == offt_size) ? MSPACK_ERR_OK : MSPACK_ERR_SEEK;
52}
53
54/* validates a system structure */
55int mspack_valid_system(struct mspack_system *sys) {
56 return (sys != NULL) && (sys->open != NULL) && (sys->close != NULL) &&
57 (sys->read != NULL) && (sys->write != NULL) && (sys->seek != NULL) &&
58 (sys->tell != NULL) && (sys->message != NULL) && (sys->alloc != NULL) &&
59 (sys->free != NULL) && (sys->copy != NULL) && (sys->null_ptr == NULL);
60}
61
62/* returns the length of a file opened for reading */
63int mspack_sys_filelen(struct mspack_system *system,
64 struct mspack_file *file, off_t *length)
65{
66 off_t current;
67
68 if (!system || !file || !length) return MSPACK_ERR_OPEN;
69
70 /* get current offset */
71 current = system->tell(file);
72
73 /* seek to end of file */
74 if (system->seek(file, (off_t) 0, MSPACK_SYS_SEEK_END)) {
75 return MSPACK_ERR_SEEK;
76 }
77
78 /* get offset of end of file */
79 *length = system->tell(file);
80
81 /* seek back to original offset */
82 if (system->seek(file, current, MSPACK_SYS_SEEK_START)) {
83 return MSPACK_ERR_SEEK;
84 }
85
86 return MSPACK_ERR_OK;
87}
88
89
90
91/* definition of mspack_default_system -- if the library is compiled with
92 * MSPACK_NO_DEFAULT_SYSTEM, no default system will be provided. Otherwise,
93 * an appropriate default system (e.g. the standard C library, or some native
94 * API calls)
95 */
96
97#ifdef MSPACK_NO_DEFAULT_SYSTEM
98struct mspack_system *mspack_default_system = NULL;
99#else
100
101/* implementation of mspack_default_system for standard C library */
102
103#include <stdio.h>
104#include <stdlib.h>
105#include <string.h>
106#include <stdarg.h>
107
108struct mspack_file_p {
109 FILE *fh;
110 const char *name;
111};
112
113static struct mspack_file *msp_open(struct mspack_system *self,
114 const char *filename, int mode)
115{
116 struct mspack_file_p *fh;
117 const char *fmode;
118
119 switch (mode) {
120 case MSPACK_SYS_OPEN_READ: fmode = "rb"; break;
121 case MSPACK_SYS_OPEN_WRITE: fmode = "wb"; break;
122 case MSPACK_SYS_OPEN_UPDATE: fmode = "r+b"; break;
123 case MSPACK_SYS_OPEN_APPEND: fmode = "ab"; break;
124 default: return NULL;
125 }
126
127 if ((fh = (struct mspack_file_p *) malloc(sizeof(struct mspack_file_p)))) {
128 fh->name = filename;
129 if ((fh->fh = fopen(filename, fmode))) return (struct mspack_file *) fh;
130 free(fh);
131 }
132 return NULL;
133}
134
135static void msp_close(struct mspack_file *file) {
136 struct mspack_file_p *self = (struct mspack_file_p *) file;
137 if (self) {
138 fclose(self->fh);
139 free(self);
140 }
141}
142
143static int msp_read(struct mspack_file *file, void *buffer, int bytes) {
144 struct mspack_file_p *self = (struct mspack_file_p *) file;
145 if (self && buffer && bytes >= 0) {
146 size_t count = fread(buffer, 1, (size_t) bytes, self->fh);
147 if (!ferror(self->fh)) return (int) count;
148 }
149 return -1;
150}
151
152static int msp_write(struct mspack_file *file, void *buffer, int bytes) {
153 struct mspack_file_p *self = (struct mspack_file_p *) file;
154 if (self && buffer && bytes >= 0) {
155 size_t count = fwrite(buffer, 1, (size_t) bytes, self->fh);
156 if (!ferror(self->fh)) return (int) count;
157 }
158 return -1;
159}
160
161static int msp_seek(struct mspack_file *file, off_t offset, int mode) {
162 struct mspack_file_p *self = (struct mspack_file_p *) file;
163 if (self) {
164 switch (mode) {
165 case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
166 case MSPACK_SYS_SEEK_CUR: mode = SEEK_CUR; break;
167 case MSPACK_SYS_SEEK_END: mode = SEEK_END; break;
168 default: return -1;
169 }
170#ifdef HAVE_FSEEKO
171 return fseeko(self->fh, offset, mode);
172#else
173 return fseek(self->fh, offset, mode);
174#endif
175 }
176 return -1;
177}
178
179static off_t msp_tell(struct mspack_file *file) {
180 struct mspack_file_p *self = (struct mspack_file_p *) file;
181#ifdef HAVE_FSEEKO
182 return (self) ? (off_t) ftello(self->fh) : 0;
183#else
184 return (self) ? (off_t) ftell(self->fh) : 0;
185#endif
186}
187
188static void msp_msg(struct mspack_file *file, const char *format, ...) {
189 va_list ap;
190 if (file) fprintf(stderr, "%s: ", ((struct mspack_file_p *) file)->name);
191 va_start(ap, format);
192 vfprintf(stderr, format, ap);
193 va_end(ap);
194 fputc((int) '\n', stderr);
195 fflush(stderr);
196}
197
198static void *msp_alloc(struct mspack_system *self, size_t bytes) {
199#ifdef DEBUG
200 /* make uninitialised data obvious */
201 char *buf = malloc(bytes + 8);
202 if (buf) memset(buf, 0xDC, bytes);
203 *((size_t *)buf) = bytes;
204 return &buf[8];
205#else
206 return malloc(bytes);
207#endif
208}
209
210static void msp_free(void *buffer) {
211#ifdef DEBUG
212 char *buf = buffer;
213 size_t bytes;
214 if (buf) {
215 buf -= 8;
216 bytes = *((size_t *)buf);
217 /* make freed data obvious */
218 memset(buf, 0xED, bytes);
219 free(buf);
220 }
221#else
222 free(buffer);
223#endif
224}
225
226static void msp_copy(void *src, void *dest, size_t bytes) {
227 memcpy(dest, src, bytes);
228}
229
230static struct mspack_system msp_system = {
231 &msp_open, &msp_close, &msp_read, &msp_write, &msp_seek,
232 &msp_tell, &msp_msg, &msp_alloc, &msp_free, &msp_copy, NULL
233};
234
235struct mspack_system *mspack_default_system = &msp_system;
236
237#endif
diff --git a/rbutil/rbutilqt/mspack/system.h b/rbutil/rbutilqt/mspack/system.h
new file mode 100644
index 0000000000..4a400850aa
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/system.h
@@ -0,0 +1,124 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_SYSTEM_H
11#define MSPACK_SYSTEM_H 1
12
13#ifdef __cplusplus
14extern "C" {
15#endif
16
17/* ensure config.h is read before mspack.h */
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <mspack.h>
23
24/* fix for problem with GCC 4 and glibc (thanks to Ville Skytta)
25 * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=150429
26 */
27#ifdef read
28# undef read
29#endif
30
31#ifdef DEBUG
32# include <stdio.h>
33/* Old GCCs don't have __func__, but __FUNCTION__:
34 * http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
35 */
36# if __STDC_VERSION__ < 199901L
37# if __GNUC__ >= 2
38# define __func__ __FUNCTION__
39# else
40# define __func__ "<unknown>"
41# endif
42# endif
43# define D(x) do { printf("%s:%d (%s) ",__FILE__, __LINE__, __func__); \
44 printf x ; fputc('\n', stdout); fflush(stdout);} while (0);
45#else
46# define D(x)
47#endif
48
49/* CAB supports searching through files over 4GB in size, and the CHM file
50 * format actively uses 64-bit offsets. These can only be fully supported
51 * if the system the code runs on supports large files. If not, the library
52 * will work as normal using only 32-bit arithmetic, but if an offset
53 * greater than 2GB is detected, an error message indicating the library
54 * can't support the file should be printed.
55 */
56#ifdef HAVE_LIMITS_H
57# include <limits.h>
58#endif
59
60#if ((defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS >= 64) || \
61 (defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
62 (defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \
63 defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE))
64# define LARGEFILE_SUPPORT
65# define LD "lld"
66# define LU "llu"
67#else
68extern const char *largefile_msg;
69# define LD "ld"
70# define LU "lu"
71#endif
72
73/* endian-neutral reading of little-endian data */
74#define __egi32(a,n) ( ((((unsigned char *) a)[n+3]) << 24) | \
75 ((((unsigned char *) a)[n+2]) << 16) | \
76 ((((unsigned char *) a)[n+1]) << 8) | \
77 ((((unsigned char *) a)[n+0])))
78#define EndGetI64(a) ((((unsigned long long int) __egi32(a,4)) << 32) | \
79 ((unsigned int) __egi32(a,0)))
80#define EndGetI32(a) __egi32(a,0)
81#define EndGetI16(a) ((((a)[1])<<8)|((a)[0]))
82
83/* endian-neutral reading of big-endian data */
84#define EndGetM32(a) (((((unsigned char *) a)[0]) << 24) | \
85 ((((unsigned char *) a)[1]) << 16) | \
86 ((((unsigned char *) a)[2]) << 8) | \
87 ((((unsigned char *) a)[3])))
88#define EndGetM16(a) ((((a)[0])<<8)|((a)[1]))
89
90extern struct mspack_system *mspack_default_system;
91
92/* returns the length of a file opened for reading */
93extern int mspack_sys_filelen(struct mspack_system *system,
94 struct mspack_file *file, off_t *length);
95
96/* validates a system structure */
97extern int mspack_valid_system(struct mspack_system *sys);
98
99#if HAVE_STRINGS_H
100# include <strings.h>
101#endif
102
103#if HAVE_STRING_H
104# include <string.h>
105#endif
106
107#if HAVE_MEMCMP
108# define mspack_memcmp memcmp
109#else
110/* inline memcmp() */
111static inline int mspack_memcmp(const void *s1, const void *s2, size_t n) {
112 unsigned char *c1 = (unsigned char *) s1;
113 unsigned char *c2 = (unsigned char *) s2;
114 if (n == 0) return 0;
115 while (--n && (*c1 == *c2)) c1++, c2++;
116 return *c1 - *c2;
117}
118#endif
119
120#ifdef __cplusplus
121}
122#endif
123
124#endif
diff --git a/rbutil/rbutilqt/mspack/szdd.h b/rbutil/rbutilqt/mspack/szdd.h
new file mode 100644
index 0000000000..e07c6b7c8e
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/szdd.h
@@ -0,0 +1,39 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10#ifndef MSPACK_SZDD_H
11#define MSPACK_SZDD_H 1
12
13#include <lzss.h>
14
15/* input buffer size during decompression - not worth parameterising IMHO */
16#define SZDD_INPUT_SIZE (2048)
17
18/* SZDD compression definitions */
19
20struct msszdd_compressor_p {
21 struct msszdd_compressor base;
22 struct mspack_system *system;
23 int error;
24};
25
26/* SZDD decompression definitions */
27
28struct msszdd_decompressor_p {
29 struct msszdd_decompressor base;
30 struct mspack_system *system;
31 int error;
32};
33
34struct msszddd_header_p {
35 struct msszddd_header base;
36 struct mspack_file *fh;
37};
38
39#endif
diff --git a/rbutil/rbutilqt/mspack/szddc.c b/rbutil/rbutilqt/mspack/szddc.c
new file mode 100644
index 0000000000..cdd39a6305
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/szddc.c
@@ -0,0 +1,24 @@
1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie.
3 *
4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
6 *
7 * For further details, see the file COPYING.LIB distributed with libmspack
8 */
9
10/* SZDD compression implementation */
11
12#include <system.h>
13#include <szdd.h>
14
15struct msszdd_compressor *
16 mspack_create_szdd_compressor(struct mspack_system *sys)
17{
18 /* todo */
19 return NULL;
20}
21
22void mspack_destroy_szdd_compressor(struct msszdd_compressor *self) {
23 /* todo */
24}
diff --git a/rbutil/rbutilqt/mspack/szddd.c b/rbutil/rbutilqt/mspack/szddd.c
new file mode 100644
index 0000000000..99c5aa4658
--- /dev/null
+++ b/rbutil/rbutilqt/mspack/szddd.c
@@ -0,0 +1,247 @@
1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie.
3 *
4 * SZDD is a format used in the MS-DOS commands COMPRESS.EXE and
5 * EXPAND.EXE. The compression method is attributed to Steven Zeck,
6 * however it's pretty much identical to LZSS.
7 *
8 * libmspack is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
10 *
11 * For further details, see the file COPYING.LIB distributed with libmspack
12 */
13
14/* SZDD decompression implementation */
15
16#include <system.h>
17#include <szdd.h>
18
19/* prototypes */
20static struct msszddd_header *szddd_open(
21 struct msszdd_decompressor *base, const char *filename);
22static void szddd_close(
23 struct msszdd_decompressor *base, struct msszddd_header *hdr);
24static int szddd_read_headers(
25 struct mspack_system *sys, struct mspack_file *fh,
26 struct msszddd_header *hdr);
27static int szddd_extract(
28 struct msszdd_decompressor *base, struct msszddd_header *hdr,
29 const char *filename);
30static int szddd_decompress(
31 struct msszdd_decompressor *base, const char *input, const char *output);
32static int szddd_error(
33 struct msszdd_decompressor *base);
34
35/***************************************
36 * MSPACK_CREATE_SZDD_DECOMPRESSOR
37 ***************************************
38 * constructor
39 */
40struct msszdd_decompressor *
41 mspack_create_szdd_decompressor(struct mspack_system *sys)
42{
43 struct msszdd_decompressor_p *self = NULL;
44
45 if (!sys) sys = mspack_default_system;
46 if (!mspack_valid_system(sys)) return NULL;
47
48 if ((self = (struct msszdd_decompressor_p *) sys->alloc(sys, sizeof(struct msszdd_decompressor_p)))) {
49 self->base.open = &szddd_open;
50 self->base.close = &szddd_close;
51 self->base.extract = &szddd_extract;
52 self->base.decompress = &szddd_decompress;
53 self->base.last_error = &szddd_error;
54 self->system = sys;
55 self->error = MSPACK_ERR_OK;
56 }
57 return (struct msszdd_decompressor *) self;
58}
59
60/***************************************
61 * MSPACK_DESTROY_SZDD_DECOMPRESSOR
62 ***************************************
63 * destructor
64 */
65void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
66{
67 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
68 if (self) {
69 struct mspack_system *sys = self->system;
70 sys->free(self);
71 }
72}
73
74/***************************************
75 * SZDDD_OPEN
76 ***************************************
77 * opens an SZDD file without decompressing, reads header
78 */
79static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
80 const char *filename)
81{
82 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
83 struct msszddd_header *hdr;
84 struct mspack_system *sys;
85 struct mspack_file *fh;
86
87 if (!self) return NULL;
88 sys = self->system;
89
90 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
91 hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p));
92 if (fh && hdr) {
93 ((struct msszddd_header_p *) hdr)->fh = fh;
94 self->error = szddd_read_headers(sys, fh, hdr);
95 }
96 else {
97 if (!fh) self->error = MSPACK_ERR_OPEN;
98 if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
99 }
100
101 if (self->error) {
102 if (fh) sys->close(fh);
103 if (hdr) sys->free(hdr);
104 hdr = NULL;
105 }
106
107 return hdr;
108}
109
110/***************************************
111 * SZDDD_CLOSE
112 ***************************************
113 * closes an SZDD file
114 */
115static void szddd_close(struct msszdd_decompressor *base,
116 struct msszddd_header *hdr)
117{
118 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
119 struct msszddd_header_p *hdr_p = (struct msszddd_header_p *) hdr;
120
121 if (!self || !self->system) return;
122
123 /* close the file handle associated */
124 self->system->close(hdr_p->fh);
125
126 /* free the memory associated */
127 self->system->free(hdr);
128
129 self->error = MSPACK_ERR_OK;
130}
131
132/***************************************
133 * SZDDD_READ_HEADERS
134 ***************************************
135 * reads the headers of an SZDD format file
136 */
137static unsigned char szdd_signature_expand[8] = {
138 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33
139};
140static unsigned char szdd_signature_qbasic[8] = {
141 0x53, 0x5A, 0x20, 0x88, 0xF0, 0x27, 0x33, 0xD1
142};
143
144static int szddd_read_headers(struct mspack_system *sys,
145 struct mspack_file *fh,
146 struct msszddd_header *hdr)
147{
148 unsigned char buf[8];
149
150 /* read and check signature */
151 if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ;
152
153 if ((mspack_memcmp(buf, szdd_signature_expand, 8) == 0)) {
154 /* common SZDD */
155 hdr->format = MSSZDD_FMT_NORMAL;
156
157 /* read the rest of the header */
158 if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
159 if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
160 hdr->missing_char = buf[1];
161 hdr->length = EndGetI32(&buf[2]);
162 }
163 else if ((mspack_memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
164 /* special QBasic SZDD */
165 hdr->format = MSSZDD_FMT_QBASIC;
166 if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
167 hdr->missing_char = '\0';
168 hdr->length = EndGetI32(buf);
169 }
170 else {
171 return MSPACK_ERR_SIGNATURE;
172 }
173 return MSPACK_ERR_OK;
174}
175
176/***************************************
177 * SZDDD_EXTRACT
178 ***************************************
179 * decompresses an SZDD file
180 */
181static int szddd_extract(struct msszdd_decompressor *base,
182 struct msszddd_header *hdr, const char *filename)
183{
184 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
185 struct mspack_file *fh, *outfh;
186 struct mspack_system *sys;
187 off_t data_offset;
188
189 if (!self) return MSPACK_ERR_ARGS;
190 if (!hdr) return self->error = MSPACK_ERR_ARGS;
191 sys = self->system;
192
193 fh = ((struct msszddd_header_p *) hdr)->fh;
194
195 /* seek to the compressed data */
196 data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12;
197 if (sys->seek(fh, data_offset, MSPACK_SYS_SEEK_START)) {
198 return self->error = MSPACK_ERR_SEEK;
199 }
200
201 /* open file for output */
202 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
203 return self->error = MSPACK_ERR_OPEN;
204 }
205
206 /* decompress the data */
207 self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
208 hdr->format == MSSZDD_FMT_NORMAL
209 ? LZSS_MODE_EXPAND
210 : LZSS_MODE_QBASIC);
211
212 /* close output file */
213 sys->close(outfh);
214
215 return self->error;
216}
217
218/***************************************
219 * SZDDD_DECOMPRESS
220 ***************************************
221 * unpacks directly from input to output
222 */
223static int szddd_decompress(struct msszdd_decompressor *base,
224 const char *input, const char *output)
225{
226 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
227 struct msszddd_header *hdr;
228 int error;
229
230 if (!self) return MSPACK_ERR_ARGS;
231
232 if (!(hdr = szddd_open(base, input))) return self->error;
233 error = szddd_extract(base, hdr, output);
234 szddd_close(base, hdr);
235 return self->error = error;
236}
237
238/***************************************
239 * SZDDD_ERROR
240 ***************************************
241 * returns the last error that occurred
242 */
243static int szddd_error(struct msszdd_decompressor *base)
244{
245 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
246 return (self) ? self->error : MSPACK_ERR_ARGS;
247}