├── .gitignore
├── .travis.yml
├── COPYING
├── Makefile
├── README.md
├── default.nix
├── sfArkLib.h
├── sfklCoding.cpp
├── sfklCrunch.cpp
├── sfklDiff.cpp
├── sfklFile.cpp
├── sfklLPC.cpp
├── sfklString.cpp
├── sfklZip.cpp
└── wcc.h
/.gitignore:
--------------------------------------------------------------------------------
1 | *.so
2 | *.o
3 | /result
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 | arch:
3 | - amd64
4 | - ppc64le
5 |
6 | script: make && make test
7 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | INSTALL?=install
2 | USE_SOLINK:=
3 |
4 | OBJECTS=sfklCoding.o sfklDiff.o sfklLPC.o sfklZip.o sfklCrunch.o sfklFile.o sfklString.o
5 |
6 | CXXFLAGS+=-fPIC -Wall -Wextra -ffloat-store
7 |
8 | OS := $(shell uname)
9 |
10 | ifneq (,$(filter Linux GNU/kFreeBSD GNU,${OS}))
11 | CPPFLAGS+=-DUSE_ENDIAN_H
12 | else ifneq (,$(findstring BSD,${OS}))
13 | CPPFLAGS+=-DUSE_SYS_ENDIAN_H
14 | else
15 | ENDIANNESS=LITTLE_ENDIAN
16 | CPPFLAGS+=-DUSE_MANUAL_ENDIANNESS -DMANUAL_${ENDIANNESS}
17 | endif
18 |
19 | ifeq ($(OS),Darwin)
20 | LDFLAGS += -flat_namespace -undefined suppress -dynamiclib
21 | SO = dylib
22 | else
23 | LDFLAGS += -shared
24 | SHLIB_MAJOR:=1
25 | SHLIB_MINOR:=0
26 | SHLIB_PATCHLEVEL:=0
27 | ifneq (,$(filter Linux GNU/kFreeBSD GNU,${OS}))
28 | INSTALL += -D
29 | USE_SOLINK:=so.${SHLIB_MAJOR} so
30 | SO = so.${SHLIB_MAJOR}.${SHLIB_MINOR}.${SHLIB_PATCHLEVEL}
31 | LDFLAGS += -Wl,-soname,libsfark.so.${SHLIB_MAJOR}
32 | else ifneq (,$(findstring BSD,${OS}))
33 | # OpenBSD/MirBSD, might apply to NetBSD, FreeBSD/MidnightBSD might differ
34 | SO = so.${SHLIB_MAJOR}.${SHLIB_MINOR}
35 | else
36 | SO = so
37 | endif
38 | endif
39 |
40 | PREFIX ?= /usr/local
41 | ifdef DEB_HOST_MULTIARCH
42 | LIBDIR = ${PREFIX}/lib/${DEB_HOST_MULTIARCH}
43 | else
44 | LIBDIR = ${PREFIX}/lib
45 | endif
46 | INCDIR = ${PREFIX}/include
47 |
48 | all: libsfark.$(SO)
49 | ifneq (,$(strip ${USE_SOLINK}))
50 | set -ex; for solink in ${USE_SOLINK}; do \
51 | rm -f libsfark.$$solink; \
52 | ln -s libsfark.$(SO) libsfark.$$solink; \
53 | done
54 | endif
55 |
56 | .PHONY: clean
57 |
58 | clean:
59 | -rm *.o libsfark.$(SO)
60 | ifneq (,$(strip ${USE_SOLINK}))
61 | set -ex; for solink in ${USE_SOLINK}; do \
62 | rm -f libsfark.$$solink; \
63 | done
64 | endif
65 |
66 | test: libsfark.$(SO)
67 | -rm -rf sfarkxtc
68 | git clone https://github.com/raboof/sfarkxtc
69 | CXXFLAGS="-I.. -L.." make -C sfarkxtc
70 | rm -rf sfarkxtc
71 |
72 | libsfark.$(SO): $(OBJECTS)
73 | $(CXX) -shared $(LDFLAGS) $(OBJECTS) -o libsfark.$(SO) -lz
74 |
75 | # It is unclear to me whether /usr/local/* is the proper location on
76 | # OSX, as reportedly it's not on the clang path by default there. Let
77 | # me know if you know how this should be done there :).
78 | install: libsfark.$(SO) sfArkLib.h
79 | $(INSTALL) libsfark.$(SO) ${DESTDIR}${LIBDIR}/libsfark.$(SO)
80 | $(INSTALL) sfArkLib.h ${DESTDIR}${INCDIR}/sfArkLib.h
81 | ifneq (,$(strip ${USE_SOLINK}))
82 | set -ex; for solink in ${USE_SOLINK}; do \
83 | rm -f ${DESTDIR}${LIBDIR}/libsfark.$$solink; \
84 | ln -s libsfark.$(SO) ${DESTDIR}${LIBDIR}/libsfark.$$solink; \
85 | done
86 | endif
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | sfArkLib
2 | ========
3 |
4 | Library for decompressing sfArk soundfonts.
5 |
6 | A simple command-line tool to convert sfArk files to sf2
7 | based on this library can be found at https://github.com/raboof/sfArkXTm
8 |
9 | Prerequisites
10 | =============
11 |
12 | * Install zlib, e.g. from the zlib1g-dev package
13 |
14 | Building
15 | ========
16 |
17 | $ make
18 | $ sudo make install
19 | $ sudo ldconfig
20 |
21 | Building with nix (no other prerequisites)
22 | ========
23 |
24 | $ nix-build
25 |
26 | Development shell:
27 |
28 | $ nix-shell
29 |
--------------------------------------------------------------------------------
/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs ? import (
2 | builtins.fetchTarball {
3 | # nixpkgs pin @ NixOS 21.05
4 | url = "https://github.com/NixOS/nixpkgs/archive/d4590d21006387dcb190c516724cb1e41c0f8fdf.tar.gz";
5 | sha256 = "17q39hlx1x87xf2rdygyimj8whdbx33nzszf4rxkc6b85wz0l38n";
6 | }
7 | ) {}
8 | }:
9 |
10 | pkgs.stdenv.mkDerivation {
11 | name = "sfArkLib";
12 | src = builtins.filterSource (
13 | path: type: baseNameOf path != ".git" && type != "symlink"
14 | ) ./.;
15 |
16 | buildInputs = [ pkgs.zlib ];
17 |
18 | installFlags = [ "PREFIX=$(out)" ];
19 |
20 | meta = {
21 | description = "Library for decompressing sfArk soundfonts";
22 | platforms = pkgs.lib.platforms.linux;
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/sfArkLib.h:
--------------------------------------------------------------------------------
1 | // Header for sfArkLib
2 |
3 | // copyright 1998-2000 Andy Inman
4 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
5 |
6 | // This file is part of sfArkLib.
7 | //
8 | // sfArkLib is free software: you can redistribute it and/or modify
9 | // it under the terms of the GNU General Public License as published by
10 | // the Free Software Foundation, either version 3 of the License, or
11 | // (at your option) any later version.
12 | //
13 | // sfArkLib is distributed in the hope that it will be useful,
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | // GNU General Public License for more details.
17 | //
18 | // You should have received a copy of the GNU General Public License
19 | // along with sfArkLib. If not, see .
20 |
21 | /*
22 | Changes since V1.15
23 | ===================
24 | All constants now prefixed with SFARKLIB_, and function names prefxied with sfkl_
25 |
26 | sfkl_GetLicenseAgreement and sfkl_DisplayNotes functions now both take 2 parameters: the text of the text file
27 | and the name of the text file. This makes it easier for the application to either display the text itself or pass
28 | the filename onto some other program. Mac/Linux users note: the text is probably in Windows format!
29 | Future sfArk versions will allow Notes and License files to be of other types than plain text (e.g. HTML, RTF) so
30 | look at the file extenson in order to decide how to handle it.
31 | */
32 |
33 | // Some max sizes...
34 | #define SFARKLIB_MAX_FILENAME 256 // Longest filename handled (or directory name)
35 | #define SFARKLIB_MAX_FILEPATH 1024 // Longest full path handled
36 | #define SFARKLIB_MAX_MSGTEXT (SFARKLIB_MAX_FILEPATH + 1024) // Longest message we might produce with sfkl_msg()
37 |
38 | // Flags used with msg() function...
39 | #define SFARKLIB_MSG_SameLine (1 << 0) // Overwrite previous message
40 | #define SFARKLIB_MSG_AppendLine (1 << 1) // Append to previous message
41 | #define SFARKLIB_MSG_PopUp (1 << 2) // Should "pop up" a dialogue (usually an error message)
42 |
43 | // Error codes...
44 | #define SFARKLIB_SUCCESS 0 // No error
45 | #define SFARKLIB_ERR_INIT -1 // Failed to initialise
46 | #define SFARKLIB_ERR_MALLOC -2 // Failed to allocate memory
47 | #define SFARKLIB_ERR_SIGNATURE -3 // header does not contain "sfArk" signature
48 | #define SFARKLIB_ERR_HEADERCHECK -4 // sfArk file has a corrupt header
49 | #define SFARKLIB_ERR_INCOMPATIBLE -5 // sfArk file is incompatible (i.e. not sfArk V2.x)
50 | #define SFARKLIB_ERR_UNSUPPORTED -6 // sfArk file uses unsupported feature
51 | #define SFARKLIB_ERR_CORRUPT -7 // got invalid compressed data (file is corrupted)
52 | #define SFARKLIB_ERR_FILECHECK -8 // file checksum failed (file is corrupted)
53 | #define SFARKLIB_ERR_FILEIO -9 // File i/o error
54 | #define SFARKLIB_ERR_LICENSE -10 // License included not agreed by user
55 | #define SFARKLIB_ERR_OTHER -11 // Other error (currently unused)
56 |
57 | // Future SfArkLib versions may include additional further error codes,
58 | // so, any other negative value is "unknown error"
59 |
60 | // Callback functions needed by sfArkLib (must be supplied by Application) ...
61 | extern void sfkl_msg(const char *MessageText, int Flags); // Message display function
62 | extern void sfkl_UpdateProgress(int ProgressPercent); // Progress indication
63 | extern bool sfkl_GetLicenseAgreement(const char *LicenseText, const char *LicenseFileName); // Display/confirm license
64 | extern void sfkl_DisplayNotes(const char *NotesText, const char *NotesFileName); // Display notes text file
65 |
66 | // Functions in sfArkLib for use by Application...
67 | extern unsigned short sfkl_GetVersion(void);
68 | extern int sfkl_Decode(const char *InFileName, const char *ReqOutFileName);
69 |
--------------------------------------------------------------------------------
/sfklCoding.cpp:
--------------------------------------------------------------------------------
1 | //sfArkLib Coding
2 | //Copyright 1998-2000 Andy Inman
3 | //Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 |
21 | // V2.11 Initial release (with SDL 0.07)
22 | // V2.12 Bug fix in UnMemcomp (OutBytes was uninitialised causing crash for some files)
23 | // Used for SDL 0.08.
24 | // V2.13 Bug fix, previously file written was corrupt due to wrong buffer pointers
25 | // V2.14 Now using UpdateProgress function (supplied by application)
26 | // V2.15 Now using GetLicenseAgreement & DisplayNotes functions (app-supplied)
27 |
28 | // 2.20 Version bumped to 2.20 - First version for MacOS support
29 | // Major re-write to ReadHeader function, supports any size of self-extraction code in sfArk.exe files.
30 | // 2.21 25-09-02 Fixed byte order on output samples (for MacOS).
31 |
32 | // 2.22 27-09-03 Fixed bug in call to UpdateProgress which reset to zero with large files when bytes
33 | // written greater than (1<<31)/100 (approx 20MB) -- was due to 32-bit integer overflow
34 | // Added more floating-point precision conversions in LPC to tighten-up on Mac compatibility issues
35 | // Avoid potential bug in WriteOutputFile, now test BytesWritten != BytesToWrite instead of <= 0
36 | // Fixed rare bug when POST_AUDIO is more than ZBUF_SIZE (256kb) uncompressed (affected RealFont_2_1.sfArk)
37 |
38 | // 2.23 02-10-03 LPC Speeded up, now double the speed of earlier versions (on Intel at least)
39 |
40 | // CLIB headers...
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | // sfArk specific headers...
47 | #define SFARKLIB_GLOBAL
48 | #include "wcc.h"
49 | #include "zlib.h"
50 |
51 | // Set to 1 for special debug mode (needs enabled version of compressor)
52 | #define DB_BLOCKCHECK 0
53 |
54 | // FileSection equates...
55 | #define RIFF_HEADER 0
56 | #define RIFF_INFO 1
57 | #define INFO_LIST 2
58 | #define SDTA_LIST 3
59 | #define AUDIO_START 4
60 | #define AUDIO 5
61 | #define PRE_AUDIO 6
62 | #define POST_AUDIO 7
63 | #define NON_AUDIO 8
64 | #define FINISHED 9
65 |
66 | // Misc equates...
67 | #define OPTWINSIZE 32 // Default window size used by CrunchWin()
68 | #define ZBUF_SIZE (256 * 1024) // Size of buffer used for MemComp (do not change!)
69 | #define NSHIFTS (MAX_BUFSIZE / SHIFTWIN) // Max number of shift values per block (MaxBuf/SHIFTWIN = 4096/64)
70 | #define MAX_DIFF_LOOPS 20 // Max number of BufDif loops
71 |
72 | // --- Version 2 File Header Structure ---
73 |
74 | #define HDR_NAME_LEN 5
75 | #define HDR_VERS_LEN 5
76 |
77 | typedef struct
78 | /*
79 | NB: For compatibilty with sfArk V1, we must store "sfArk" at offset 27 (base 1) in
80 | 5 characters and the compression method as one byte immediately afterwards at offset 32.
81 | This will allow sfArk V1 to recoginse this as a .sfArk file (though not decompress it!)
82 | */
83 | {
84 | uint32_t Flags; // 0-3 Bits 0 & 1 used to indicate presence of Notes and License files
85 | uint32_t OriginalSize; // 4-7 Uncompressed file size
86 | uint32_t CompressedSize; // 8-11 Compressed file size (including header)
87 | uint32_t FileCheck; // 12-15 File Checksum
88 | uint32_t HdrCheck; // 16-19 Header Checksum
89 | uint8_t ProgVersionNeeded; // 20 SfArk version needed to unpack this file (20 = Version 2.0x, etc.)
90 | char ProgVersion[HDR_NAME_LEN]; // 21-25 Version string (nn.nn) that created this file (NOT terminated)
91 | char ProgName[HDR_VERS_LEN]; // 26-30 Signature "sfArk" (not terminated)
92 | uint8_t CompMethod; // 31 Compression Method
93 | uint16_t FileType; // 32-33 Currently always 0 (for SF2)
94 | uint32_t AudioStart; // 34-37 Position in original file of start of audio data
95 | uint32_t PostAudioStart; // 38-41 Position in original file of start any data after audio data (e.g. SF2 parameters)
96 | char FileName[MAX_FILENAME]; // 42-297 Original filename, no path (stored variable length, null terminated)
97 | } V2_FILEHEADER;
98 |
99 | // Some extras re. Header structure...
100 | #define V2_FILEHEADER_SIZE 298 // *Actual* size of header data, may be less than sizeof(V2_FILEHEADER)
101 | #define HEADER_HDRCHECK_POS 16 // Byte position of HeaderCheck field in header
102 | #define HEADER_SIG_POS 26 // Byte position of "sfArk" signautre in header
103 | #define HEADER_MAX_OFFSET (128*1024) // Maximum search extent: maximum expected size of "self-extractor" code.
104 |
105 | // FileHeader Flags...
106 | #define FLAGS_Notes (1 << 0) // Notes file included
107 | #define FLAGS_License (1 << 1) // License file included
108 |
109 | const char LicenseExt[] = ".license.txt"; // File extension for license file
110 | const char NotesExt[] = ".txt"; // File extension for notes file
111 | const char SfExt[] = ".sf2"; // File extension for output file
112 |
113 | static BYTE *Zbuf1 = NULL, *Zbuf2 = NULL;
114 |
115 | // Data per block, passed to ProcessNextBlock()
116 | typedef struct
117 | {
118 | V2_FILEHEADER FileHeader; // FileHeader structre
119 | int FileSection; // Track current "file section"
120 |
121 | int ReadSize; // Number of words to read per block
122 | int MaxLoops; // Max loops for reduction with BufDiff2/3
123 | int MaxBD4Loops; // Max loops for reduction with BufDiff4
124 | int nc; // Number of LPC parameters
125 | int WinSize; // Window size for CrunchWin
126 |
127 | AWORD *SrcBuf; // Address of source buffer
128 | AWORD *DstBuf; // Address of destination buffer
129 |
130 | ULONG TotBytesWritten; // Total bytes written in file
131 | ULONG FileCheck; // File checksum (accumulated)
132 | AWORD PrevIn[MAX_DIFF_LOOPS]; // Previous values (per loop)
133 |
134 | USHORT PrevEncodeCount; // Previous number of loops used
135 | USHORT BD4PrevEncodeCount; // Previous number of loops used for BD4
136 | short PrevShift; // Previous Shift value
137 | short PrevUsedShift; // Previously used (non zero) Shift value
138 | } BLOCK_DATA;
139 |
140 | // Messages...
141 | const char CorruptedMsg[] = "- This file appears to be corrupted.";
142 | const char UpgradeMsg[] = "Please see Help/About for information on how to obtain an update.";
143 | char OutFileNameMain[SFARKLIB_MAX_FILEPATH] = "";
144 | char OutFileNameNotes[SFARKLIB_MAX_FILEPATH] = "";
145 | char OutFileNameLicense[SFARKLIB_MAX_FILEPATH] = "";
146 |
147 | // ==============================================================
148 | USHORT GetsfArkLibVersion(void)
149 | {
150 | return (ProgVersionMaj * 10) + ProgVersionMin/10;
151 | }
152 |
153 | // ==============================================================
154 |
155 | // Read the File Header....
156 | int ReadHeader(V2_FILEHEADER *FileHeader, BYTE *fbuf, int bufsize)
157 | {
158 | int HeaderLen = 0, HdrOffset;
159 | char CreatedByProg[HDR_NAME_LEN +1], CreatedByVersion[HDR_VERS_LEN +1];
160 | ULONG CalcHdrCheck = 0;
161 | BYTE *HdrBuf, *bpFileHeader = (BYTE *) FileHeader;
162 |
163 | // Find and process the Header: This could be a plain sfArk file, a self-extracting file or some other (invalid) file.
164 | // Also, it could be a sfArk V1 file, which we can't decompress, but should at least recognise.
165 | // We locate the header by looking for the string "sfArk" within the first HEADER_MAX_OFFSET bytes of the file
166 | // but because self-extractor code is likely to contain that string, we look for its final occurence
167 | // by searching backwards.
168 | // To speed things up, we first check at offset 0 (the case for a standard sfArk file)
169 | // If we think we've found a (V2) header, we veryify it using the Header checksum. If the checksum fails,
170 | // chances are it was a corrupt file, but could conceivably be a non-sfArk file. either way we report it as corrupt.
171 |
172 | int fbufsize = HEADER_MAX_OFFSET + V2_FILEHEADER_SIZE; // Amount data to read
173 | if (fbufsize > bufsize) fbufsize = bufsize; // Buffer too small (should never happen)
174 |
175 | SetInputFilePosition(0); // set to logical start (maybe a predefined offset)
176 | RETURN_ON_ERROR();
177 | ReadInputFile(fbuf, fbufsize); // Read a chunk of data from the start of the file
178 | RETURN_ON_ERROR();
179 |
180 | bool SigFound = false, SeemsV1 = false, HdrCheckDone = false; // Some flags to remember what we're doing
181 |
182 | for(int TryOffset = 0; TryOffset < HEADER_MAX_OFFSET; TryOffset++)
183 | {
184 | HdrOffset = (TryOffset == 0)? 0 : HEADER_MAX_OFFSET - TryOffset; // Check offset = 0 first, then backwards from end
185 |
186 | BYTE *sigpos = fbuf + HdrOffset + HEADER_SIG_POS;
187 | if (*sigpos != 's' || memcmp(sigpos, "sfArk", 5) != 0) continue;
188 |
189 | SigFound = true; // Set a flag to remember that we at least got this far
190 | HdrBuf = fbuf + HdrOffset;
191 |
192 | if (V2_FILEHEADER_SIZE != sizeof(V2_FILEHEADER)) // Compare structure size to real size
193 | {
194 | // The compiler has messed with structure (alignment), so copy the data to the structure byte by byte...
195 | BYTE *bptr = HdrBuf; // Point to start
196 | // Copy all fields...
197 | #define CPF(f) memcpy(&(FileHeader->f), bptr, sizeof(FileHeader->f)); bptr += sizeof(FileHeader->f)
198 | CPF(Flags); CPF(OriginalSize); CPF(CompressedSize); CPF(FileCheck); CPF(HdrCheck);
199 | CPF(ProgVersionNeeded); CPF(ProgVersion); CPF(ProgName); CPF(CompMethod);
200 | CPF(FileType); CPF(AudioStart); CPF(PostAudioStart); CPF(FileName);
201 | #undef CPF
202 | if (bptr != HdrBuf+V2_FILEHEADER_SIZE) return (GlobalErrorFlag = SFARKLIB_ERR_OTHER); // Sanity check
203 | }
204 | else
205 | memcpy(bpFileHeader, HdrBuf, V2_FILEHEADER_SIZE); // Copy entire data block to structure
206 |
207 | if (FileHeader->CompMethod < COMPRESSION_v2) // Looks like a sfArk V1 file?
208 | {
209 | SeemsV1 = true; // set a flag
210 | continue; // and keep searching
211 | }
212 |
213 | // Header->FileName is a null-terminated string, we need it's length to calculate actual length of header data...
214 | FileHeader->FileName[sizeof(FileHeader->FileName) -1] = '\0'; // Ensure strlen finds a terminator (string may be junk)
215 | HeaderLen = V2_FILEHEADER_SIZE - sizeof(FileHeader->FileName) + strlen(FileHeader->FileName) + 1;
216 |
217 | // If we get this far, there's a good chance we've got the header...
218 | #if BYTE_ORDER == BIG_ENDIAN
219 | // FixEndians of all multi-byte integers (currently only relevent to Mac)
220 | #define FIXENDIAN(field) FixEndian(&(FileHeader->field), sizeof(FileHeader->field))
221 | FIXENDIAN(Flags); FIXENDIAN(OriginalSize); FIXENDIAN(CompressedSize);
222 | FIXENDIAN(FileCheck); FIXENDIAN(HdrCheck); FIXENDIAN(FileType);
223 | FIXENDIAN(AudioStart); FIXENDIAN(PostAudioStart);
224 | #undef FIXENDIAN
225 | #endif
226 |
227 | // Ok now, we know the HeaderLength and have the FileHeader structure properly populated...
228 | #if 0
229 | // debug, display header...
230 | printf("Flags %lx OrignalSize %ld CompressedSize %ld\n", FileHeader->Flags, FileHeader->OriginalSize, FileHeader->CompressedSize);
231 | printf("FileCheck %lx HdrCheck %lx ProgVersionNeeded %d\n", FileHeader->FileCheck, FileHeader->HdrCheck, FileHeader->ProgVersionNeeded);
232 | printf("AudioStart %ld PostAudioStart %ld Orginal filename %s\n", FileHeader->AudioStart, FileHeader->PostAudioStart, FileHeader->FileName);
233 | #endif
234 | *(uint32_t *)(HdrBuf+HEADER_HDRCHECK_POS) = 0; // Zero-out the HeaderChecksum position in the buffer
235 | CalcHdrCheck = adler32(0, HdrBuf, HeaderLen); // and recalculate the header checksum
236 | HdrCheckDone = true;
237 | if (CalcHdrCheck == FileHeader->HdrCheck) break; // Check passed: Yes, we've found the header!
238 | }
239 |
240 | // When we get here, see what happened:
241 | if (SigFound && HdrCheckDone && CalcHdrCheck == FileHeader->HdrCheck) // Everything Ok! File is V2 and valid
242 | ; // Fall through to below (everything else is an error)
243 | else if (SeemsV1) // Seems to be a sfArkV1 file
244 | {
245 | sprintf(MsgTxt, "This file was created with sfArk V1, and this program only handles sfArk V2+ files. Unfortunately sfArk V1 uses a proprietary compression algorithm for the non-audio metadata, so we cannot really support that. You might try running the Windows sfArk program from http://melodymachine.com/sfark.htm under Wine.");
246 | msg(MsgTxt, MSG_PopUp);
247 | return (GlobalErrorFlag = SFARKLIB_ERR_INCOMPATIBLE);
248 | }
249 | else if (SigFound) // Apparently a corrupt sfArk file (well, it had "sfArk" in it!)
250 | {
251 | sprintf(MsgTxt, "File Header fails checksum!%s", CorruptedMsg);
252 | msg(MsgTxt, MSG_PopUp);
253 | return (GlobalErrorFlag = SFARKLIB_ERR_HEADERCHECK);
254 | }
255 | else // Either very corrupted, or not a sfArk file
256 | {
257 | sprintf(MsgTxt, "This does not appear to be a sfArk file!");
258 | msg(MsgTxt, MSG_PopUp);
259 | return (GlobalErrorFlag = SFARKLIB_ERR_SIGNATURE);
260 | }
261 |
262 | // Get CreatedBy program name and version number (need null-terminated strings)...
263 | strncpy(CreatedByProg, FileHeader->ProgName, HDR_NAME_LEN); // Copy program name
264 | CreatedByProg[HDR_NAME_LEN] = 0; // Terminate string
265 | strncpy(CreatedByVersion, FileHeader->ProgVersion, HDR_VERS_LEN); // Copy version string
266 | CreatedByVersion[HDR_VERS_LEN] = 0; // Terminate string
267 |
268 | // Check for compatible version...
269 | if (FileHeader->ProgVersionNeeded > ProgVersionMaj)
270 | {
271 | sprintf(MsgTxt, "You need %s version %2.1f (or higher) to decompress this file (your version is %s) %s",
272 | ProgName, (float)FileHeader->ProgVersionNeeded/10, ProgVersion, UpgradeMsg);
273 | msg(MsgTxt, MSG_PopUp);
274 | return (GlobalErrorFlag = SFARKLIB_ERR_INCOMPATIBLE);
275 | }
276 |
277 | // Warn if file was created by a newer version than this version...
278 | float fProgVersion = (float) atof(ProgVersion);
279 | float fCreatedByVersion = (float) atof(CreatedByVersion);
280 | if (fCreatedByVersion > fProgVersion)
281 | {
282 | sprintf(MsgTxt, "This file was created with %s %s. Your version of %s (%s) can uncompress this file, "
283 | "but you might like to obtain the latest version. %s",
284 | CreatedByProg, CreatedByVersion, ProgName, ProgVersion, UpgradeMsg);
285 | msg(MsgTxt, MSG_PopUp);
286 | }
287 |
288 | SetInputFilePosition(HdrOffset + HeaderLen); // re-wind file to start of post-header data
289 | RETURN_ON_ERROR();
290 | return SFARKLIB_SUCCESS;
291 | }
292 |
293 | // =================================================================================
294 | void InitFilenames(const char *OrigFileName, const char *InFileName, const char *ReqOutFileName)
295 | {
296 | if (ReqOutFileName)
297 | {
298 | ChangeFileExt(ReqOutFileName, SfExt, OutFileNameMain, sizeof(OutFileNameMain));
299 | ChangeFileExt(ReqOutFileName, NotesExt, OutFileNameNotes, sizeof(OutFileNameNotes));
300 | ChangeFileExt(ReqOutFileName, LicenseExt, OutFileNameLicense, sizeof(OutFileNameLicense));
301 | }
302 | else
303 | {
304 | if (strchr(OrigFileName, '/') || strchr(OrigFileName, '\\'))
305 | {
306 | msg("Please run Decode again and provide an output filename. We cannot use the original filename because"
307 | " it contains a disallowed character.", MSG_PopUp);
308 | }
309 | else
310 | {
311 | ChangeFileExt(OrigFileName, SfExt, OutFileNameMain, sizeof(OutFileNameMain));
312 | ChangeFileExt(OrigFileName, NotesExt, OutFileNameNotes, sizeof(OutFileNameNotes));
313 | ChangeFileExt(OrigFileName, LicenseExt, OutFileNameLicense, sizeof(OutFileNameLicense));
314 | }
315 | }
316 |
317 | if (!OutFileNameMain[0] || !OutFileNameNotes[0] || !OutFileNameLicense[0])
318 | {
319 | msg("Could not get output path (path too long?)", MSG_PopUp);
320 | GlobalErrorFlag = SFARKLIB_ERR_FILEIO;
321 | }
322 | }
323 |
324 | // ==============================================================
325 | bool InvalidEncodeCount(int EncodeCount, int MaxLoops)
326 | {
327 | if (EncodeCount < 0 || EncodeCount > MaxLoops) // EncodeCount out of range?
328 | {
329 | sprintf(MsgTxt, "ERROR - Invalid EncodeCount (apparently %d) %s", EncodeCount, CorruptedMsg);
330 | msg(MsgTxt, MSG_PopUp);
331 | return true;
332 | }
333 | else
334 | return false;
335 | }
336 |
337 | // ==============================================================
338 | int DecompressTurbo(BLOCK_DATA *Blk, USHORT NumWords)
339 | {
340 | int EncodeCount = InputDiff(Blk->PrevEncodeCount);
341 | if (InvalidEncodeCount(EncodeCount, Blk->MaxLoops)) return (GlobalErrorFlag = SFARKLIB_ERR_CORRUPT);
342 | Blk->PrevEncodeCount = EncodeCount;
343 |
344 | int UnCrunchResult = UnCrunchWin(Blk->SrcBuf, NumWords, 8*OPTWINSIZE);
345 | if (UnCrunchResult < 0)
346 | {
347 | sprintf(MsgTxt, "ERROR - UnCrunchWin returned: %d %s", UnCrunchResult, CorruptedMsg);
348 | msg(MsgTxt, MSG_PopUp);
349 | return (GlobalErrorFlag = SFARKLIB_ERR_CORRUPT);
350 | }
351 |
352 | for (int j = EncodeCount-1; j >= 0; j--)
353 | {
354 | if (j == 0) Blk->FileCheck = (Blk->FileCheck << 1) + BufSum(Blk->SrcBuf, NumWords);
355 | UnBufDif2(Blk->DstBuf, Blk->SrcBuf, NumWords, &(Blk->PrevIn[j]));
356 | AWORD *SwapBuf = Blk->SrcBuf; Blk->SrcBuf = Blk->DstBuf; Blk->DstBuf = SwapBuf;
357 | }
358 | return SFARKLIB_SUCCESS;
359 | }
360 |
361 | // ==============================================================
362 | bool CheckShift(short *ShiftVal, USHORT NumWords, short *PrevShift, short *PrevUsedShift)
363 | // Here we look to see if the current buffer has been rightshifted
364 | // There is a flag for the whole buffer to show if any shifted data exists,
365 | // and if so there further flags to show if the Shift value changes within each sub block
366 | // of ShiftWin words.
367 | // For any changes, then follows the sub-block number where change occurs, then the new
368 | // ShiftValue. The latter is given either as absolute value (if shift was previously
369 | // non-zero) or relative change from previously used value (if shift was previously zero)
370 | // For non-zero shift value, we then need to leftshift the data by that number of bits.
371 | {
372 | #define ShiftWin 64 // Size of window for Shift
373 |
374 | bool UsingShift = BioReadFlag(); // Read flag to see if using any shift
375 | if (UsingShift) // and if so...
376 | {
377 | int MaxShifts = (NumWords+ShiftWin-1) / ShiftWin; // Number of ShiftWin sized sub-blocks in this block
378 | int ChangePos = 0; // Init. position of last change
379 |
380 | int p = 0;
381 | while (BioReadFlag()) // Read flag to see if there is a (further) change of shift value
382 | {
383 | // Read position of new shift value...
384 | int nb = GetNBits(MaxShifts - ChangePos -1); // number of possible bits for ChangePos
385 | ChangePos = BioRead(nb) + ChangePos; // Get position of next change of shift value
386 |
387 | // Read value of new shift...
388 | short NewShift;
389 | if (*PrevShift == 0) // If previous shift was 0
390 | {
391 | NewShift = InputDiff(*PrevUsedShift); // Get new shift as diff from last used shift
392 | *PrevUsedShift = NewShift; // Update PrevUsedShift
393 | }
394 | else // Else
395 | NewShift = InputDiff(0); // Get new shift as difference from 0
396 |
397 | // Update all ShiftVal[] data prior to change...
398 | if (ChangePos > MaxShifts) // Corrupt data?
399 | {
400 | sprintf(MsgTxt, "ERROR - Invalid Shift ChangePos (apparently %d) %s", ChangePos, CorruptedMsg);
401 | msg(MsgTxt, MSG_PopUp);
402 | GlobalErrorFlag = SFARKLIB_ERR_CORRUPT;
403 | return false;
404 | }
405 |
406 | for ( ; p < ChangePos; p++) ShiftVal[p] = *PrevShift;
407 | *PrevShift = NewShift; // Update prev shift
408 | }
409 |
410 | for ( ; p < MaxShifts; p++) ShiftVal[p] = *PrevShift; // Fill array to end with final shift value
411 |
412 | }
413 | return UsingShift;
414 | }
415 |
416 | // ==============================================================
417 |
418 | int DecompressFast(BLOCK_DATA *Blk, USHORT NumWords)
419 | {
420 | int i, EncodeCount;
421 | short ShiftVal[NSHIFTS]; // Shift values (one per SHIFTWIN words)
422 | USHORT Method[MAX_DIFF_LOOPS]; // Block processing methods used per iteration
423 |
424 | #if DB_BLOCKCHECK // If debug mode block check enabled
425 | ULONG BlockCheck = BioRead(16); // Read block check bits
426 | #endif
427 |
428 | bool UsingShift = CheckShift(ShiftVal, NumWords, &Blk->PrevShift, &Blk->PrevUsedShift);
429 | bool UsingBD4 = BioReadFlag(); // See if using BD4
430 |
431 | if (UsingBD4)
432 | {
433 | EncodeCount = InputDiff(Blk->BD4PrevEncodeCount);
434 | if (InvalidEncodeCount(EncodeCount, Blk->MaxBD4Loops)) return(GlobalErrorFlag = SFARKLIB_ERR_CORRUPT);
435 | Blk->BD4PrevEncodeCount = EncodeCount;
436 | }
437 | else // Using BD2/3
438 | {
439 | EncodeCount = InputDiff(Blk->PrevEncodeCount);
440 | if (InvalidEncodeCount(EncodeCount, Blk->MaxLoops)) return(GlobalErrorFlag = SFARKLIB_ERR_CORRUPT);
441 | Blk->PrevEncodeCount = EncodeCount;
442 |
443 | for(i = 0; i < EncodeCount; i++)
444 | Method[i] = BioReadFlag(); // Read flags for BD2/3
445 | }
446 |
447 | // If using LPC, check for and read flags...
448 | ULONG LPCflags;
449 | bool UsingLPC = (Blk->FileHeader.CompMethod != COMPRESSION_v2Fast);
450 | if (UsingLPC)
451 | {
452 | if (BioReadFlag()) // Any flags?
453 | LPCflags = BioRead(16) | (BioRead(16) << 16); // Then read them (32 bits)
454 | else // else
455 | LPCflags = 0;
456 | }
457 |
458 | // Read the file and unpack the bitstream into buffer at Buf1p...
459 | if (int UnCrunchResult = UnCrunchWin(Blk->SrcBuf, NumWords, OPTWINSIZE) < 0) // failed?
460 | {
461 | sprintf(MsgTxt, "ERROR - UnCrunchWin returned: %d %s", UnCrunchResult, CorruptedMsg);
462 | msg(MsgTxt, MSG_PopUp);
463 | return(GlobalErrorFlag = SFARKLIB_ERR_CORRUPT);
464 | }
465 |
466 | if (UsingLPC)
467 | {
468 | UnLPC(Blk->DstBuf, Blk->SrcBuf, NumWords, Blk->nc, &LPCflags);
469 | AWORD *SwapBuf = Blk->SrcBuf; Blk->SrcBuf = Blk->DstBuf; Blk->DstBuf = SwapBuf;
470 | }
471 |
472 | if (UsingBD4)
473 | {
474 | for (i = EncodeCount-1; i >= 0; i--)
475 | {
476 | UnBufDif4(Blk->DstBuf, Blk->SrcBuf, NumWords, &(Blk->PrevIn[i]));
477 | AWORD *SwapBuf = Blk->SrcBuf; Blk->SrcBuf = Blk->DstBuf; Blk->DstBuf = SwapBuf;
478 | }
479 | }
480 | else
481 | {
482 | for (i = EncodeCount-1; i >= 0; i--)
483 | {
484 | switch (Method[i])
485 | {
486 | case 0: UnBufDif2(Blk->DstBuf, Blk->SrcBuf, NumWords, &(Blk->PrevIn[i])); break;
487 | case 1: UnBufDif3(Blk->DstBuf, Blk->SrcBuf, NumWords, &(Blk->PrevIn[i])); break;
488 | }
489 | AWORD *SwapBuf = Blk->SrcBuf; Blk->SrcBuf = Blk->DstBuf; Blk->DstBuf = SwapBuf;
490 | }
491 | }
492 |
493 | if (UsingShift) UnBufShift(Blk->SrcBuf, NumWords, ShiftVal);
494 |
495 | #if DB_BLOCKCHECK // If debug mode block check enabled
496 | ULONG CalcBlockCheck = adler32(0, (const BYTE *) Blk->SrcBuf, 2*NumWords) & 0xffff;
497 | //ULONG CalcBlockCheck = Blk->FileCheck & 0xffff;
498 | //printf("Audio Block Checks Read: %ld, Calc %ld Length=%d\n", BlockCheck, CalcBlockCheck, 2*NumWords);
499 | //getc(stdin);
500 | if (BlockCheck != CalcBlockCheck) // Compare to calculated cheksum
501 | {
502 | msg("*** Audio Block check FAIL");
503 | }
504 | //else
505 | // printf("Audio Block check Ok\n");
506 | #endif
507 |
508 | Blk->FileCheck = 2 * Blk->FileCheck + BufSum(Blk->SrcBuf, NumWords);
509 | return SFARKLIB_SUCCESS;
510 | }
511 | // ==============================================================
512 | int ProcessNextBlock(BLOCK_DATA *Blk)
513 | {
514 | //int TotBytesRead = 0; // Total bytes read in file
515 | int NumWords; //
516 |
517 | uint32_t n, m; // NB: Must be 32-bit integer
518 |
519 | #define AWBYTES (sizeof(AWORD))
520 | BYTE *zSrcBuf = (BYTE *) Blk->SrcBuf;
521 | BYTE *zDstBuf = (BYTE *) Blk->DstBuf;
522 |
523 | switch (Blk->FileSection)
524 | {
525 | case AUDIO:
526 | {
527 | NumWords = Blk->ReadSize; // Number of words we will read in this block
528 | n = NumWords * AWBYTES; // ... and number of bytes
529 |
530 | if (Blk->TotBytesWritten + n >= Blk->FileHeader.PostAudioStart) // Short block? (near end of file)
531 | {
532 | n = Blk->FileHeader.PostAudioStart - Blk->TotBytesWritten; // Get exact length in bytes
533 | NumWords = n / AWBYTES; // ... and words
534 | Blk->FileSection = POST_AUDIO; // End of Audio -- PostAudio section is next
535 | }
536 |
537 | //printf("AUDIO, read %ld bytes\n", n);
538 |
539 | if (Blk->FileHeader.CompMethod == COMPRESSION_v2Turbo) // If using Turbo compression
540 | DecompressTurbo(Blk, NumWords); // Decompress
541 | else // For all other methods
542 | DecompressFast(Blk, NumWords); // Decompress
543 |
544 | //printf("B4 WriteOutputFile: %ld\n", adler32(0, (const BYTE *) Blk->SrcBuf, n) & 0xffff);
545 | #if BYTE_ORDER == BIG_ENDIAN
546 | #define WFIX(I) s = bp[I+0]; bp[I+0] = bp[I+1]; bp[I+1] = s;
547 | BYTE *bp = (BYTE *) Blk->SrcBuf; BYTE *ep = bp + n;
548 | do {
549 | BYTE s;
550 | WFIX(0); WFIX(2); WFIX(4); WFIX(6);
551 | WFIX(8); WFIX(10); WFIX(12); WFIX(14);
552 | bp += 16;
553 | } while (bp < ep);
554 | #undef WFIX
555 | #endif
556 |
557 | WriteOutputFile((const BYTE *)Blk->SrcBuf, n); // Write to output file
558 | Blk->TotBytesWritten += n; // Accumulate total bytes written
559 | break;
560 | }
561 |
562 | case PRE_AUDIO: case POST_AUDIO: case NON_AUDIO:
563 | {
564 | BioReadBuf((BYTE *) &n, sizeof(n));
565 | FixEndian(&n, sizeof(n));
566 | //printf("Reading PRE/POST AUDIO block, compressed %ld bytes\n", n);
567 | if (n > ZBUF_SIZE) // Check for valid block length
568 | {
569 | sprintf(MsgTxt, "ERROR - Invalid length for Non-audio Block (apparently %d bytes) %s", n, CorruptedMsg);
570 | msg(MsgTxt, MSG_PopUp);
571 | return (GlobalErrorFlag = SFARKLIB_ERR_CORRUPT);
572 | }
573 |
574 | BioReadBuf(zSrcBuf, n); // Read the block
575 | m = UnMemcomp(zSrcBuf, n, zDstBuf, ZBUF_SIZE); //printf("PRE/POST AUDIO block, compressed %ld bytes, uncompressed %ld bytes\n", n, m);
576 |
577 | // Uncompress
578 | if (GlobalErrorFlag != SFARKLIB_SUCCESS) return(GlobalErrorFlag);
579 | if (m <= ZBUF_SIZE) // Uncompressed ok & size is valid?
580 | {
581 | //printf("writing uncompressed block %ld bytes\n", m);
582 | Blk->FileCheck = adler32(Blk->FileCheck, zDstBuf, m); // Accumulate checksum
583 | WriteOutputFile(zDstBuf, m); // and write to output file
584 | Blk->TotBytesWritten += m; // Accumulate byte count
585 | }
586 | else
587 | return SFARKLIB_ERR_CORRUPT;
588 |
589 | #if DB_BLOCKCHECK // If debug mode block check enabled
590 | ULONG BlockCheck = BioRead(16); // Read block check bits
591 | FixEndian(&BlockCheck, sizeof(Blockcheck));
592 | ULONG CalcBlockCheck = adler32(0, zDstBuf, m) & 0xFFFF;
593 | printf("NonAudio Block Checks Read: %ld, Calc %ld Length=%d\n", BlockCheck, CalcBlockCheck, m);
594 | if (BlockCheck != CalcBlockCheck) // Compare to calculated cheksum
595 | {
596 | printf("*** NonAudio Block check FAIL\n");
597 | }
598 | else
599 | printf("NonAudio Block check Ok\n");
600 | #endif
601 |
602 | //printf("PRE/POST AUDIO, read %ld bytes, writing %ld bytes...", n, m);
603 |
604 | if (Blk->TotBytesWritten >= Blk->FileHeader.OriginalSize) // Have we finished the file?
605 | Blk->FileSection = FINISHED;
606 | else if (Blk->FileSection == PRE_AUDIO && Blk->TotBytesWritten >= Blk->FileHeader.AudioStart) // finished Pre-Audio?
607 | Blk->FileSection = AUDIO; // .. then next section is Audio
608 |
609 | break;
610 | } // case
611 | } //switch
612 |
613 | //sprintf(MsgTxt, "BytesWritten: %ld of %ld", Blk->TotBytesWritten, Blk->FileHeader.OriginalSize);
614 | //msg(MsgTxt, 0);
615 | return SFARKLIB_SUCCESS;
616 | }
617 |
618 | // ==============================================================
619 | int EndProcess(int ErrorNum)
620 | {
621 | CloseInputFile();
622 | CloseOutputFile();
623 | return ErrorNum;
624 | }
625 |
626 | // ==============================================================
627 | // Extract License & Notes files
628 | // These are stored as 4-bytes length, followed by length-bytes of compressed data
629 | bool ExtractTextFile(BLOCK_DATA *Blk, ULONG FileType)
630 | {
631 | ULONG n, m;
632 | BYTE *zSrcBuf = (BYTE *) Blk->SrcBuf;
633 | BYTE *zDstBuf = (BYTE *) Blk->DstBuf;
634 |
635 | const char *OutFileName = 0;
636 | if (FileType == FLAGS_License)
637 | OutFileName = OutFileNameLicense;
638 | else if (FileType == FLAGS_Notes)
639 | OutFileName = OutFileNameNotes;
640 | else
641 | return false;
642 |
643 | // NB:Can't use BioReadBuf... aligment problems? Yet it works for ProcessNextBlock() !!??
644 | // Ok, can use ReadInputFile here cause everythjing is whole no. of bytes...
645 |
646 | //BioReadBuf((BYTE *)&n, sizeof(n)); // Read length of block from file
647 | ReadInputFile((BYTE *)&n, sizeof(n)); // Read length of block from file
648 | FixEndian(&n, sizeof(n)); // Fix endian
649 |
650 | if (n <= 0 || n > ZBUF_SIZE) // Check for valid block length
651 | {
652 | sprintf(MsgTxt, "ERROR - Invalid length for %s file (apparently %d bytes) %s", OutFileName, n, CorruptedMsg);
653 | msg(MsgTxt, MSG_PopUp);
654 | GlobalErrorFlag = SFARKLIB_ERR_CORRUPT;
655 | return false;
656 | }
657 |
658 | //BioReadBuf(zSrcBuf, n); // Read the block
659 | ReadInputFile((BYTE *)zSrcBuf, n); // Read the block
660 | m = UnMemcomp(zSrcBuf, n, zDstBuf, ZBUF_SIZE); // Uncompress
661 | Blk->FileCheck = adler32(Blk->FileCheck, zDstBuf, m); // Accumulate checksum
662 | if (GlobalErrorFlag || m > ZBUF_SIZE) // Uncompressed ok & size is valid?
663 | return false;
664 |
665 | OpenOutputFile(OutFileName); // Create notes / license file
666 | WriteOutputFile(zDstBuf, m); // and write to output file
667 | CloseOutputFile();
668 | if (FileType == FLAGS_License)
669 | {
670 | sprintf(MsgTxt, "Created license file: %s", OutFileName);
671 | msg(MsgTxt, 0);
672 | if (GetLicenseAgreement((const char *)zDstBuf, OutFileName) == false)
673 | {
674 | GlobalErrorFlag = SFARKLIB_ERR_LICENSE;
675 | return EndProcess(false);
676 | }
677 | }
678 | else if (FileType == FLAGS_Notes)
679 | {
680 | sprintf(MsgTxt, "Created notes file: %s", OutFileName);
681 | msg(MsgTxt, 0);
682 | DisplayNotes((const char *)zDstBuf, OutFileName);
683 | }
684 |
685 | return true;
686 | }
687 |
688 | // ==============================================================
689 |
690 | int Decode(const char *InFileName, const char *ReqOutFileName)
691 | {
692 | int NumLoops; // Number of loops before screen update etc.
693 |
694 | BLOCK_DATA Blk;
695 | memset(&Blk, 0, sizeof(Blk));
696 | V2_FILEHEADER *FileHeader = &Blk.FileHeader;
697 |
698 | // NB: We keep 2 buffers with pointers in Blk->SrcBuf and Blk->DstBuf
699 | // Generally we process from SrcBuf to DstBuf then swap the pointers,
700 | // so that current data is always at SrcBuf
701 |
702 | // NB: On MacOS/GNU C, the following allocation of Zbuf1 and Zbuf2 causes "segmentation fault"
703 | // BYTE Zbuf1[ZBUF_SIZE]; // Buffer1
704 | // BYTE Zbuf2[ZBUF_SIZE]; // Buffer2
705 | // so instead...
706 |
707 | #if 0
708 | static BYTE Zbuf1[ZBUF_SIZE]; // Buffer1
709 | static BYTE Zbuf2[ZBUF_SIZE]; // Buffer2
710 |
711 | #else
712 | if (Zbuf1 == NULL) Zbuf1 = (BYTE *) calloc(ZBUF_SIZE, sizeof(BYTE));
713 | if (Zbuf2 == NULL) Zbuf2 = (BYTE *) calloc(ZBUF_SIZE, sizeof(BYTE));
714 |
715 | if (Zbuf1 == NULL || Zbuf2 == NULL)
716 | return EndProcess(SFARKLIB_ERR_MALLOC);
717 | #endif
718 |
719 | Blk.SrcBuf = (AWORD *) Zbuf1; // Point to Zbuf1
720 | Blk.DstBuf = (AWORD *) Zbuf2; // Point to Zbuf2
721 |
722 | // Initialisation...
723 | BioDecompInit(); // Initialise bit i/o
724 | LPCinit(); // Init LPC
725 | GlobalErrorFlag = SFARKLIB_SUCCESS;
726 |
727 | // Open input (.sfArk) file and read the header...
728 | OpenInputFile(InFileName);
729 | if (GlobalErrorFlag) return EndProcess(GlobalErrorFlag); // Something went wrong?
730 | ReadHeader(FileHeader, Zbuf1, ZBUF_SIZE);
731 |
732 | if (GlobalErrorFlag) return EndProcess(GlobalErrorFlag); // Something went wrong?
733 |
734 | InitFilenames(FileHeader->FileName, InFileName, ReqOutFileName);
735 | if (GlobalErrorFlag) return EndProcess(GlobalErrorFlag); // Something went wrong?
736 |
737 | if ((FileHeader->Flags & FLAGS_License) != 0) // License file exists?
738 | {
739 | if (ExtractTextFile(&Blk, FLAGS_License) == false)
740 | return EndProcess(GlobalErrorFlag);
741 | }
742 |
743 | if ((FileHeader->Flags & FLAGS_Notes) != 0) // Notes file exists?
744 | {
745 | if (ExtractTextFile(&Blk, FLAGS_Notes) == false)
746 | return EndProcess(GlobalErrorFlag);
747 | }
748 |
749 | OpenOutputFile(OutFileNameMain); // Create the main output file...
750 |
751 | // Set the decompression parameters...
752 | switch (FileHeader->CompMethod) // Depending on compression method that was used...
753 | {
754 | case COMPRESSION_v2Max:
755 | {
756 | //msg("Compression: Max\n");
757 | Blk.ReadSize = 4096;
758 | Blk.MaxLoops = 3;
759 | Blk.MaxBD4Loops = 5;
760 | Blk.nc = 128;
761 | Blk.WinSize = OPTWINSIZE;
762 | NumLoops = 2 * 4096 / Blk.ReadSize;
763 | break;
764 | }
765 | case COMPRESSION_v2Standard:
766 | {
767 | //printf("Compression: Standard\n");
768 | Blk.MaxLoops = 3;
769 | Blk.MaxBD4Loops = 3;
770 | Blk.ReadSize = 4096;
771 | Blk.nc = 8;
772 | Blk.WinSize = OPTWINSIZE;
773 | NumLoops = 50 * 4096 / Blk.ReadSize;
774 | break;
775 | }
776 | case COMPRESSION_v2Fast:
777 | {
778 | //printf("Compression: Fast\n");
779 | Blk.MaxLoops = 20;
780 | Blk.MaxBD4Loops = 20;
781 | Blk.ReadSize = 1024;
782 | Blk.WinSize = OPTWINSIZE;
783 | NumLoops = 300 * 4096 / Blk.ReadSize;
784 | break;
785 | }
786 | case COMPRESSION_v2Turbo:
787 | {
788 | //printf("Compression: Turbo\n");
789 | Blk.MaxLoops = 3;
790 | Blk.MaxBD4Loops = 0;
791 | Blk.ReadSize = 4096;
792 | Blk.WinSize = OPTWINSIZE << 3;
793 | NumLoops = 400 * 4096 / Blk.ReadSize;
794 | break;
795 | }
796 | default:
797 | {
798 | sprintf(MsgTxt, "Unknown Compression Method: %d%s", FileHeader->CompMethod, CorruptedMsg);
799 | GlobalErrorFlag = SFARKLIB_ERR_INCOMPATIBLE;
800 | msg(MsgTxt, MSG_PopUp);
801 | return EndProcess(GlobalErrorFlag);
802 | }
803 | }
804 |
805 | // Process the main file...
806 | Blk.FileSection = PRE_AUDIO; // We start with pre-audio data
807 |
808 | ULONG ProgressUpdateInterval = Blk.FileHeader.OriginalSize / 100; // Calculate progress update
809 | ULONG NextProgressUpdate = ProgressUpdateInterval;
810 | int ProgressPercent = 0;
811 | UpdateProgress(0);
812 |
813 | //int BlockNum = 0;
814 | for (Blk.FileSection = PRE_AUDIO; Blk.FileSection != FINISHED; )
815 | {
816 | for (int BlockCount = 0; BlockCount < NumLoops && Blk.FileSection != FINISHED; BlockCount++)
817 | {
818 | //printf("Block: %d\n", ++BlockNum);
819 | ProcessNextBlock(&Blk);
820 |
821 | while (Blk.TotBytesWritten >= NextProgressUpdate) // Further 1% done since last UpdateProgress?
822 | {
823 | UpdateProgress(++ProgressPercent);
824 | NextProgressUpdate += ProgressUpdateInterval;
825 | }
826 | if (GlobalErrorFlag) return EndProcess(GlobalErrorFlag);
827 | }
828 | // CheckForCancel();
829 | if (GlobalErrorFlag) return EndProcess(GlobalErrorFlag);
830 | }
831 |
832 | if (ProgressPercent != 100) UpdateProgress(100);
833 |
834 | // Check the CheckSum...
835 | if (Blk.FileCheck != FileHeader->FileCheck)
836 | {
837 | sprintf(MsgTxt, "CheckSum Fail!%s",CorruptedMsg);
838 | msg(MsgTxt, MSG_PopUp);
839 | //sprintf(MsgTxt, "Calc check %lx", Blk.FileCheck);
840 | //msg(MsgTxt, MSG_PopUp);
841 | GlobalErrorFlag = SFARKLIB_ERR_FILECHECK;
842 | return EndProcess(GlobalErrorFlag);
843 | }
844 |
845 | sprintf(MsgTxt, "Created %s (%d KiB) successfully.", OutFileNameMain, Blk.TotBytesWritten/1024);
846 | msg(MsgTxt, 0);
847 |
848 | return EndProcess(GlobalErrorFlag);
849 | }
850 |
851 | // ==============================================================
852 |
853 | // Adjust integer held at *num for this machine's endian system
854 | void FixEndian(void *num, int nsize)
855 | {
856 | #if BYTE_ORDER == BIG_ENDIAN
857 | int i;
858 | BYTE bb[4];
859 | for (i = 0; i < nsize; i++) bb[i] = ((BYTE *) num)[i];
860 | for (i = 0; i < nsize; i++) ((BYTE *) num)[i] = bb[nsize-1-i];
861 | #endif
862 | }
863 |
864 | // ==============================================================
865 |
--------------------------------------------------------------------------------
/sfklCrunch.cpp:
--------------------------------------------------------------------------------
1 | // BIO (Bit i/o) routines for sfArk / daArk
2 | // Copyright 1998-2000 Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 |
21 | #include "wcc.h"
22 | #include
23 | #include
24 |
25 | // Static table to store number of bits per word...
26 | static BYTE nb_init = 0;
27 | static BYTE nb[1 << (AWORD_BITS-1)]; // Array to hold number of bits needed to represent each unsigned short value
28 |
29 | // =========================================================================
30 | // Macros for Bit I/O (BIO) ....
31 |
32 | // Static buffer and pointers....
33 | #define BIO_WBITS ((signed) (8 * sizeof(BIOWORD)))
34 | #define BIOBUFSIZE (16 * 1024) // Disk-read buffer size, bigger may increased speed
35 |
36 | BIOWORD2 bioBits; // Bits not yet shifted from bioBuf (up to double length of BIOWORD)
37 | BIOWORD bioBuf[BIOBUFSIZE]; // Buffer
38 |
39 | int bioP; // Count of output (index into bioBuf)
40 | int bioRemBits; // Remaining bits left in bioBits
41 | int bioWholeBlocks; // Count blocks read from disk
42 | short bioPfb; // Previous "FixBits" value
43 |
44 | // --------------------------------------------------------------------------
45 | #define GRP_INBITS(g) \
46 | /* Get grp value from input by counting number of zeroes before we get a 1 */\
47 | g = 0; \
48 | while (bioBits == 0) \
49 | { \
50 | g += bioRemBits; \
51 | CHECK_INBUFFER \
52 | bioBits = bioBuf[bioP++]; \
53 | bioRemBits = BIO_WBITS; \
54 | } \
55 | \
56 | g += bioRemBits; \
57 | while ((bioBits >> --bioRemBits) != 1); \
58 | g -= bioRemBits+1; \
59 | bioBits = LOWBITS(bioBits, bioRemBits)
60 |
61 | // --------------------------------------------------------------------------
62 | #define INBITS(w, n) \
63 | /* Input value w using n bits (n must be <= BIO_WBITS) ... */\
64 | if (bioRemBits < BIO_WBITS) \
65 | { \
66 | CHECK_INBUFFER \
67 | bioBits = (bioBits << BIO_WBITS) | bioBuf[bioP++]; \
68 | bioRemBits += BIO_WBITS; \
69 | } \
70 | bioRemBits -= n; \
71 | w = (BIOWORD) (bioBits >> bioRemBits); \
72 | bioBits = LOWBITS(bioBits, bioRemBits)
73 |
74 | // =========================================================================
75 | #if BYTE_ORDER == BIG_ENDIAN
76 |
77 | #define WFIX(I) s = bp[I+0]; bp[I+0] = bp[I+1]; bp[I+1] = s;
78 | // Read from disk if needed, and fix endians
79 | #define CHECK_INBUFFER \
80 | if (bioP == BIOBUFSIZE) \
81 | { \
82 | bioWholeBlocks++; \
83 | bioP = 0; \
84 | int ReadLen = ReadInputFile((BYTE *) bioBuf, BIOBUFSIZE * sizeof(BIOWORD)); \
85 | if (ReadLen <= 0) return 0; \
86 | BYTE *bp = (BYTE *) bioBuf, *ep = (BYTE *) (bioBuf+BIOBUFSIZE); \
87 | do { \
88 | BYTE s; \
89 | WFIX(0); WFIX(2); WFIX(4); WFIX(6); \
90 | WFIX(8); WFIX(10); WFIX(12); WFIX(14); \
91 | bp += 16; \
92 | } while (bp < ep); \
93 | }
94 |
95 | #else
96 | // Read from disk if needed...
97 | #define CHECK_INBUFFER \
98 | if (bioP == BIOBUFSIZE) \
99 | { \
100 | bioWholeBlocks++; \
101 | bioP = 0; \
102 | int ReadLen = ReadInputFile((BYTE *) bioBuf, BIOBUFSIZE * sizeof(BIOWORD)); \
103 | if (ReadLen <= 0) return 0; \
104 | }
105 |
106 | #endif
107 |
108 | // --------------------------------------------------------------------------
109 | // End of macros
110 | // --------------------------------------------------------------------------
111 |
112 |
113 | // =========================================================================
114 | void BioDecompInit()
115 | {
116 | GetNBits(0); // Initialise nb array
117 | bioRemBits= 0;
118 | bioBits = 0;
119 | bioP = BIOBUFSIZE;
120 | bioPfb = 8;
121 | return;
122 | }
123 | // =========================================================================
124 | void BioDecompEnd()
125 | {
126 | return;
127 | }
128 | // =========================================================================
129 | BIOWORD BioRead(int n)
130 | // Read bits from input, return value
131 | {
132 | BIOWORD w;
133 | INBITS(w, n);
134 | return w;
135 | }
136 |
137 | // =========================================================================
138 | bool BioReadFlag(void)
139 | // Read single bit from input, return value as bool
140 | {
141 | BIOWORD w;
142 | INBITS(w, 1);
143 | return (w != 0);
144 | }
145 |
146 | // =========================================================================
147 | long BioReadBuf(BYTE *buf, long n)
148 | // Read *bytes* to output, return number of BYTES
149 | {
150 | int SavebioP = bioP;
151 | bioWholeBlocks = 0;
152 |
153 | while (n--)
154 | {
155 | BIOWORD b;
156 | INBITS(b, 8);
157 | *buf++ = (BYTE) b;
158 | }
159 |
160 | return (bioP - SavebioP + bioWholeBlocks * BIOBUFSIZE) * sizeof(BIOWORD);
161 | }
162 | // =========================================================================
163 | AWORD InputDiff(AWORD Prev)
164 | // Read a value from input as difference from Previous value, return new value
165 | {
166 | AWORD x;
167 |
168 | GRP_INBITS(x);
169 | if (x != 0) // If non-zero, check sign bit
170 | {
171 | int sign; INBITS(sign, SIGNBIT);
172 | if (sign != 0) x = -x;
173 | }
174 | return x + Prev;
175 | }
176 |
177 | // ==============================================================
178 |
179 | long UnCrunch(AWORD *UnCompBuf, USHORT bufsize)
180 | {
181 | short FixBits;
182 | AWORD *bp = UnCompBuf, *endp = UnCompBuf+bufsize;
183 |
184 | FixBits = InputDiff(bioPfb);
185 | bioPfb = FixBits;
186 |
187 | if (FixBits >= 0 && FixBits < 14)
188 | {
189 | // Uncompress the block...
190 | short FSbits = FixBits + SIGNBIT;
191 | do {
192 | UAWORD grp, LoBits;
193 | INBITS(LoBits, FSbits); // Get LowBits & SignBit
194 | GRP_INBITS(grp); // Get group bits
195 | *bp = ((grp << FixBits) | (LoBits>>1)) ^ -(LoBits&1); // NB: -Sign gives 0 or 0xFFFF
196 | } while (++bp < endp);
197 | }
198 | else if (FixBits == 14) // Non-compressed block?
199 | {
200 | do {
201 | INBITS(*bp, AWORD_BITS);
202 | } while (++bp < endp);
203 | }
204 | else if (FixBits == -1) // Data all 0 and -1 ?
205 | {
206 | do {
207 | INBITS(*bp, 1); // Get SignBit
208 | *bp = -*bp; // Sign=0 means word is 0, Sign=1 means word is -1;
209 | } while (++bp < endp);
210 | }
211 | else if (FixBits == -2) // Data all 0?
212 | {
213 | do *bp = 0; while (++bp < endp); // Set buffer to 0
214 | }
215 | else // Shouldn't happen!
216 | return -1; // Issues an error message
217 |
218 | return 0;
219 | }
220 |
221 | // =========================================================================
222 | long UnCrunchWin(AWORD *buf, USHORT bufsize, USHORT winsize)
223 | {
224 | USHORT finalwinsize = bufsize % winsize;
225 | AWORD *endp = buf + bufsize - finalwinsize;
226 |
227 | for ( ; buf < endp; buf += winsize)
228 | {
229 | long result = UnCrunch(buf, winsize);
230 | if (result < 0) return result;
231 | }
232 |
233 | if (finalwinsize)
234 | {
235 | long result = UnCrunch(buf, finalwinsize);
236 | if (result < 0) return result;
237 | }
238 |
239 | return bufsize;
240 | }
241 |
242 | // =========================================================================
243 | short GetNBits(short w)
244 | // Get the number of bits used by value w
245 | // e.g. w=000b, n=0
246 | // w=001b, n=1
247 | // w=010b, n=2
248 | // w=011b, n=2
249 | // w=100b, n=3
250 | // w=111b, n=3 etc.
251 |
252 | {
253 | // If not initialised (first time), build table in nb[] array...
254 | if (nb_init == 0)
255 | {
256 | long first = 1, last, i;
257 | BYTE nbits = 1;
258 | nb_init = 1;
259 | nb[0] = 0;
260 |
261 | do {
262 | last = first + (1 << (nbits-1));
263 | for (i = first; i < last; i++) nb[i] = nbits;
264 | nbits++;
265 | first = last;
266 | } while(last <= MAX_AWORD);
267 | }
268 | return nb[w];
269 | }
270 |
271 | // =========================================================================
272 |
--------------------------------------------------------------------------------
/sfklDiff.cpp:
--------------------------------------------------------------------------------
1 | // Misc C stuff for sfArk/daArk
2 | // Copyright 1998-2000 Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 |
21 | #include "wcc.h"
22 | #include
23 | #include
24 |
25 | // =========================================================================
26 | void UnBufDif2(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev)
27 | {
28 | // NB: This code is optimised for speed - do not change order of operations or data types!!!
29 | // -----------------------------------------------------------------------------------------
30 |
31 | #if 0
32 | const AWORD *bufend1 = InBuf + bufsize;
33 |
34 | // Process start of buffer...
35 | *OutBuf++ = *InBuf++ + *prev;
36 |
37 | // Process rest of buffer...
38 | #define STEPSIZE 8
39 | #define DO_ONE(N) OutBuf[N] = InBuf[N] + OutBuf[N-1];
40 | // ----------------------------------------------------
41 |
42 | const AWORD *bufend2 = bufend1 - STEPSIZE;
43 | while (InBuf < bufend2)
44 | {
45 | DO_ONE(0); DO_ONE(1); DO_ONE(2); DO_ONE(3);
46 | DO_ONE(4); DO_ONE(5); DO_ONE(6); DO_ONE(7);
47 | OutBuf += STEPSIZE; InBuf += STEPSIZE;
48 | }
49 |
50 | // Do final few...
51 | while (InBuf < bufend1) { DO_ONE(0); OutBuf++; InBuf++; };
52 |
53 | *prev = OutBuf[-1];
54 |
55 | #else
56 | const AWORD *bufend1 = OutBuf + bufsize;
57 |
58 | //for (int i = 0; i < bufsize; i++) OutBuf[i] = InBuf[i];
59 | memcpy(OutBuf, InBuf, bufsize*sizeof(AWORD));
60 |
61 | // Process start of buffer...
62 | *OutBuf++ += *prev;
63 |
64 | // Process rest of buffer...
65 | #define STEPSIZE 8
66 | #define DO_ONE(N) OutBuf[N] += OutBuf[N-1];
67 | // ----------------------------------------------------
68 |
69 | const AWORD *bufend2 = bufend1 - STEPSIZE;
70 | while (OutBuf < bufend2)
71 | {
72 | DO_ONE(0); DO_ONE(1); DO_ONE(2); DO_ONE(3);
73 | DO_ONE(4); DO_ONE(5); DO_ONE(6); DO_ONE(7);
74 | OutBuf += STEPSIZE;
75 | }
76 |
77 | // Do final few...
78 | while (OutBuf < bufend1) {
79 | *OutBuf += OutBuf[-1];
80 | OutBuf++;
81 | };
82 |
83 | *prev = OutBuf[-1];
84 | #endif
85 |
86 | return;
87 |
88 | #undef DO_ONE
89 | #undef STEPSIZE
90 | }
91 |
92 | // =========================================================================
93 | void old_UnBufDif3(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev)
94 | {
95 | // Decoding is done from the END of the buffer, backwards...
96 |
97 | const AWORD *bufstart = InBuf;
98 |
99 | InBuf += bufsize-1;
100 | OutBuf+= bufsize-1;
101 |
102 | // Process end of buffer...
103 | *OutBuf-- = *InBuf--;
104 |
105 | //-----------------------------------------
106 | #define DO_ONE(N) OutBuf[N] = InBuf[N] + NSDIV(InBuf[N-1] + OutBuf[N+1], 1);
107 | // Process rest of buffer...
108 | while (InBuf > bufstart) { DO_ONE(0); InBuf--; OutBuf--; }
109 |
110 | // Final word
111 | *OutBuf = *InBuf + NSDIV(OutBuf[1], 1);
112 |
113 | *prev = OutBuf[bufsize-1];
114 | return;
115 | #undef DO_ONE
116 | }
117 |
118 |
119 | void UnBufDif3(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev)
120 | {
121 | // Decoding is done from the END of the buffer, backwards...
122 |
123 | #define STEPSIZE 8
124 | const AWORD *bufstart = InBuf, *bufstart1 = InBuf+STEPSIZE;
125 |
126 | InBuf += bufsize-1;
127 | OutBuf+= bufsize-1;
128 |
129 | // Process end of buffer...
130 | *OutBuf-- = *InBuf--;
131 |
132 | // Process rest of buffer...
133 | //-----------------------------------------
134 | #define DO_ONE(N) OutBuf[N] = InBuf[N] + NSDIV(InBuf[N-1] + OutBuf[N+1], 1);
135 | //-----------------------------------------
136 |
137 | // Process most of buffer...
138 | while (InBuf > bufstart1)
139 | {
140 | DO_ONE(0); DO_ONE(-1);DO_ONE(-2);DO_ONE(-3);
141 | DO_ONE(-4);DO_ONE(-5);DO_ONE(-6);DO_ONE(-7);
142 | InBuf-=STEPSIZE; OutBuf-=STEPSIZE;
143 | }
144 |
145 | // Process rest of buffer...
146 | while (InBuf > bufstart) { DO_ONE(0); InBuf--; OutBuf--; }
147 |
148 | // Final word
149 | *OutBuf = *InBuf + NSDIV(OutBuf[1], 1);
150 |
151 | *prev = OutBuf[bufsize-1];
152 | return;
153 | #undef DO_ONE
154 | #undef STEPSIZE
155 | }
156 |
157 | // =========================================================================
158 | void UnBufDif4(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev)
159 | {
160 | AWORD avg = *prev;
161 | const AWORD *bufend1 = InBuf + bufsize;
162 |
163 | // Process rest of buffer...
164 | //-----------------------------------------
165 | #define STEPSIZE 8
166 | const AWORD *bufend2 = bufend1 - STEPSIZE;
167 |
168 | #define DO_ONE(N) \
169 | OutBuf[N] = InBuf[N] + avg; \
170 | avg += SDIV(InBuf[N], 1); \
171 |
172 | //-----------------------------------------
173 |
174 | for (; InBuf < bufend2; InBuf += STEPSIZE, OutBuf += STEPSIZE)
175 | {
176 | DO_ONE(0); DO_ONE(1); DO_ONE(2); DO_ONE(3);
177 | DO_ONE(4); DO_ONE(5); DO_ONE(6); DO_ONE(7);
178 | }
179 | for (; InBuf < bufend1; ++InBuf, ++OutBuf)
180 | {
181 | DO_ONE(0);
182 | }
183 |
184 | *prev = avg;
185 | return;
186 |
187 | #undef DO_ONE
188 | #undef STEPSIZE
189 | }
190 | // =========================================================================
191 | long BufSum(const AWORD *buf, USHORT bufsize)
192 | {
193 | // --- Optimised! ---
194 | long Total = 0;
195 |
196 | const AWORD *endp1 = buf + bufsize - 7;
197 | const AWORD *endp2 = buf + bufsize;
198 |
199 | for (; buf < endp1; buf += 8)
200 | {
201 | Total += QUICKABS2(buf[0]) + QUICKABS2(buf[1]) + QUICKABS2(buf[2]) + QUICKABS2(buf[3])
202 | + QUICKABS2(buf[4]) + QUICKABS2(buf[5]) + QUICKABS2(buf[6]) + QUICKABS2(buf[7]);
203 | }
204 |
205 | for ( ; buf < endp2; ++buf)
206 | Total += QUICKABS2(*buf);
207 |
208 | return Total;
209 | }
210 |
211 | // =========================================================================
212 | void UnBufShift1(AWORD *InBuf, USHORT bufsize, short Shift)
213 | {
214 | #define STEPSIZE 8
215 |
216 | // Ok, now we have a shift value - perform the shift...
217 | AWORD *bps = InBuf, *bufend1s = bps + bufsize;
218 | AWORD *bufend2s = bufend1s - STEPSIZE;
219 |
220 | #define DO_ONE(I) bps[I] <<= Shift
221 | while (bps < bufend2s)
222 | {
223 | DO_ONE(0); DO_ONE(1); DO_ONE(2); DO_ONE(3);
224 | DO_ONE(4); DO_ONE(5); DO_ONE(6); DO_ONE(7);
225 | bps += STEPSIZE;
226 | }
227 |
228 | // Do final few...
229 | while (bps < bufend1s) { DO_ONE(0); bps++; };
230 |
231 | return;
232 |
233 | #undef DO_ONE
234 | #undef STEPSIZE
235 | }
236 |
237 | // =========================================================================
238 | void UnBufShift(AWORD *InBuf, USHORT bufsize, short *shift)
239 | {
240 | for(AWORD *endp = InBuf + bufsize; InBuf < endp; InBuf+= SHIFTWIN)
241 | {
242 | short s = *shift++;
243 | if (s != 0) UnBufShift1(InBuf, SHIFTWIN, s);
244 | }
245 |
246 | return;
247 | }
248 | // =========================================================================
249 |
--------------------------------------------------------------------------------
/sfklFile.cpp:
--------------------------------------------------------------------------------
1 | // sfArkLib file i/o
2 | // copyright 1998-2000, Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 |
21 | // NB: When sfArkLib is used with SDL, these functions are replaced
22 | // by equvalents in sdl.cpp because the linker finds those first.
23 |
24 | #include
25 | #include
26 |
27 | #include "wcc.h"
28 | //#include "zlib.h" // only needed for debug printf
29 |
30 | #ifdef TARGET_WIN32
31 | // Windows32 target
32 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
33 | #include "windows.h"
34 | #undef WIN32_LEAN_AND_MEAN
35 |
36 | #define FILE_SHARE_NONE 0
37 | #define NO_SECURITY ((LPSECURITY_ATTRIBUTES) 0)
38 | #define NOT_OVERLAPPED ((LPOVERLAPPED) 0)
39 | #define NO_TEMPLATE ((HANDLE) 0)
40 |
41 | #define CREATEFILE(FileName) CreateFile((LPCTSTR)FileName, GENERIC_WRITE, FILE_SHARE_NONE, NO_SECURITY, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NO_TEMPLATE)
42 | #define OPENFILE(FileName) CreateFile((LPCTSTR)FileName, GENERIC_READ, FILE_SHARE_READ, NO_SECURITY, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL + FILE_FLAG_SEQUENTIAL_SCAN, NO_TEMPLATE)
43 | #define READFILE(fh, Buf, BytesToRead, pBytesRead) ReadFile(fh, Buf, BytesToRead, pBytesRead, NOT_OVERLAPPED)
44 | #define WRITEFILE(fh, Buf, BytesToWrite, pBytesWritten) ReadFile(fh, Buf, BytesToWrite, pBytesWritten, NOT_OVERLAPPED)
45 | #define SETFILEPOINTER(fh, NewPos) (SetFilePointer(fh, NewPos, 0, FILE_BEGIN))
46 | #define CLOSEFILE(fh) (CloseHandle(fh))
47 | #define GETLASTERROR() (GetLastError())
48 |
49 | // Mac, Linux target
50 | #else
51 | typedef FILE* HANDLE;
52 |
53 | #define INVALID_HANDLE_VALUE (NULL)
54 |
55 | #define CREATEFILE(filename) fopen(filename, "wb")
56 | #define OPENFILE(filename) fopen(filename, "rb")
57 | #define READFILE(fh, Buf, BytesToRead, pBytesRead) *pBytesRead = fread(Buf, 1, BytesToRead, fh)
58 | #define WRITEFILE(fh, Buf, BytesToWrite, pBytesWritten) *pBytesWritten = fwrite(Buf, 1, BytesToWrite, fh)
59 | #define SETFILEPOINTER(fh, NewPos) (fseek(fh, NewPos, SEEK_SET))
60 | #define CLOSEFILE(fh) (fclose(fh) == 0)
61 | #define GETLASTERROR() (-1)
62 | #endif
63 |
64 |
65 | // Static data to track current input and output file...
66 | HANDLE InputFileHandle = INVALID_HANDLE_VALUE; // current input file handle
67 | HANDLE OutputFileHandle = INVALID_HANDLE_VALUE; // ... output file handle
68 | char InFileName[SFARKLIB_MAX_FILEPATH]; // current input file name
69 | char OutFileName[SFARKLIB_MAX_FILEPATH]; // ... and output file name
70 | //char *TempFileExt = "$sfkl";
71 |
72 | // Local prototypes...
73 | int ChkErr(const char *message, const char *filename);
74 |
75 | // =================================================================================
76 |
77 | void OpenOutputFile(const char *FileName)
78 | {
79 | strncpy(OutFileName, FileName, sizeof(OutFileName));
80 |
81 | //strcat(OutFileName, TempFileExt); // Add temporary extension
82 |
83 | OutputFileHandle = CREATEFILE(OutFileName);
84 | if (OutputFileHandle == INVALID_HANDLE_VALUE) ChkErr("create", OutFileName);
85 | }
86 | // =================================================================================
87 |
88 | void OpenInputFile(const char *FileName)
89 | {
90 | //printf("OpenInputFile: %s\n", FileName);
91 | strncpy(InFileName, FileName, sizeof(InFileName));
92 | InputFileHandle = OPENFILE(FileName);
93 | if (InputFileHandle == INVALID_HANDLE_VALUE) ChkErr("open", InFileName);
94 | //else printf("OpenInputFile successful\n");
95 | }
96 | // =================================================================================
97 |
98 | int ReadInputFile(BYTE *Buf, int BytesToRead)
99 | {
100 | int BytesRead;
101 |
102 | READFILE(InputFileHandle, Buf, BytesToRead, &BytesRead);
103 | if (BytesRead < 0)
104 | {
105 | ChkErr("read from", InFileName);
106 | BytesRead = 0;
107 | }
108 | //else printf("ReadInputFile Ok: %d bytes read\n", BytesRead);
109 | return BytesRead;
110 | }
111 | // =================================================================================
112 |
113 | int WriteOutputFile(const BYTE *Buf, int BytesToWrite)
114 | {
115 | int BytesWritten;
116 | //printf("WriteOutputFile: bytes=%d\n", BytesToWrite);
117 | WRITEFILE(OutputFileHandle, Buf, BytesToWrite, &BytesWritten);
118 | if (BytesWritten != BytesToWrite)
119 | {
120 | //printf("WriteOutputFile error: %d bytes to write, %d bytes written\n", BytesToWrite, BytesWritten);
121 | ChkErr("write to", OutFileName);
122 | BytesWritten = 0;
123 | }
124 | //else printf("WriteOutputFile Ok: %d bytes written\n", BytesWritten);
125 | return BytesWritten;
126 | }
127 |
128 | // =================================================================================
129 |
130 | bool SetInputFilePosition(int NewPos)
131 | {
132 | if (SETFILEPOINTER(InputFileHandle, NewPos) != 0)
133 | {
134 | ChkErr("SetInputFilePosition", InFileName);
135 | return false;
136 | }
137 | //else printf("SetInputFilePosition Ok: Requested %d Actual %ld\n", NewPos, ftell(InputFileHandle));
138 | return true;
139 | }
140 | // =================================================================================
141 |
142 | bool SetOutputFilePosition(int NewPos)
143 | {
144 | if (SETFILEPOINTER(OutputFileHandle, NewPos) != 0)
145 | {
146 | ChkErr("SetOutputFilePosition", OutFileName);
147 | return false;
148 | }
149 | //else printf("SetOutputFilePosition Ok: Requested %d Actual %ld\n", NewPos, ftell(InputFileHandle));
150 | return true;
151 | }
152 | // =================================================================================
153 |
154 | void CloseInputFile(void)
155 | {
156 | if (InputFileHandle != INVALID_HANDLE_VALUE && CLOSEFILE(InputFileHandle) == 0)
157 | ChkErr("Close input file: ", InFileName);
158 | InputFileHandle = INVALID_HANDLE_VALUE;
159 | return;
160 | }
161 | // =================================================================================
162 |
163 | void CloseOutputFile(void)
164 | {
165 | if (OutputFileHandle != INVALID_HANDLE_VALUE && CLOSEFILE(OutputFileHandle) == 0)
166 | ChkErr("Close output file", OutFileName);
167 |
168 | //char FinalFileName[SFARKLIB_MAX_FILEPATH];
169 | OutputFileHandle = INVALID_HANDLE_VALUE;
170 | return;
171 | }
172 | // =================================================================================
173 |
174 | int ChkErr(const char *ErrorMsg, const char *FileName)
175 | {
176 | int ErrCode;
177 | char ErrDesc[MAX_MSGTEXT];
178 |
179 | if (~GlobalErrorFlag) // Prevent multiple error messages
180 | {
181 | ErrCode = GETLASTERROR();
182 | sprintf(ErrDesc, "OS ERROR %d - Failed to %s: %s", ErrCode, ErrorMsg, FileName);
183 | msg(ErrDesc, MSG_PopUp);
184 | GlobalErrorFlag = SFARKLIB_ERR_FILEIO;
185 | }
186 | return(GlobalErrorFlag);
187 | }
188 |
189 | // =================================================================================
190 | // eof
191 |
--------------------------------------------------------------------------------
/sfklLPC.cpp:
--------------------------------------------------------------------------------
1 | // sfArkLib LPC
2 | // copyright 1998-2000, Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 |
25 | #include "wcc.h"
26 | #include "zlib.h"
27 |
28 | void LPCinit();
29 |
30 | #define REFINT 1 // Integers for Reflection Coefficients (faster)
31 |
32 | #define LPCWIN 4096
33 |
34 | #define PMAX 128 // Max allowed nc
35 | #define ZWINMIN 128 // 128 or 256 best. Smaller - slightly slower
36 | #define ZWINMAX ZWINMIN
37 |
38 | #if (LPCWIN / ZWINMIN) > 32 // Check use of 32bit *Flags
39 | #error Invalid LPCWIN / ZWINMIN
40 | #endif
41 |
42 | // The following parameters determine the history sized used for LPC analysis (little impact on speed)
43 | // The history is the amount of prev
44 | #define HISTSIZE (4*128/ZWINMIN) // Multiple of number of ZWINs to use as history size (seems best value)
45 |
46 | typedef LAWORD LPC_WORD; // LPC_WORD must have (slightly) greater range than AWORD
47 |
48 | // There are compatibility issues in floating point calculations between Intel and Mac versions. Not sure if this
49 | // is a compiler issue or a processor issue -- in short on Windows it seems that calculations performed on float
50 | // datatype get done in double precision. So, we need to force the correct precision when used on Mac.
51 | // Better longterm solution is to force single precision for all calculations (for the compressor also) but
52 | // that would require a version update.
53 | #if 0 // Use double for datatypes, convert to single before storage (doesn't work!)
54 | typedef double LPC_FLOAT;
55 | #else // Use single for datatypes, convert to double for calculations (works)
56 | typedef float LPC_FLOAT;
57 | #endif
58 | typedef double XPN; // eXtra PrecisioN during calculations
59 | typedef float LPN; // Lower PrecisioN to store results of calculations
60 |
61 | #define ISCALE_BITS 14 // Fixed scale seems to work fine in practice
62 | #define ISCALE (1 << ISCALE_BITS)
63 |
64 | #if REFINT == 1
65 | typedef long LPC_PRAM;
66 | #else
67 | typedef LPC_FLOAT LPC_PRAM;
68 | #endif
69 |
70 | typedef LPC_FLOAT LPC_CORR;
71 | typedef LPC_FLOAT LPC_CORR2; // Holds LPC_CORR*LPC_CORR
72 |
73 | // ======================================================================
74 | LPC_CORR schur( // returns the minimum mean square error
75 | LPC_CORR const * ac, // in: [0...p] autocorrelation values
76 | int nc, // in: number of ref. coeff
77 | LPC_PRAM * ref) // out: [0...p-1] reflection coefficients
78 | {
79 | int i, m;
80 |
81 | LPC_CORR2 error, r;
82 | LPC_CORR2 Gen0[PMAX], Gen1[PMAX];
83 |
84 | if (ac[0] == 0)
85 | {
86 | for (i = 0; i < nc; i++) ref[i] = 0;
87 | return 0;
88 | }
89 |
90 | // Initialize the rows of the generator matrix G to ac[1...p].
91 | error = ac[0];
92 |
93 | for (i = 0; i < nc; i++)
94 | Gen0[i] = Gen1[i] = ac[i + 1];
95 |
96 | // static int blk = 0;
97 |
98 | for (i = 0;;)
99 | {
100 | // Calculate this iteration's reflection coefficient and error.
101 | r = - (LPN) ((XPN)Gen1[0] / (XPN)error);
102 | error = (LPN) ( (XPN)error + ((XPN)Gen1[0] * (XPN)r) );
103 |
104 | #if REFINT == 1
105 | ref[i] = (LPC_PRAM) ( (LPN)((XPN)r * ISCALE)) ; // Scale-up to avoid loss of precision
106 | #else
107 | ref[i] = r;
108 | #endif
109 |
110 | if (++i >= nc) break;
111 |
112 | // Update the generator matrix.
113 | for (m = 0; m < nc - i; m++)
114 | {
115 | // Gen1[m] = (XPN) Gen1[m + 1] + ((XPN) r * (XPN) Gen0[m]);
116 | // Gen0[m] = (XPN) Gen0[m] + ((XPN) r * (XPN) Gen1[m + 1]);
117 | Gen1[m] = (LPN) ( (XPN) Gen1[m + 1] + ((XPN) r * (XPN) Gen0[m]) );
118 | Gen0[m] = (LPN) ( (XPN) Gen0[m] + ((XPN) r * (XPN) Gen1[m + 1]) );
119 | }
120 | }
121 |
122 | // blk++;
123 | return error;
124 | }
125 |
126 | // ======================================================================
127 | // Compute the autocorrelation
128 | void autocorrelation(int n, LPC_WORD const *ibuf, int nc, LPC_CORR *ac)
129 | {
130 | int i;
131 |
132 | // Copy integer data to float -- speeds things up slightly...
133 | LPC_FLOAT buf[ZWINMAX];
134 | for (i = 0; i < n ; i++) buf[i] = (LPC_FLOAT) ibuf[i];
135 |
136 | while (nc--)
137 | {
138 | LPC_CORR c = 0;
139 | LPC_FLOAT const *lbuf = buf + nc; // Points to current sample + nc
140 |
141 | #define CI(I) ( ((XPN)buf[I] * (XPN)lbuf[I]) )
142 | //#define CI(I) (buf[I] * lbuf[I])
143 |
144 | int istop = n - nc - 15; // Process 16 steps at a time for speed...
145 | for (i = 0; i < istop; i += 16)
146 | c = (LPN) ((XPN) c + CI(i+0) + CI(i+1) + CI(i+2) + CI(i+3) + CI(i+4) + CI(i+5) + CI(i+6) + CI(i+7)
147 | + CI(i+8) + CI(i+9) + CI(i+10)+ CI(i+11)+ CI(i+12)+ CI(i+13)+ CI(i+14)+ CI(i+15) );
148 |
149 | istop = n - nc; // Process any remainder, one step at a time...
150 | for (; i < istop; i++)
151 | c = (LPN) ( (XPN) c + CI(i) );
152 |
153 | ac[nc] = c;
154 | #undef CI
155 | }
156 | }
157 |
158 |
159 | // ======================================================================
160 | // Add the autocorrelation for the end section of previous Window / start of current window
161 | void AddAC (LPC_WORD const *hbuf, LPC_WORD const *ibuf, int nc, LPC_CORR *ac)
162 | {
163 | int i;
164 |
165 | // Copy integer data to float -- speeds things up slightly...
166 | LPC_FLOAT buf[PMAX*2];
167 |
168 | int n = nc-1; // Number of samples is always one less than nc value
169 |
170 | for (i = 0; i < n ; i++)
171 | {
172 | buf[i] = (LPC_FLOAT) hbuf[i];
173 | buf[i + n] = (LPC_FLOAT) ibuf[i];
174 | }
175 |
176 | while (nc-- > 1)
177 | {
178 | LPC_CORR c = 0;
179 | LPC_FLOAT const *lbuf = buf + nc; // Points to current sample + nc
180 |
181 | int istop;
182 |
183 | #define CI(I) ( ((XPN)buf[I] * (XPN)lbuf[I]) )
184 | //#define CI(I) (buf[I] * lbuf[I])
185 |
186 | istop = n - 15; // Process 16 steps at a time for speed...
187 | i = n - nc;
188 |
189 | for (; i < istop; i += 16)
190 | c = (LPN) ( (XPN) c + CI(i+0) + CI(i+1) + CI(i+2) + CI(i+3) + CI(i+4) + CI(i+5) + CI(i+6) + CI(i+7)
191 | + CI(i+8) + CI(i+9) + CI(i+10)+ CI(i+11)+ CI(i+12)+ CI(i+13)+ CI(i+14)+ CI(i+15) );
192 |
193 | istop = n; // Process any remainder, one step at a time...
194 | for (; i < istop; i++)
195 | c = (LPN) ( (XPN) c + (XPN) CI(i) );
196 |
197 | ac[nc] = (LPN) ( (XPN) ac[nc] + (XPN) c );
198 | #undef CI
199 | }
200 | }
201 |
202 | // ======================================================================
203 | static void LPCdecode(
204 | LPC_PRAM const *ref, // in: [0...p-1] reflection coefficients
205 | int nc, // in: number of coefficients
206 | int n, // # of samples
207 | LPC_WORD const *in, // [0...n-1] residual input
208 | LPC_WORD *out) // out: [0...n-1] short-term signal
209 |
210 | {
211 | LPC_WORD s;
212 | static LPC_WORD u[PMAX+1]; // NB: Intermediate values here can be out of range of AWORD
213 | int i;
214 |
215 | if (in == LAW_NULL) // Initialise?
216 | {
217 | for (i = 0; i < PMAX; i++) u[i] = 0;
218 | return;
219 | }
220 |
221 | while (n--)
222 | {
223 | s = *in++;
224 |
225 | #if REFINT == 1 //22.4 8gm
226 | // ------------------------------------------------------
227 | #define LPC_AN1(I) \
228 | s -= SDIV(refp[I] * up[I], ISCALE_BITS); \
229 | up[I+1] = up[I] + SDIV(refp[I] * s, ISCALE_BITS); \
230 | // ------------------------------------------------------
231 |
232 | LPC_PRAM const *refp = ref+nc-1;
233 | LPC_WORD *up = u+nc-1;
234 |
235 | while(refp >= ref)
236 | {
237 | LPC_AN1(0) ; LPC_AN1(-1); LPC_AN1(-2); LPC_AN1(-3);
238 | LPC_AN1(-4); LPC_AN1(-5); LPC_AN1(-6); LPC_AN1(-7);
239 | up -= 8; refp -= 8;
240 | }
241 | #undef LPC_AN1
242 |
243 | #else
244 | for (i = nc; i--;)
245 | {
246 | #if REFINT == 1
247 | #if 1 // Use SDIV
248 | long m;
249 | m = ( ref[i] * u[i] );
250 | s = ( s - SDIV(m, ISCALE_BITS) );
251 | m = ( ref[i] * s );
252 | u[i+1] = ( u[i] + SDIV(m, ISCALE_BITS) );
253 | #else
254 | s = s - ref[i] * u[i] / ISCALE;
255 | u[i+1] = u[i] + (ref[i] * s / ISCALE);
256 | #endif
257 | #else // Use floating point, convert to int...
258 | s = s - (int) (ref[i] * u[i]);
259 | u[i+1] = u[i] + (int) (ref[i] * s);
260 | #endif
261 | }
262 | #endif
263 |
264 | *out++ = u[0] = s;
265 | }
266 | }
267 |
268 |
269 | // ======================================================================
270 |
271 | // UnLPC2() is called by UnLPC() -- process one LPCWIN sized chunk
272 |
273 | long UnLPC2(LPC_WORD *OutBuf, LPC_WORD *InBuf, short bufsize, short nc, ULONG *Flags)
274 | {
275 | static LPC_WORD HistBuf[PMAX*2];
276 |
277 | static LPC_CORR AcHist[HISTSIZE][PMAX+1];
278 | static int HistNum;
279 |
280 | LPC_PRAM ref[PMAX];
281 | LPC_CORR ac[PMAX+1];
282 |
283 | int i, k;
284 | ULONG FlagMask = 1;
285 | int zwin = ZWINMIN;
286 | if (nc > zwin) zwin = ZWINMAX;
287 |
288 | if (InBuf == LAW_NULL) // Initialise?
289 | {
290 | HistNum = 0;
291 | for (i = 0; i < nc; i++) ref[i] = 0;
292 | for (i = 0; i < PMAX*2; i++) HistBuf[i] = 0;
293 | for (i = 0; i < PMAX+1; i++)
294 | for (int j = 0; j < HISTSIZE; j++)
295 | AcHist[j][i] = 0;
296 | // LPCdecode(LAW_NULL, nc, 0, LAW_NULL, LAW_NULL);
297 | LPCdecode(NULL, nc, 0, NULL, NULL);
298 | return 0;
299 | }
300 |
301 | //if ((bufsize % zwin) != 0) return -3;
302 |
303 | for (i = 0; i < bufsize; i += zwin)
304 | {
305 | #if HISTSIZE == 4
306 | for (k = 0; k < nc+1; k++)
307 | ac[k] = (XPN)AcHist[0][k] + (XPN)AcHist[1][k] + (XPN)AcHist[2][k] + (XPN)AcHist[3][k];
308 | #else
309 | for (k = 0; k < nc+1; k++)
310 | {
311 | ac[k] = 0;
312 | for (int h = 0; h < HISTSIZE; h++)
313 | ac[k] = (XPN)ac[k] + (XPN)AcHist[h][k];
314 | }
315 | #endif
316 |
317 | // Decode...
318 |
319 | if ((*Flags & FlagMask) == 0)
320 | {
321 | schur(ac, nc, ref);
322 | LPCdecode(ref, nc, zwin, InBuf+i, OutBuf+i);
323 | }
324 | else
325 | {
326 | LPCinit(); // Re-initialise
327 | for (int j = 0; j < zwin; j++) OutBuf[i+j] = InBuf[i+j]; // Copy input to output
328 | }
329 | FlagMask <<= 1;
330 |
331 | // Update the AutoCorrelation history data...
332 | AddAC(HistBuf, OutBuf+i, nc+1, AcHist[HistNum]); // Process overlap of prev. & current buffer
333 | if (++HistNum == HISTSIZE) HistNum = 0; // Increment History counter, wrap-around if needed
334 |
335 | autocorrelation(zwin, OutBuf+i, nc+1, AcHist[HistNum]); // Update AcHist with current buffer
336 | for (k = 0; k < nc; k++) HistBuf[k] = OutBuf[i+k]; // Store beginning of current buffer for next AddAC()
337 | }
338 |
339 | return 0;
340 | }
341 |
342 | // ======================================================================
343 |
344 | void LPCinit()
345 | {
346 | UnLPC2(LAW_NULL, LAW_NULL, 0, 0, (ULONG *)0);
347 | }
348 | // ======================================================================
349 |
350 | long UnLPC(AWORD *OutBuf, AWORD *InBuf, short bufsize, short nc, ULONG *Flags)
351 | {
352 | long OutBits = 0;
353 | LPC_WORD lInBuf[MAX_BUFSIZE], lOutBuf[MAX_BUFSIZE];
354 | LPC_WORD *inp = lInBuf, *bufend = inp + bufsize, *outp = lOutBuf;
355 |
356 | int i;
357 |
358 | // Copy 16 bit data to 32 bits...
359 | while (inp < bufend) *inp++ = *InBuf++;
360 |
361 | inp = lInBuf;
362 |
363 | short WinSize = LPCWIN;
364 | if (WinSize > bufsize) WinSize = bufsize;
365 |
366 | int WordsLeft = bufsize;
367 | do {
368 | if (WordsLeft < ZWINMIN)
369 | {
370 | for (i = 0; i < WordsLeft; i++)
371 | outp[i] = inp[i];
372 | }
373 | else
374 | {
375 | long LPCout = UnLPC2(outp, inp, WinSize, nc, Flags);
376 | if (LPCout < 0) return LPCout;
377 | OutBits += LPCout;
378 | }
379 |
380 | inp += WinSize;
381 | outp += WinSize;
382 | WordsLeft -= WinSize;
383 |
384 | } while (inp < bufend);
385 |
386 | // Copy 32 bit data to 16 bits...
387 | outp = lOutBuf; bufend = outp + bufsize;
388 | while (outp < bufend)
389 | *OutBuf++ = (AWORD) *outp++;
390 |
391 | return 0;
392 | }
393 |
394 |
395 | // ======================================================================
396 |
--------------------------------------------------------------------------------
/sfklString.cpp:
--------------------------------------------------------------------------------
1 | //sfArkLib String functions
2 | // copyright 1998-2000 Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 | #include
21 | #include
22 | #include "wcc.h"
23 |
24 | char *GetFileExt(char *FileName)
25 | {
26 | // return pointer to (final) file extension including the dot e.g. '.txt'
27 | // returns NULL if extension is not found
28 | char *p;
29 |
30 | for(p = FileName + strlen(FileName); p > FileName; p--)
31 | {
32 | if (*p == '.')
33 | {
34 | return p;
35 | }
36 | else if (*p == '/' || *p == '\\')
37 | {
38 | return NULL;
39 | }
40 | }
41 |
42 | return NULL;
43 | }
44 |
45 | char *StrncpyEnsureNul(char *destination, const char *source, int num)
46 | {
47 | if (num <= 0 || !destination)
48 | {
49 | return destination;
50 | }
51 | else if (!source)
52 | {
53 | destination[0] = '\0';
54 | return destination;
55 | }
56 | else
57 | {
58 | // same as strncpy, except it ensures the result is nul-terminated.
59 | char *ret = strncpy(destination, source, num - 1);
60 | destination[num - 1] = 0;
61 | return ret;
62 | }
63 | }
64 |
65 | void ChangeFileExt(const char *path, const char *newExtension, char *out, int outSize)
66 | {
67 | if (strlen(path) >= MAX_FILEPATH)
68 | {
69 | // path is too long for our buffer
70 | out[0] = 0;
71 | return;
72 | }
73 |
74 | char pathWithoutExtension[MAX_FILEPATH] = "";
75 | StrncpyEnsureNul(pathWithoutExtension, path, sizeof(pathWithoutExtension));
76 | char *p = GetFileExt(pathWithoutExtension);
77 | if (p)
78 | {
79 | // add null-terminator where the '.' used to be.
80 | *p = 0;
81 | }
82 |
83 | // if there's no extension in the input, we'll simply append the new extension.
84 | int ret = snprintf(out, outSize, "%s%s", pathWithoutExtension, newExtension);
85 | if (ret < 0 || ret >= outSize)
86 | {
87 | out[0] = 0;
88 | return;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/sfklZip.cpp:
--------------------------------------------------------------------------------
1 | // sfArkLib ZLIB interface
2 | // Copyright 1998-2000 Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 | #include
21 | #include
22 |
23 | #include "wcc.h"
24 | #include "zlib.h"
25 |
26 | ULONG UnMemcomp(const BYTE *InBuf, int InBytes, BYTE *OutBuf, int OutBufLen)
27 | {
28 | // Uncompress buffer using ZLIBs uncompress function...
29 | unsigned long OutBytes = OutBufLen;
30 | int Result = uncompress(OutBuf, &OutBytes, InBuf, InBytes);
31 | if (Result != Z_OK) // uncompress failed?
32 | {
33 | sprintf(MsgTxt, "ZLIB uncompress failed: %d", Result);
34 | msg(MsgTxt, MSG_PopUp);
35 | OutBytes = 0;
36 | if (Result == Z_MEM_ERROR)
37 | GlobalErrorFlag = SFARKLIB_ERR_MALLOC;
38 | else
39 | GlobalErrorFlag = SFARKLIB_ERR_CORRUPT;
40 | }
41 |
42 | return OutBytes;
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/wcc.h:
--------------------------------------------------------------------------------
1 | // Definitions for sfArk / WaveComp
2 | // Copyright 1998-2000 Andy Inman
3 | // Contact via: http://netgenius.co.uk or http://melodymachine.com
4 |
5 | // This file is part of sfArkLib.
6 | //
7 | // sfArkLib is free software: you can redistribute it and/or modify
8 | // it under the terms of the GNU General Public License as published by
9 | // the Free Software Foundation, either version 3 of the License, or
10 | // (at your option) any later version.
11 | //
12 | // sfArkLib is distributed in the hope that it will be useful,
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | // GNU General Public License for more details.
16 | //
17 | // You should have received a copy of the GNU General Public License
18 | // along with sfArkLib. If not, see .
19 |
20 | #if defined(USE_MANUAL_ENDIANNESS) && \
21 | (defined(MANUAL_LITTLE_ENDIAN) || defined(MANUAL_BIG_ENDIAN))
22 | #define LITTLE_ENDIAN 1234
23 | #define BIG_ENDIAN 4321
24 | #ifdef MANUAL_LITTLE_ENDIAN
25 | #define BYTE_ORDER LITTLE_ENDIAN
26 | #else
27 | #define BYTE_ORDER BIG_ENDIAN
28 | #endif
29 | #elif defined(USE_SYS_ENDIAN_H)
30 | /* BSD */
31 | #include
32 | #elif defined(USE_ENDIAN_H)
33 | /* GNU */
34 | #include
35 | #endif
36 |
37 | #if !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
38 | #error ENDIAN system undefined
39 | #endif
40 |
41 | #if (BYTE_ORDER != LITTLE_ENDIAN) && (BYTE_ORDER != BIG_ENDIAN)
42 | /* PDP endian or something */
43 | #error only big or little endian systems are supported
44 | #endif
45 |
46 | #include "sfArkLib.h"
47 |
48 | // ------------------------------------------------------------------------------------
49 | // The following are now defined in sfarklib.h ... redefined here for compatibility...
50 | #define MAX_FILENAME SFARKLIB_MAX_FILENAME
51 | #define MAX_FILEPATH SFARKLIB_MAX_FILEPATH
52 | #define MAX_MSGTEXT SFARKLIB_MAX_MSGTEXT
53 | #define MSG_SameLine SFARKLIB_MSG_SameLine
54 | #define MSG_AppendLine SFARKLIB_MSG_AppendLine
55 | #define MSG_PopUp SFARKLIB_MSG_PopUp
56 |
57 | #define msg(a, b) sfkl_msg(a, b) // Message display function
58 | #define UpdateProgress(a) sfkl_UpdateProgress(a) // Progress indication
59 | #define GetLicenseAgreement(a, b) sfkl_GetLicenseAgreement(a, b)// Display/confirm license
60 | #define DisplayNotes(a, b) sfkl_DisplayNotes(a, b) // Display notes text file
61 | #define GetsfArkLibVersion(a) sfkl_GetVersion(a)
62 | #define Decode(a, b) sfkl_Decode(a, b)
63 | // ------------------------------------------------------------------------------------
64 |
65 | // -------- Global flags and data ----------
66 | #ifdef SFARKLIB_GLOBAL // Compiling main file?
67 | //bool Aborted;
68 | int GlobalErrorFlag;
69 | const char ProgName[] = "sfArkLib";
70 | const char ProgVersion[] = " 3.00"; // 5 characters xx.xx
71 | const unsigned char ProgVersionMaj = 30; // 0-255 = V0 to V25.5xx, etc.
72 | const unsigned char ProgVersionMin = 00; // 0-99 = Vx.x99, etc.
73 | char MsgTxt[MAX_MSGTEXT]; // Used with sprintf to build message // Text buffer for msg()
74 | unsigned SourceFileOffset = 0; // Set non-zero by app for self-extraction
75 | #else
76 | //extern bool Aborted;
77 | extern int GlobalErrorFlag;
78 | extern char *MsgTxt;
79 |
80 | extern const char *ProgName; // e.g. "sfArkLib"
81 | extern const char *ProgVersion; // e.g."2.10 "
82 | extern const unsigned char ProgVersionMaj; // 00-255 = V25.5x, etc.
83 | extern const unsigned char ProgVersionMin; // 00-99 = Vx.x99, etc.
84 | extern unsigned SourceFileOffset; // Set non-zero by app for self-extraction
85 | #endif
86 |
87 | // ----- typdefs -----
88 | typedef unsigned short USHORT;
89 | typedef unsigned char BYTE;
90 | typedef unsigned int ULONG;
91 | //typedef int bool;
92 |
93 | typedef short AWORD; // Audio word, i.e. 16-bit audio
94 | typedef unsigned short UAWORD;
95 | typedef int LAWORD; // "long" audio word, i.e. 32 bits
96 | typedef unsigned int ULAWORD;
97 |
98 | // Types used by Bit I/O (BIO) routines...
99 | typedef USHORT BIOWORD;
100 | typedef ULONG BIOWORD2;
101 |
102 | // -------------------
103 |
104 |
105 | // ----- Constants -----
106 | #ifndef true
107 | #define true 1
108 | #define false 0
109 | #endif
110 |
111 | #define SHIFTWIN 64 // window size used for shift operations
112 |
113 | // Just for readability...
114 | #define SIGNBIT 1
115 | #define FLAGBIT 1
116 |
117 | // Some max sizes...
118 | #define MAX_BUFSIZE 4096 // Largest buffer size
119 | #define MAX_AWORD ( (1 << (AWORD_BITS-1)) -1 ) // 32767 for 16-Bit AWORD
120 | #define MAX_UAWORD ( (1 << AWORD_BITS)-1 ) // 65535 for 16-Bit AWORD
121 |
122 | // Typed NULLs ...
123 | #define FL_NULL ((float *) 0)
124 | #define AW_NULL ((AWORD *) 0)
125 | #define LAW_NULL ((LAWORD *) 0)
126 |
127 | // Compression methods...
128 | #define COMPRESSION_v1 0 // sfArk V1 compression
129 | #define COMPRESSION_v1Fast 1 // sfArk V1.1 "Fast" compression
130 | #define COMPRESSION_v1Full 2 // sfArk V1.1 "Full" compression
131 |
132 | #define COMPRESSION_v2 3 // Lowest value for V2 compression
133 |
134 | #define COMPRESSION_v2NonAudio 3 // sfArk V2 "NonAudio" (uses ZLib MemComp)
135 | #define COMPRESSION_v2Turbo 4 // sfArk V2 "Turbo" compression (BD2 only, maxloops 3)
136 | #define COMPRESSION_v2Fast 5 // sfArk V2 "Fast" compression (BD2,3,4, maxloops 15)
137 | #define COMPRESSION_v2Standard 6 // sfArk V2 "Standard" compression (BD2 + LPC, 8 LPC parameters)
138 | #define COMPRESSION_v2Max 7 // sfArk V2 "Max" compression (BD2, 3, 4 + LPC with 128(?) LPC parameters)
139 | #define COMPRESSION_v2Custom 8 // sfArk V2 "Custom" compression (user choices)
140 | #define COMPRESSION_NotV1 254 // Returned by ReadV1Header() for non-V1 files
141 | #define COMPRESSION_Error 255 // Returned by ReadV1Header() for unrecognised compression type
142 |
143 | // ----------------------
144 |
145 | // ------ Macros -------
146 | #define RETURN_ON_ERROR() if (GlobalErrorFlag != SFARKLIB_SUCCESS) return(GlobalErrorFlag)
147 | #define JUMP_ON_ERROR(label) if (GlobalErrorFlag != SFARKLIB_SUCCESS) goto label
148 |
149 | #if BYTE_ORDER == BIG_ENDIAN
150 | #define FIX_ENDIAN16(w) ((((BYTE) w) << 8) | (((USHORT)w) >> 8))
151 | #else
152 | #define FIX_ENDIAN16(w) (w)
153 | #endif
154 |
155 | #define BIT_SIZEOF(x) (sizeof(x) * 8)
156 | #define AWORD_BITS BIT_SIZEOF(AWORD) // Number of bits in Audio Word
157 |
158 | #define ABS(x) ( ((x) > 0) ? (x) : -(x))
159 |
160 | #define MIN(x, y) ( ( (x) < (y) )? (x) : (y) )
161 | #define MAX(x, y) ( ( (x) > (y) )? (x) : (y) )
162 | #define NZSIGN(w) ((w) != 0) // Used to add 1 for SignBit if value is non-zero
163 | #define LOWBITS(w, n) ( (w) & ((1 << (n))-1) )
164 |
165 |
166 | #if 0 // Safer methods (use in case of compile compatibility problems, etc)...
167 | #define SIGN(x) ( ((x) >= 0) ? 0 : 1)
168 | #define QUICKABS(x) ABS(x)
169 | #define QUICKABS2(x) ( ABS(x) - SIGN(x) )
170 |
171 | #else
172 | // Quick "absolute value" for (much faster than using conditional) ...
173 | // if x is positive QUICKABS2(x) = abs(x) ... but...
174 | // if x is negative QUICKABS2(x) = abs(x)-1 -- wrong! but suits many of our purposes here!
175 | #define SIGN(x) ( (((x)) >> (BIT_SIZEOF(x)-1)) & 1 ) // Fast! Returns 0 for positive, 1 for negative
176 | #define QUICKABS2(x) ( (x) ^ ( (x) >> (BIT_SIZEOF(x)-1) ) ) // Fast version (inaccurate for negative value)
177 | #define QUICKABS(x) ( QUICKABS2(x) + SIGN(x) ) // Correct ABS value
178 |
179 | #endif
180 |
181 | // Fast division using Shift for Unsigned numbers (or where innacuracy isn't a problem)
182 | // Innacurate on negative odd numbers, e.g. NSDIV(-100, 1) gives -51 instead of -50. (Use SDIV instead).
183 | #define NSDIV(x, y) ( (x) >> (y) )
184 |
185 | // Fast division using Shift for Signed numbers
186 | #define SDIV(x, y) ( ((x) >= 0)? (x) >> (y) : -((-(x)) >> (y)) )
187 |
188 | // ------- Prototypes -------
189 |
190 | // sfArkLib_Coding...
191 | //extern USHORT GetsfArkLibVersion(void);
192 | //extern int Decode(const char *InFileName, const char *ReqOutFileName);
193 | extern void FixEndian(void *num, int nsize);
194 |
195 | // sfArkLib_Diff...
196 | extern long BufSum(const AWORD *buf, USHORT bufsize);
197 | extern void UnBufDif2(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev);
198 | extern void UnBufDif4(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev);
199 | extern void UnBufDif3(AWORD *OutBuf, const AWORD *InBuf, USHORT bufsize, AWORD *prev);
200 | extern void UnBufShift(AWORD *Buf, USHORT SizeOfBuf, short *Shifts);
201 |
202 | // sfArkLib_Crunch...
203 | extern long UnCrunchWin(AWORD *Buf, USHORT BufSize, USHORT WinSize);
204 | extern void BioDecompInit(void);
205 | extern void BioDecompEnd(void);
206 | extern BIOWORD BioRead(int NumberOfBits);
207 | extern bool BioReadFlag(void);
208 | extern long BioReadBuf(BYTE *Buf, long BufSize);
209 | extern AWORD InputDiff(AWORD PrevValue);
210 | extern short GetNBits(short w);
211 |
212 | // sfArkLib_File (or supplied by SDL.cpp)...
213 | extern void OpenOutputFile(const char *FileName);
214 | extern void OpenInputFile(const char *FileName);
215 | extern int ReadInputFile(BYTE *Buf, int NumberOfBytesToRead);
216 | extern int WriteOutputFile(const BYTE *Buf, int NumberOfBytesToWrite);
217 | extern bool SetInputFilePosition(int NewPos);
218 | extern bool SetOutputFilePosition(int NewPos);
219 | extern void CloseInputFile(void);
220 | extern void CloseOutputFile(void);
221 |
222 | // sfArkLib_LPC...
223 | extern void LPCinit(void);
224 | extern long UnLPC(AWORD *OutBuf, AWORD *InBuf, short bufsize, short nc, ULONG *Flags);
225 |
226 | // sfArkLib_Zip...
227 | extern ULONG UnMemcomp(const BYTE *InBuf, int InBytes, BYTE *OutBuf, int OutBufLen);
228 |
229 | // sfArkLib_String...
230 | extern char *StrncpyEnsureNul(char *destination, const char *source, int num);
231 | void ChangeFileExt(const char *path, const char *newExtension, char *out, int outSize);
232 |
--------------------------------------------------------------------------------