pax_global_header00006660000000000000000000000064127017003640014512gustar00rootroot0000000000000052 comment=e740c549e59a3a58dca615478dc5dcee3fb915d8 jbig2dec-0.13/000077500000000000000000000000001270170036400131065ustar00rootroot00000000000000jbig2dec-0.13/.gitignore000066400000000000000000000001211270170036400150700ustar00rootroot00000000000000# ignore normal build products jbig2dec libjbig2dec.a # ignore object files *.o jbig2dec-0.13/CHANGES000066400000000000000000000050701270170036400141030ustar00rootroot00000000000000Version 0.13 (2016 April 07) * Bug fix release. Version 0.12 (2014 October 1) * Bug fix release. Version 0.11 (2010 February 2) * Support for generic regions with typical prediction (042_8.jb2) * Correct bitmap offsets with transposed text (042_19.jb2) * Autotools build now uses libtool and provides a shared library * Manpage for jbig2dec * Code cleanup and robustness fixes Version 0.10 (2009 May 28) * Security fix for malicious symbol dictionaries CVE-2009-0196 * Fix various resource leaks and error handling issues * Dynamically allocate huffman symbol length histogram to save space * Support aggregate symbol coding * Work around invalid Xerox WorkCentre streams which write the final segment length as -1 * Fix an issue with huffman table runcodes Version 0.9 (2006 July 27) * striped page support * successfully decodes ubc test streams 042_9, 042_20 Version 0.8 (2005 April 6) * Fix an allocation error in the page array * properly handle non-OR image composition operators * Fix a UMR bug in the compositor * successfully decodes ubc test streams 042_12,15,16,17,18 * various memory leak fixes Version 0.7 (2004 December 8) * properly initialize page buffers * refinement region handling * successfully decodes ubc test streams 042_21, 042_22 and 042_23 * generic region template 3 handling with arbitrary AT locations * successfully decodes ubc test streams 042_6 and 042_7 Version 0.6 (2003 December 31) * minor portability fix for cygwin Version 0.5 (2003 December 4) * compiler warning fixes * Properly handle the export specification for symbol dictionaries. * successfully decodes multipage documents from the Adobe encoder. Version 0.4 (released 2003 August 1) * redid license header to simplify relabelling for commercial distribution, borrowing from Ghostscript. Version 0.3 (released 2003 May 20) * win32 portability fixes related to ghostscript integration * generic mmr region support * successfully decodes ubc test stream 042_3 Version 0.2 (released 2003 April 17) * portability fixes * support for metadata extension segments (latin-1 only) * decodes single-page documents from the Adobe encoder * various other bugfixes Version 0.1 (released 2002 August 6) * decodes artithmetic and huffman-coded generic regions - some templates not working * decodes arithmetic symbol dictionaries * decodes artithmetic text regions * successfully decodes ubc test streams 042_1,2,4,5 and 10. * successfully decodes CVision embedded bitstream str-p39 * regression testing harness based on SHA-1 hashes of known files jbig2dec-0.13/COPYING000066400000000000000000001033301270170036400141410ustar00rootroot00000000000000 GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . jbig2dec-0.13/LICENSE000066400000000000000000000022221270170036400141110ustar00rootroot00000000000000 The files in this directory (folder) and any subdirectories (sub-folders) thereof are part of jbig2dec, with the exception of certain source files included to support portability which are marked otherwise in their copyright headers. jbig2dec is free software; you can redistribute it and/or modify it under the terms the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program in the file named COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. In addition, specific permission is given to link jbig2dec to or compile jbig2dec into AFPL Ghostscript and to distribute same under the Aladdin Free Public License (AFPL) version 9. jbig2dec-0.13/Makefile.am000066400000000000000000000031231270170036400151410ustar00rootroot00000000000000## process this file with automake to generate Makefile.in # require automake 1.7 AUTOMAKE_OPTIONS = foreign 1.7 dist-bzip2 dist-zip -Wall lib_LTLIBRARIES = libjbig2dec.la include_HEADERS = jbig2.h CFLAGS = @CFLAGS@ $(XCFLAGS) libjbig2dec_la_LDFLAGS = -version-info @JBIG2DEC_LT_CURRENT@:@JBIG2DEC_LT_REVISION@:@JBIG2DEC_LT_AGE@ -no-undefined libjbig2dec_la_SOURCES = jbig2.c \ jbig2_arith.c jbig2_arith_int.c jbig2_arith_iaid.c jbig2_huffman.c \ jbig2_segment.c jbig2_page.c \ jbig2_symbol_dict.c jbig2_text.c \ jbig2_generic.c jbig2_refinement.c jbig2_mmr.c \ jbig2_halftone.c \ jbig2_image.c jbig2_image_pbm.c \ os_types.h config_types.h config_win32.h \ jbig2.h jbig2_priv.h jbig2_image.h \ jbig2_arith.h jbig2_arith_iaid.h jbig2_arith_int.h \ jbig2_huffman.h jbig2_hufftab.h jbig2_mmr.h \ jbig2_generic.h jbig2_symbol_dict.h jbig2_text.h \ jbig2_metadata.c jbig2_metadata.h memento.c memento.h bin_PROGRAMS = jbig2dec noinst_PROGRAMS = test_sha1 test_huffman test_arith jbig2dec_SOURCES = jbig2dec.c sha1.c sha1.h \ jbig2.h jbig2_image.h getopt.h \ os_types.h config_types.h config_win32.h jbig2dec_LDADD = libjbig2dec.la @LIBOBJS@ $(PNG_LIBS) dist_man_MANS = jbig2dec.1 EXTRA_DIST = test_jbig2dec.py msvc.mak LICENSE CHANGES MAINTAINERCLEANFILES = config_types.h.in TESTS = test_sha1 test_jbig2dec.py test_huffman test_arith test_sha1_SOURCES = sha1.c sha1.h test_sha1_CFLAGS = -DTEST test_arith_SOURCES = jbig2_arith.c test_arith_CFLAGS = -DTEST test_arith_LDADD = libjbig2dec.la test_huffman_SOURCES = jbig2_huffman.c test_huffman_CFLAGS = -DTEST test_huffman_LDADD = libjbig2dec.la jbig2dec-0.13/Makefile.unix000066400000000000000000000023161270170036400155320ustar00rootroot00000000000000# Simple unix makefile default: all prefix ?= /usr/local CFLAGS := -Wall -g -O2 -DHAVE_STDINT_H LIB_SRCS := \ jbig2_arith.c jbig2_arith_int.c jbig2_arith_iaid.c \ jbig2_huffman.c jbig2_segment.c jbig2_page.c jbig2_symbol_dict.c \ jbig2_text.c jbig2_halftone.c jbig2_generic.c jbig2_refinement.c \ jbig2_mmr.c jbig2_image.c jbig2_metadata.c jbig2.c LIB_OBJS := $(LIB_SRCS:%.c=%.o) LIB_HDRS := \ jbig2.h jbig2_arith.h jbig2_arith_iaid.h jbig2_arith_int.h \ jbig2_generic.h jbig2_huffman.h jbig2_hufftab.h jbig2_image.h \ jbig2_metadata.h jbig2_mmr.h jbig2_priv.h jbig2_symbol_dict.h \ jbig2_text.h os_types.h APP_SRCS := jbig2_image_pbm.c jbig2_image_png.c jbig2dec.c sha1.c APP_OBJS := $(APP_SRCS:%.c=%.o) APP_HDRS := sha1.h $(LIB_OBJS): $(LIB_HDRS) $(APP_OBJS): $(LIB_HDRS) $(APP_HDRS) libjbig2dec.a: $(LIB_OBJS) ar cru $@ $^ jbig2dec: $(APP_OBJS) libjbig2dec.a $(CC) -o $@ $^ -lpng -lz all: jbig2dec libjbig2dec.a install: jbig2dec libjbig2dec.a install -d $(prefix)/bin $(prefix)/lib $(prefix)/include $(prefix)/man/man1 install jbig2dec $(prefix)/bin install jbig2dec.1 $(prefix)/man/man1 install jbig2.h $(prefix)/include install libjbig2dec.a $(prefix)/lib clean: rm -f *.o jbig2dec libjbig2dec.a jbig2dec-0.13/README000066400000000000000000000017151270170036400137720ustar00rootroot00000000000000jbig2dec is a decoder library and example utility implementing the JBIG2 bi-level image compression spec. Also known as ITU T.88 and ISO IEC 14492, and included by reference in Adobe's PDF version 1.4 and later. The basic invocation is: jbig2dec [-o ] file.jbig2 It also supports separate 'global' and 'page' streams, generally extracted from some embedded format: jbig2dec [-o ] The program is only partially functional at this time, but should be useful in some limited contexts. We welcome files that the decoder can't handle, or renders incorrectly. A set of example files is available from http://www.ece.ubc.ca/spmg/jbig2/bitstreams/main.html More information about this project and updated versions are available from http://jbig2dec.sf.net/ Development source code is kept in a subversion repository at svn.ghostscript.com. The contact address for the project is . jbig2dec-0.13/annex-h.jbig2000066400000000000000000000015341270170036400153660ustar00rootroot00000000000000JB2  &x/@0@8yyB1%  @pA',6, &qΧ- фaE|ÞE}B b/Db"5* w W $ 6UkZ@.RҊJ #$JTJ)*I@@10@8 O IJo @ % nZ@ '#6, + qkmI}Hhn@  > $ ˂f /dev/null 2>&1 || { echo echo "You must have autoconf installed to compile $package." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" exit 1 } VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/" VERSIONMKMAJ="sed -e s/\([0-9][0-9]*\)[^0-9].*/\\1/" VERSIONMKMIN="sed -e s/.*[0-9][0-9]*\.//" # do we need automake? if test "x$USE_OLD" = "xyes" ; then if test -r Makefile.am; then AM_OPTIONS=`fgrep AUTOMAKE_OPTIONS Makefile.am` AM_NEEDED=`echo $AM_OPTIONS | $VERSIONGREP` if test "x$AM_NEEDED" = "x$AM_OPTIONS"; then AM_NEEDED="" fi if test -z "$AM_NEEDED"; then echo -n "checking for automake... " AUTOMAKE=automake ACLOCAL=aclocal if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then echo "yes" else echo "no" AUTOMAKE= fi else echo -n "checking for automake $AM_NEEDED or later... " majneeded=`echo $AM_NEEDED | $VERSIONMKMAJ` minneeded=`echo $AM_NEEDED | $VERSIONMKMIN` for am in automake-$AM_NEEDED automake$AM_NEEDED automake \ automake-1.7 automake-1.8 automake-1.9 automake-1.10; do ($am --version < /dev/null > /dev/null 2>&1) || continue ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP` maj=`echo $ver | $VERSIONMKMAJ` min=`echo $ver | $VERSIONMKMIN` if test $maj -eq $majneeded -a $min -ge $minneeded; then AUTOMAKE=$am echo $AUTOMAKE break fi done test -z $AUTOMAKE && echo "no" echo -n "checking for aclocal $AM_NEEDED or later... " for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED aclocal\ aclocal-1.7 aclocal-1.8 aclocal-1.9 aclocal-1.10; do ($ac --version < /dev/null > /dev/null 2>&1) || continue ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP` maj=`echo $ver | $VERSIONMKMAJ` min=`echo $ver | $VERSIONMKMIN` if test $maj -eq $majneeded -a $min -ge $minneeded; then ACLOCAL=$ac echo $ACLOCAL break fi done test -z $ACLOCAL && echo "no" fi test -z $AUTOMAKE || test -z $ACLOCAL && { echo echo "You must have automake installed to compile $package." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" exit 1 } fi else AUTOMAKE=automake ACLOCAL=aclocal AM_VER=`$AUTOMAKE --version | grep "automake (GNU automake)" | sed 's/[^0-9\.]*//g'` AM_MAJ=`echo $AM_VER |cut -d. -f1` AM_MIN=`echo $AM_VER |cut -d. -f2` AM_PAT=`echo $AM_VER |cut -d. -f3` AM_NEEDED=`fgrep AUTOMAKE_OPTIONS Makefile.am | $VERSIONGREP` AM_MAJOR_REQ=`echo $AM_NEEDED |cut -d. -f1` AM_MINOR_REQ=`echo $AM_NEEDED |cut -d. -f2` echo "checking for automake $AM_NEEDED or later..." if [ $AM_MAJ -lt $AM_MAJOR_REQ -o $AM_MIN -lt $AM_MINOR_REQ ] ; then echo echo "You must have automake $AM_NEEDED or better installed to compile $package." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" exit 1 fi fi # do we need libtool? if ! test -z `grep -l -s -e PROG_LIBTOOL configure.ac configure.in`; then echo -n "Checking for libtoolize... " LIBTOOLIZE= for lt in glibtoolize libtoolize; do if ($lt --version < /dev/null > /dev/null 2>&1); then LIBTOOLIZE=$lt echo $lt break; fi done if test -z $LIBTOOLIZE; then echo echo "You must have GNU libtool installed to compile $package." echo "Download the appropriate package for your distribution," echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" exit 1 fi fi echo "Generating configuration files for $package, please wait...." echo " $ACLOCAL $ACLOCAL_FLAGS" $ACLOCAL $ACLOCAL_FLAGS echo " $LIBTOOLIZE" $LIBTOOLIZE --copy echo " autoheader" autoheader echo " creating config_types.h.in" cat >config_types.h.in < # else typedef unsigned @JBIG2_INT32_T@ uint32_t; typedef unsigned @JBIG2_INT16_T@ uint16_t; typedef unsigned @JBIG2_INT8_T@ uint8_t; typedef signed @JBIG2_INT32_T@ int32_t; typedef signed @JBIG2_INT16_T@ int16_t; typedef signed @JBIG2_INT8_T@ int8_t; # endif /* JBIG2_REPLACE_STDINT */ #endif /* HAVE_STDINT_H */ EOF echo " $AUTOMAKE --add-missing $AUTOMAKE_FLAGS" $AUTOMAKE --add-missing --copy $AUTOMAKE_FLAGS echo " autoconf" autoconf if test -z "$*"; then echo "I am going to run ./configure with no arguments - if you wish " echo "to pass any to it, please specify them on the $0 command line." else echo "running ./configure $@" fi $srcdir/configure "$@" && echo jbig2dec-0.13/config_win32.h000066400000000000000000000026131270170036400155500ustar00rootroot00000000000000/* Copyright (C) 2001-2016 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* configuration header file for compiling under Microsoft Windows */ /* update package version here */ #define PACKAGE "jbig2dec" #define VERSION "0.13" #if defined(_MSC_VER) || (defined(__BORLANDC__) && defined(__WIN32__)) /* Microsoft Visual C++ or Borland C++ */ typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; typedef __int64 int64_t; typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; /* no uint64_t */ # if defined(_MSC_VER) # if _MSC_VER < 1500 /* VS 2008 has vsnprintf */ # define vsnprintf _vsnprintf # endif # endif # if defined(_MSC_VER) && _MSC_VER>=1900 /* VS 2014 and later have (finally) snprintf */ # define STDC99 # else # define snprintf _snprintf # endif #endif /* _MSC_VER */ jbig2dec-0.13/configure.ac000066400000000000000000000110711270170036400153740ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. AC_INIT([jbig2dec], [0.13], [jbig2-dev@ghostscript.com]) AC_PREREQ(2.53) AC_CONFIG_SRCDIR([jbig2dec.c]) AM_INIT_AUTOMAKE([-Wall]) AM_CONFIG_HEADER(config.h) dnl Library versioning - Adapted from the libtool info page dnl dnl 1. If source has changed at all: increment revision dnl 2. If the ABI changed: increment current, reset revision to 0 dnl 3. If interfaces have been added since last public release: increment age dnl 4. If interfaces have been removed: reset age to 0 AC_SUBST([JBIG2DEC_LT_CURRENT], [0]) AC_SUBST([JBIG2DEC_LT_REVISION], [0]) AC_SUBST([JBIG2DEC_LT_AGE], [0]) # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O AC_LIBTOOL_WIN32_DLL AC_PROG_LIBTOOL # platform specific compiler flags if test "x$GCC" = xyes; then CFLAGS="$CFLAGS -Wall" fi # Checks for libraries. dnl by default we want png support if possible AC_ARG_WITH([libpng], AC_HELP_STRING([--with-libpng[=prefix]], [include support for png output (if libpng is available)]), [ac_cv_want_libpng="$withval"], [ac_cv_want_libpng="yes"]) save_cflags="$CFLAGS" save_ldflags="$LDFLAGS" have_libpng="no" if test "x$ac_cv_want_libpng" != "xno"; then if test "x$ac_cv_want_libpng" != "xyes"; then dnl if it's not yes or no, treat as a prefix CFLAGS="$CFLAGS -I$ac_cv_want_libpng/include" LDFLAGS="$LDFLAGS -L$ac_cv_want_libpng/lib" fi dnl libpng requires pow() which may be in libm AC_SEARCH_LIBS([pow], [m]) AC_CHECK_LIB([png], [png_create_write_struct], [ AC_CHECK_LIB([z], [deflate], [ AC_DEFINE(HAVE_LIBPNG, 1, [Define if libpng is available (-lpng)]) PNG_LIBS="-lpng -lz" AC_LIBOBJ([jbig2_image_png]) have_libpng="yes" ]) ]) fi dnl restore (possibly changed) flags if we didn't find working libpng if test "x$have_libpng" != "xyes"; then CFLAGS="$save_cflags" LDFLAGS="$save_ldflags" fi AC_SUBST(PNG_LIBS) # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([libintl.h stddef.h unistd.h strings.h]) dnl We assume the fixed-size types from stdint.h. If that header is dnl not available, look for the same types in a few other headers. dnl We also attempt to define them ourselves, but only use those if dnl the native versions aren't available. The substitutions happen dnl in a file config_types.h, whose template is created by autogen.sh stdint_types_in="no_replacement_found" stdint_types_discovered="yes" AC_CHECK_SIZEOF(char) AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(int) AC_CHECK_SIZEOF(long) case 1 in $ac_cv_sizeof_char) int8_type="char";; *) stdint_types_discovered="no" esac case 2 in $ac_cv_sizeof_short) int16_type="short";; $ac_cv_sizeof_char) int16_type="char";; $ac_cv_sizeof_int) int16_type="char";; *) stdint_types_discovered="no";; esac case 4 in $ac_cv_sizeof_int) int32_type="int";; $ac_cv_sizeof_long) int32_type="long";; $ac_cv_sizeof_short) int32_type="short";; *) stdint_types_discovered="no";; esac AC_CHECK_HEADER([stdint.h]) if test "x$ac_cv_header_stdint_h" != "xyes"; then for include in sys/types.h inttypes.h sys/inttypes.h sys/int_types.h ; do AC_MSG_CHECKING([for uint32_t in $include]) AC_TRY_COMPILE([#include <$include>], [uint32_t canary;], [ AC_MSG_RESULT([yes]) stdint_types_in="$include" break; ], AC_MSG_RESULT([no]) ) done if test "x$stdint_types_in" != "xno_replacement_found"; then AC_MSG_RESULT([Adding $stdint_types_in to config header for stdint types]) AC_DEFINE([JBIG2_REPLACE_STDINT_H],, [set by configure if an alternate header with the stdint.h types is found]) elif test "x$stdint_types_discovered" = "xno"; then AC_MSG_ERROR([ Unable to find suitable definitions of the stdint.h types (uint32_t and friends) You will have to define these yourself in a separate header. See config_win32.h for an example. ]) fi fi AC_SUBST(JBIG2_INT32_T, [$int32_type]) AC_SUBST(JBIG2_INT16_T, [$int16_type]) AC_SUBST(JBIG2_INT8_T, [$int8_type]) AC_SUBST(JBIG2_STDINT_H, [$stdint_types_in]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T AC_C_BIGENDIAN # Checks for library functions. AC_FUNC_MEMCMP dnl we use realloc() but don't depend on the zero-length behavior dnl tested by AC_FUNC_REALLOC AC_REPLACE_FUNCS([snprintf]) AC_CHECK_FUNCS([memset strdup]) dnl use our included getopt if the system doesn't have getopt_long() AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPT_LONG,, [Define if the local libc includes getopt_long()] ),[ AC_LIBOBJ([getopt]) AC_LIBOBJ([getopt1]) ]) # generate output AC_CONFIG_FILES([Makefile config_types.h]) AC_OUTPUT jbig2dec-0.13/getopt.c000066400000000000000000001017031270170036400145560ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if defined HAVE_LIBINTL_H || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv(); #endif static char * my_index(str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *)str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen(const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange(char **); #endif static void exchange(argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc(top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset(__mempcpy(new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS(bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS(bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize(int, char *const *, const char *); #endif static const char * _getopt_initialize(argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen(orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *)malloc(nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset(__mempcpy(__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal(argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize(argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange((char **)argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp(argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange((char **)argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index(optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp(p->name, nextchar, nameend - nextchar)) { if ((unsigned int)(nameend - nextchar) == (unsigned int)strlen(p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf(stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen(nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { if (argv[optind - 1][1] == '-') /* --option */ fprintf(stderr, _("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); else /* +option or -option */ fprintf(stderr, _("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen(nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen(nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen(nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index(optstring, *nextchar) == NULL) { if (print_errors) { if (argv[optind][1] == '-') /* --option */ fprintf(stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf(stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *)""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index(optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf(stderr, _("%s: illegal option -- %c\n"), argv[0], c); else fprintf(stderr, _("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp(p->name, nextchar, nameend - nextchar)) { if ((unsigned int)(nameend - nextchar) == strlen(p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) fprintf(stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen(nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) fprintf(stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); nextchar += strlen(nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) fprintf(stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen(nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen(nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ fprintf(stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt(argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal(argc, argv, optstring, (const struct option *)0, (int *)0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main(argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt(argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf("option %c\n", c); break; case 'a': printf("option a\n"); break; case 'b': printf("option b\n"); break; case 'c': printf("option c with value `%s'\n", optarg); break; case '?': break; default: printf("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } exit(0); } #endif /* TEST */ jbig2dec-0.13/getopt.h000066400000000000000000000146111270170036400145640ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt(int __argc, char *const *__argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt(); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long(int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only(int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal(int __argc, char *const *__argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt(); # ifndef __need_getopt extern int getopt_long(); extern int getopt_long_only(); extern int _getopt_internal(); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ jbig2dec-0.13/getopt1.c000066400000000000000000000113721270170036400146410ustar00rootroot00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "getopt.h" #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long(argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal(argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only(argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal(argc, argv, options, long_options, opt_index, 1); } #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main(argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf("option %c\n", c); break; case 'a': printf("option a\n"); break; case 'b': printf("option b\n"); break; case 'c': printf("option c with value `%s'\n", optarg); break; case 'd': printf("option d with value `%s'\n", optarg); break; case '?': break; default: printf("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } exit(0); } #endif /* TEST */ jbig2dec-0.13/jbig2.c000066400000000000000000000334071270170036400142560ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include #include #include "jbig2.h" #include "jbig2_priv.h" static void * jbig2_default_alloc(Jbig2Allocator *allocator, size_t size) { return malloc(size); } static void jbig2_default_free(Jbig2Allocator *allocator, void *p) { free(p); } static void * jbig2_default_realloc(Jbig2Allocator *allocator, void *p, size_t size) { return realloc(p, size); } static Jbig2Allocator jbig2_default_allocator = { jbig2_default_alloc, jbig2_default_free, jbig2_default_realloc }; void * jbig2_alloc(Jbig2Allocator *allocator, size_t size, size_t num) { /* check for integer multiplication overflow */ if (num > 0 && size >= (size_t) - 0x100 / num) return NULL; return allocator->alloc(allocator, size * num); } /* jbig2_free and jbig2_realloc moved to the bottom of this file */ static int jbig2_default_error(void *data, const char *msg, Jbig2Severity severity, int32_t seg_idx) { /* report only fatal errors by default */ if (severity == JBIG2_SEVERITY_FATAL) { fprintf(stderr, "jbig2 decoder FATAL ERROR: %s", msg); if (seg_idx != -1) fprintf(stderr, " (segment 0x%02x)", seg_idx); fprintf(stderr, "\n"); fflush(stderr); } return 0; } int jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t segment_number, const char *fmt, ...) { char buf[1024]; va_list ap; int n; int code; va_start(ap, fmt); n = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (n < 0 || n == sizeof(buf)) strncpy(buf, "jbig2_error: error in generating error string", sizeof(buf)); code = ctx->error_callback(ctx->error_callback_data, buf, severity, segment_number); if (severity == JBIG2_SEVERITY_FATAL) code = -1; return code; } Jbig2Ctx * jbig2_ctx_new(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCtx *global_ctx, Jbig2ErrorCallback error_callback, void *error_callback_data) { Jbig2Ctx *result; if (allocator == NULL) allocator = &jbig2_default_allocator; if (error_callback == NULL) error_callback = &jbig2_default_error; result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1); if (result == NULL) { error_callback(error_callback_data, "initial context allocation failed!", JBIG2_SEVERITY_FATAL, -1); return result; } result->allocator = allocator; result->options = options; result->global_ctx = (const Jbig2Ctx *)global_ctx; result->error_callback = error_callback; result->error_callback_data = error_callback_data; result->state = (options & JBIG2_OPTIONS_EMBEDDED) ? JBIG2_FILE_SEQUENTIAL_HEADER : JBIG2_FILE_HEADER; result->buf = NULL; result->n_segments = 0; result->n_segments_max = 16; result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max); if (result->segments == NULL) { error_callback(error_callback_data, "initial segments allocation failed!", JBIG2_SEVERITY_FATAL, -1); jbig2_free(allocator, result); return result; } result->segment_index = 0; result->current_page = 0; result->max_page_index = 4; result->pages = jbig2_new(result, Jbig2Page, result->max_page_index); if (result->pages == NULL) { error_callback(error_callback_data, "initial pages allocation failed!", JBIG2_SEVERITY_FATAL, -1); jbig2_free(allocator, result->segments); jbig2_free(allocator, result); return result; } { int index; for (index = 0; index < result->max_page_index; index++) { result->pages[index].state = JBIG2_PAGE_FREE; result->pages[index].number = 0; result->pages[index].image = NULL; } } return result; } #define get_uint16(bptr)\ (((bptr)[0] << 8) | (bptr)[1]) #define get_int16(bptr)\ (((int)get_uint16(bptr) ^ 0x8000) - 0x8000) int16_t jbig2_get_int16(const byte *bptr) { return get_int16(bptr); } uint16_t jbig2_get_uint16(const byte *bptr) { return get_uint16(bptr); } int32_t jbig2_get_int32(const byte *bptr) { return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2); } uint32_t jbig2_get_uint32(const byte *bptr) { return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2); } /** * jbig2_data_in: submit data for decoding * @ctx: The jbig2dec decoder context * @data: a pointer to the data buffer * @size: the size of the data buffer in bytes * * Copies the specified data into internal storage and attempts * to (continue to) parse it as part of a jbig2 data stream. * * Return code: 0 on success * -1 if there is a parsing error, or whatever * the error handling callback returns **/ int jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size) { const size_t initial_buf_size = 1024; if (ctx->buf == NULL) { size_t buf_size = initial_buf_size; do buf_size <<= 1; while (buf_size < size); ctx->buf = jbig2_new(ctx, byte, buf_size); if (ctx->buf == NULL) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate ctx->buf in jbig2_data_in"); } ctx->buf_size = buf_size; ctx->buf_rd_ix = 0; ctx->buf_wr_ix = 0; } else if (ctx->buf_wr_ix + size > ctx->buf_size) { if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) && ctx->buf_wr_ix - ctx->buf_rd_ix + size <= ctx->buf_size) { memmove(ctx->buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix); } else { byte *buf; size_t buf_size = initial_buf_size; do buf_size <<= 1; while (buf_size < ctx->buf_wr_ix - ctx->buf_rd_ix + size); buf = jbig2_new(ctx, byte, buf_size); if (buf == NULL) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate buf in jbig2_data_in"); } memcpy(buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix); jbig2_free(ctx->allocator, ctx->buf); ctx->buf = buf; ctx->buf_size = buf_size; } ctx->buf_wr_ix -= ctx->buf_rd_ix; ctx->buf_rd_ix = 0; } memcpy(ctx->buf + ctx->buf_wr_ix, data, size); ctx->buf_wr_ix += size; /* data has now been added to buffer */ for (;;) { const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a }; Jbig2Segment *segment; size_t header_size; int code; switch (ctx->state) { case JBIG2_FILE_HEADER: /* D.4.1 */ if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9) return 0; if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8)) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "Not a JBIG2 file header"); /* D.4.2 */ ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8]; if (ctx->file_header_flags & 0xFC) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "reserved bits (2-7) of file header flags are not zero (0x%02x)", ctx->file_header_flags); } /* D.4.3 */ if (!(ctx->file_header_flags & 2)) { /* number of pages is known */ if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13) return 0; ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9); ctx->buf_rd_ix += 13; if (ctx->n_pages == 1) jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a single page document"); else jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a %d page document", ctx->n_pages); } else { /* number of pages not known */ ctx->n_pages = 0; ctx->buf_rd_ix += 9; } /* determine the file organization based on the flags - D.4.2 again */ if (ctx->file_header_flags & 1) { ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates sequential organization"); } else { ctx->state = JBIG2_FILE_RANDOM_HEADERS; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates random-access organization"); } break; case JBIG2_FILE_SEQUENTIAL_HEADER: case JBIG2_FILE_RANDOM_HEADERS: segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size); if (segment == NULL) return 0; /* need more data */ ctx->buf_rd_ix += header_size; if (ctx->n_segments == ctx->n_segments_max) ctx->segments = jbig2_renew(ctx, ctx->segments, Jbig2Segment *, (ctx->n_segments_max <<= 2)); ctx->segments[ctx->n_segments++] = segment; if (ctx->state == JBIG2_FILE_RANDOM_HEADERS) { if ((segment->flags & 63) == 51) /* end of file */ ctx->state = JBIG2_FILE_RANDOM_BODIES; } else /* JBIG2_FILE_SEQUENTIAL_HEADER */ ctx->state = JBIG2_FILE_SEQUENTIAL_BODY; break; case JBIG2_FILE_SEQUENTIAL_BODY: case JBIG2_FILE_RANDOM_BODIES: segment = ctx->segments[ctx->segment_index]; if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix) return 0; /* need more data */ code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix); ctx->buf_rd_ix += segment->data_length; ctx->segment_index++; if (ctx->state == JBIG2_FILE_RANDOM_BODIES) { if (ctx->segment_index == ctx->n_segments) ctx->state = JBIG2_FILE_EOF; } else { /* JBIG2_FILE_SEQUENCIAL_BODY */ ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER; } if (code < 0) { ctx->state = JBIG2_FILE_EOF; return code; } break; case JBIG2_FILE_EOF: if (ctx->buf_rd_ix == ctx->buf_wr_ix) return 0; return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "Garbage beyond end of file"); } } } void jbig2_ctx_free(Jbig2Ctx *ctx) { Jbig2Allocator *ca = ctx->allocator; int i; jbig2_free(ca, ctx->buf); if (ctx->segments != NULL) { for (i = 0; i < ctx->n_segments; i++) jbig2_free_segment(ctx, ctx->segments[i]); jbig2_free(ca, ctx->segments); } if (ctx->pages != NULL) { for (i = 0; i <= ctx->current_page; i++) if (ctx->pages[i].image != NULL) jbig2_image_release(ctx, ctx->pages[i].image); jbig2_free(ca, ctx->pages); } jbig2_free(ca, ctx); } Jbig2GlobalCtx * jbig2_make_global_ctx(Jbig2Ctx *ctx) { return (Jbig2GlobalCtx *) ctx; } void jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx) { jbig2_ctx_free((Jbig2Ctx *) global_ctx); } /* I'm not committed to keeping the word stream interface. It's handy when you think you may be streaming your input, but if you're not (as is currently the case), it just adds complexity. */ typedef struct { Jbig2WordStream super; const byte *data; size_t size; } Jbig2WordStreamBuf; static int jbig2_word_stream_buf_get_next_word(Jbig2WordStream *self, int offset, uint32_t *word) { Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *) self; const byte *data = z->data; uint32_t result; if (offset + 4 < z->size) result = (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]; else if (offset >= z->size) return -1; else { int i; result = 0; for (i = 0; i < z->size - offset; i++) result |= data[offset + i] << ((3 - i) << 3); } *word = result; return 0; } Jbig2WordStream * jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size) { Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1); if (result == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate Jbig2WordStreamBuf in jbig2_word_stream_buf_new"); return NULL; } result->super.get_next_word = jbig2_word_stream_buf_get_next_word; result->data = data; result->size = size; return &result->super; } void jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws) { jbig2_free(ctx->allocator, ws); } /* When Memento is in use, the ->free and ->realloc calls get * turned into ->Memento_free and ->Memento_realloc, which is * obviously problematic. Undefine free and realloc here to * avoid this. */ #ifdef MEMENTO #undef free #undef realloc #endif void jbig2_free(Jbig2Allocator *allocator, void *p) { allocator->free(allocator, p); } void * jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num) { /* check for integer multiplication overflow */ if (num > 0 && size >= (size_t) - 0x100 / num) return NULL; return allocator->realloc(allocator, p, size * num); } jbig2dec-0.13/jbig2.h000066400000000000000000000104261270170036400142570ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef __cplusplus extern "C" { #endif #ifndef _JBIG2_H #define _JBIG2_H /* warning levels */ typedef enum { JBIG2_SEVERITY_DEBUG, JBIG2_SEVERITY_INFO, JBIG2_SEVERITY_WARNING, JBIG2_SEVERITY_FATAL } Jbig2Severity; typedef enum { JBIG2_OPTIONS_EMBEDDED = 1 } Jbig2Options; /* forward public structure declarations */ typedef struct _Jbig2Allocator Jbig2Allocator; typedef struct _Jbig2Ctx Jbig2Ctx; typedef struct _Jbig2GlobalCtx Jbig2GlobalCtx; typedef struct _Jbig2Segment Jbig2Segment; typedef struct _Jbig2Image Jbig2Image; /* private structures */ typedef struct _Jbig2Page Jbig2Page; typedef struct _Jbig2SymbolDictionary Jbig2SymbolDictionary; /* this is the general image structure used by the jbig2dec library images are 1 bpp, packed into rows a byte at a time. stride gives the byte offset to the next row, while width and height define the size of the image area in pixels. */ struct _Jbig2Image { int width, height, stride; uint8_t *data; int refcount; }; Jbig2Image *jbig2_image_new(Jbig2Ctx *ctx, int width, int height); Jbig2Image *jbig2_image_clone(Jbig2Ctx *ctx, Jbig2Image *image); void jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image); void jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image); void jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value); Jbig2Image *jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, int width, int height); /* errors are returned from the library via a callback. If no callback is provided (a NULL argument is passed ot jbig2_ctx_new) a default handler is used which prints fatal errors to the stderr stream. */ /* error callback */ typedef int (*Jbig2ErrorCallback)(void *data, const char *msg, Jbig2Severity severity, int32_t seg_idx); /* memory allocation is likewise done via a set of callbacks so that clients can better control memory usage. If a NULL is passed for this argumennt of jbig2_ctx_new, a default allocator based on malloc() is used. */ /* dynamic memory callbacks */ struct _Jbig2Allocator { void *(*alloc)(Jbig2Allocator *allocator, size_t size); void (*free)(Jbig2Allocator *allocator, void *p); void *(*realloc)(Jbig2Allocator *allocator, void *p, size_t size); }; /* decoder context */ Jbig2Ctx *jbig2_ctx_new(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCtx *global_ctx, Jbig2ErrorCallback error_callback, void *error_callback_data); void jbig2_ctx_free(Jbig2Ctx *ctx); /* global context for embedded streams */ Jbig2GlobalCtx *jbig2_make_global_ctx(Jbig2Ctx *ctx); void jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx); /* submit data to the decoder */ int jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size); /* get the next available decoded page image. NULL means there isn't one. */ Jbig2Image *jbig2_page_out(Jbig2Ctx *ctx); /* mark a returned page image as no longer needed. */ int jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image); /* mark the current page as complete, simulating an end-of-page segment (for broken streams) */ int jbig2_complete_page(Jbig2Ctx *ctx); /* segment header routines */ struct _Jbig2Segment { uint32_t number; uint8_t flags; uint32_t page_association; size_t data_length; int referred_to_segment_count; uint32_t *referred_to_segments; void *result; }; Jbig2Segment *jbig2_parse_segment_header(Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, size_t *p_header_size); int jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); void jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment); Jbig2Segment *jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number); #endif /* _JBIG2_H */ #ifdef __cplusplus } #endif jbig2dec-0.13/jbig2_arith.c000066400000000000000000000242651270170036400154470ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" struct _Jbig2ArithState { uint32_t C; int A; int CT; uint32_t next_word; int next_word_bytes; Jbig2WordStream *ws; int offset; Jbig2Ctx *ctx; }; #undef SOFTWARE_CONVENTION /* A note on the "software conventions". Previously, I had misinterpreted the spec, and had thought that the spec's description of the "software convention" was wrong. Now I believe that this code is both correct and matches the spec, with SOFTWARE_CONVENTION defined or not. Thanks to William Rucklidge for the clarification. In any case, my benchmarking indicates no speed difference at all. Therefore, for now we will just use the normative version. */ static int jbig2_arith_bytein(Jbig2ArithState *as) { byte B; /* invariant: as->next_word_bytes > 0 */ /* Figure G.3 */ B = (byte)((as->next_word >> 24) & 0xFF); if (B == 0xFF) { byte B1; if (as->next_word_bytes == 1) { Jbig2WordStream *ws = as->ws; if (ws->get_next_word(ws, as->offset, &as->next_word)) { jbig2_error(as->ctx, JBIG2_SEVERITY_FATAL, -1, "end of jbig2 buffer reached at offset %d", as->offset); return -1; } as->offset += 4; B1 = (byte)((as->next_word >> 24) & 0xFF); if (B1 > 0x8F) { #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (aa)\n", B); #endif #ifndef SOFTWARE_CONVENTION as->C += 0xFF00; #endif as->CT = 8; as->next_word = (0xFF00 | B1) << 16; as->next_word_bytes = 2; } else { #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (a)\n", B); #endif #ifdef SOFTWARE_CONVENTION as->C += 0xFE00 - (B1 << 9); #else as->C += B1 << 9; #endif as->CT = 7; as->next_word_bytes = 4; } } else { B1 = (byte)((as->next_word >> 16) & 0xFF); if (B1 > 0x8F) { #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (ba)\n", B); #endif #ifndef SOFTWARE_CONVENTION as->C += 0xFF00; #endif as->CT = 8; } else { as->next_word_bytes--; as->next_word <<= 8; #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x (b)\n", B); #endif #ifdef SOFTWARE_CONVENTION as->C += 0xFE00 - (B1 << 9); #else as->C += (B1 << 9); #endif as->CT = 7; } } } else { #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "read %02x\n", B); #endif as->CT = 8; as->next_word <<= 8; as->next_word_bytes--; if (as->next_word_bytes == 0) { Jbig2WordStream *ws = as->ws; if (ws->get_next_word(ws, as->offset, &as->next_word)) { jbig2_error(as->ctx, JBIG2_SEVERITY_FATAL, -1, "end of jbig2 buffer reached at offset %d", as->offset); return -1; } as->offset += 4; as->next_word_bytes = 4; } B = (byte)((as->next_word >> 24) & 0xFF); #ifdef SOFTWARE_CONVENTION as->C += 0xFF00 - (B << 8); #else as->C += (B << 8); #endif } return 0; } #if defined(JBIG2_DEBUG) || defined(JBIG2_DEBUG_ARITH) static void jbig2_arith_trace(Jbig2ArithState *as, Jbig2ArithCx cx) { fprintf(stderr, "I = %2d, MPS = %d, A = %04x, CT = %2d, C = %08x\n", cx & 0x7f, cx >> 7, as->A, as->CT, as->C); } #endif /** Allocate and initialize a new arithmetic coding state * the returned pointer can simply be freed; this does * not affect the associated Jbig2WordStream. */ Jbig2ArithState * jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws) { Jbig2ArithState *result; result = jbig2_new(ctx, Jbig2ArithState, 1); if (result == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate Jbig2ArithState in jbig2_arith_new"); return result; } result->ws = ws; result->ctx = ctx; if (ws->get_next_word(ws, 0, &result->next_word)) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to get first word in jbig2_arith_new"); jbig2_free(ctx->allocator, result); return NULL; } result->next_word_bytes = 4; result->offset = 4; /* Figure E.20 */ #ifdef SOFTWARE_CONVENTION result->C = (~(result->next_word >> 8)) & 0xFF0000; #else result->C = (result->next_word >> 8) & 0xFF0000; #endif if (jbig2_arith_bytein(result)) { jbig2_free(ctx->allocator, result); return NULL; } result->C <<= 7; result->CT -= 7; result->A = 0x8000; return result; } #define MAX_QE_ARRAY_SIZE 47 /* could put bit fields in to minimize memory usage */ typedef struct { unsigned short Qe; byte mps_xor; /* mps_xor = index ^ NMPS */ byte lps_xor; /* lps_xor = index ^ NLPS ^ (SWITCH << 7) */ } Jbig2ArithQe; const Jbig2ArithQe jbig2_arith_Qe[MAX_QE_ARRAY_SIZE] = { {0x5601, 1 ^ 0, 1 ^ 0 ^ 0x80}, {0x3401, 2 ^ 1, 6 ^ 1}, {0x1801, 3 ^ 2, 9 ^ 2}, {0x0AC1, 4 ^ 3, 12 ^ 3}, {0x0521, 5 ^ 4, 29 ^ 4}, {0x0221, 38 ^ 5, 33 ^ 5}, {0x5601, 7 ^ 6, 6 ^ 6 ^ 0x80}, {0x5401, 8 ^ 7, 14 ^ 7}, {0x4801, 9 ^ 8, 14 ^ 8}, {0x3801, 10 ^ 9, 14 ^ 9}, {0x3001, 11 ^ 10, 17 ^ 10}, {0x2401, 12 ^ 11, 18 ^ 11}, {0x1C01, 13 ^ 12, 20 ^ 12}, {0x1601, 29 ^ 13, 21 ^ 13}, {0x5601, 15 ^ 14, 14 ^ 14 ^ 0x80}, {0x5401, 16 ^ 15, 14 ^ 15}, {0x5101, 17 ^ 16, 15 ^ 16}, {0x4801, 18 ^ 17, 16 ^ 17}, {0x3801, 19 ^ 18, 17 ^ 18}, {0x3401, 20 ^ 19, 18 ^ 19}, {0x3001, 21 ^ 20, 19 ^ 20}, {0x2801, 22 ^ 21, 19 ^ 21}, {0x2401, 23 ^ 22, 20 ^ 22}, {0x2201, 24 ^ 23, 21 ^ 23}, {0x1C01, 25 ^ 24, 22 ^ 24}, {0x1801, 26 ^ 25, 23 ^ 25}, {0x1601, 27 ^ 26, 24 ^ 26}, {0x1401, 28 ^ 27, 25 ^ 27}, {0x1201, 29 ^ 28, 26 ^ 28}, {0x1101, 30 ^ 29, 27 ^ 29}, {0x0AC1, 31 ^ 30, 28 ^ 30}, {0x09C1, 32 ^ 31, 29 ^ 31}, {0x08A1, 33 ^ 32, 30 ^ 32}, {0x0521, 34 ^ 33, 31 ^ 33}, {0x0441, 35 ^ 34, 32 ^ 34}, {0x02A1, 36 ^ 35, 33 ^ 35}, {0x0221, 37 ^ 36, 34 ^ 36}, {0x0141, 38 ^ 37, 35 ^ 37}, {0x0111, 39 ^ 38, 36 ^ 38}, {0x0085, 40 ^ 39, 37 ^ 39}, {0x0049, 41 ^ 40, 38 ^ 40}, {0x0025, 42 ^ 41, 39 ^ 41}, {0x0015, 43 ^ 42, 40 ^ 42}, {0x0009, 44 ^ 43, 41 ^ 43}, {0x0005, 45 ^ 44, 42 ^ 44}, {0x0001, 45 ^ 45, 43 ^ 45}, {0x5601, 46 ^ 46, 46 ^ 46} }; static int jbig2_arith_renormd(Jbig2ArithState *as) { /* Figure E.18 */ do { if ((as->CT == 0) && (jbig2_arith_bytein(as) < 0)) return -1; as->A <<= 1; as->C <<= 1; as->CT--; } while ((as->A & 0x8000) == 0); return 0; } bool jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx) { Jbig2ArithCx cx = *pcx; const Jbig2ArithQe *pqe; unsigned int index = cx & 0x7f; bool D; if (index >= MAX_QE_ARRAY_SIZE) { return -1; } else { pqe = &jbig2_arith_Qe[index]; } /* Figure E.15 */ as->A -= pqe->Qe; if ( #ifdef SOFTWARE_CONVENTION /* Note: I do not think this is correct. See above. */ (as->C >> 16) < as->A #else !((as->C >> 16) < pqe->Qe) #endif ) { #ifndef SOFTWARE_CONVENTION as->C -= pqe->Qe << 16; #endif if ((as->A & 0x8000) == 0) { /* MPS_EXCHANGE, Figure E.16 */ if (as->A < pqe->Qe) { D = 1 - (cx >> 7); *pcx ^= pqe->lps_xor; } else { D = cx >> 7; *pcx ^= pqe->mps_xor; } if (jbig2_arith_renormd(as)) return -1; return D; } else return cx >> 7; } else { #ifdef SOFTWARE_CONVENTION as->C -= (as->A) << 16; #endif /* LPS_EXCHANGE, Figure E.17 */ if (as->A < pqe->Qe) { as->A = pqe->Qe; D = cx >> 7; *pcx ^= pqe->mps_xor; } else { as->A = pqe->Qe; D = 1 - (cx >> 7); *pcx ^= pqe->lps_xor; } if (jbig2_arith_renormd(as)) return -1; return D; } } bool jbig2_arith_has_reached_marker(Jbig2ArithState *as) { return as->next_word_bytes == 2 && (as->next_word >> 16) > 0xFF8F; } #ifdef TEST static int test_get_word(Jbig2WordStream *self, int offset, uint32_t *word) { byte stream[] = { 0x84, 0xC7, 0x3B, 0xFC, 0xE1, 0xA1, 0x43, 0x04, 0x02, 0x20, 0x00, 0x00, 0x41, 0x0D, 0xBB, 0x86, 0xF4, 0x31, 0x7F, 0xFF, 0x88, 0xFF, 0x37, 0x47, 0x1A, 0xDB, 0x6A, 0xDF, 0xFF, 0xAC, 0x00, 0x00 }; if (offset >= sizeof(stream)) return -1; *word = (stream[offset] << 24) | (stream[offset + 1] << 16) | (stream[offset + 2] << 8) | stream[offset + 3]; return 0; } int main(int argc, char **argv) { Jbig2Ctx *ctx; Jbig2WordStream ws; Jbig2ArithState *as; int i; Jbig2ArithCx cx = 0; ctx = jbig2_ctx_new(NULL, 0, NULL, NULL, NULL); ws.get_next_word = test_get_word; as = jbig2_arith_new(ctx, &ws); #ifdef JBIG2_DEBUG_ARITH jbig2_arith_trace(as, cx); #endif for (i = 0; i < 256; i++) { #ifdef JBIG2_DEBUG_ARITH bool D = #else (void) #endif jbig2_arith_decode(as, &cx); #ifdef JBIG2_DEBUG_ARITH fprintf(stderr, "%3d: D = %d, ", i, D); jbig2_arith_trace(as, cx); #endif } jbig2_free(ctx->allocator, as); jbig2_ctx_free(ctx); return 0; } #endif jbig2dec-0.13/jbig2_arith.h000066400000000000000000000023271270170036400154470ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ typedef struct _Jbig2ArithState Jbig2ArithState; /* An arithmetic coding context is stored as a single byte, with the index in the low order 7 bits (actually only 6 are used), and the MPS in the top bit. */ typedef unsigned char Jbig2ArithCx; /* allocate and initialize a new arithmetic coding state */ Jbig2ArithState *jbig2_arith_new(Jbig2Ctx *ctx, Jbig2WordStream *ws); /* decode a bit */ bool jbig2_arith_decode(Jbig2ArithState *as, Jbig2ArithCx *pcx); /* returns true if the end of the data stream has been reached (for sanity checks) */ bool jbig2_arith_has_reached_marker(Jbig2ArithState *as); jbig2dec-0.13/jbig2_arith_iaid.c000066400000000000000000000050631270170036400164300ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* Annex A.3 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include /* memset() */ #ifdef VERBOSE #include /* for debug printing only */ #endif #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_arith_iaid.h" struct _Jbig2ArithIaidCtx { int SBSYMCODELEN; Jbig2ArithCx *IAIDx; }; Jbig2ArithIaidCtx * jbig2_arith_iaid_ctx_new(Jbig2Ctx *ctx, int SBSYMCODELEN) { Jbig2ArithIaidCtx *result = jbig2_new(ctx, Jbig2ArithIaidCtx, 1); int ctx_size = 1 << SBSYMCODELEN; if (result == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate storage in jbig2_arith_iaid_ctx_new"); return result; } result->SBSYMCODELEN = SBSYMCODELEN; result->IAIDx = jbig2_new(ctx, Jbig2ArithCx, ctx_size); if (result->IAIDx != NULL) { memset(result->IAIDx, 0, ctx_size); } else { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate symbol ID storage in jbig2_arith_iaid_ctx_new"); } return result; } /* A.3 */ /* Return value: -1 on error, 0 on normal value */ int jbig2_arith_iaid_decode(Jbig2ArithIaidCtx *ctx, Jbig2ArithState *as, int32_t *p_result) { Jbig2ArithCx *IAIDx = ctx->IAIDx; int SBSYMCODELEN = ctx->SBSYMCODELEN; int PREV = 1; int D; int i; /* A.3 (2) */ for (i = 0; i < SBSYMCODELEN; i++) { D = jbig2_arith_decode(as, &IAIDx[PREV]); if (D < 0) return -1; #ifdef VERBOSE fprintf(stderr, "IAID%x: D = %d\n", PREV, D); #endif PREV = (PREV << 1) | D; } /* A.3 (3) */ PREV -= 1 << SBSYMCODELEN; #ifdef VERBOSE fprintf(stderr, "IAID result: %d\n", PREV); #endif *p_result = PREV; return 0; } void jbig2_arith_iaid_ctx_free(Jbig2Ctx *ctx, Jbig2ArithIaidCtx *iax) { if (iax != NULL) { jbig2_free(ctx->allocator, iax->IAIDx); jbig2_free(ctx->allocator, iax); } } jbig2dec-0.13/jbig2_arith_iaid.h000066400000000000000000000016101270170036400164270ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ typedef struct _Jbig2ArithIaidCtx Jbig2ArithIaidCtx; Jbig2ArithIaidCtx *jbig2_arith_iaid_ctx_new(Jbig2Ctx *ctx, int SBSYMCODELEN); int jbig2_arith_iaid_decode(Jbig2ArithIaidCtx *ctx, Jbig2ArithState *as, int32_t *p_result); void jbig2_arith_iaid_ctx_free(Jbig2Ctx *ctx, Jbig2ArithIaidCtx *iax); jbig2dec-0.13/jbig2_arith_int.c000066400000000000000000000066351270170036400163220ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* Annex A */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include /* memset() */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_arith_int.h" struct _Jbig2ArithIntCtx { Jbig2ArithCx IAx[512]; }; Jbig2ArithIntCtx * jbig2_arith_int_ctx_new(Jbig2Ctx *ctx) { Jbig2ArithIntCtx *result = jbig2_new(ctx, Jbig2ArithIntCtx, 1); if (result == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate Jbig2ArithIntCtx in jbig2_arith_int_ctx_new"); } else { memset(result->IAx, 0, sizeof(result->IAx)); } return result; } /* A.2 */ /* Return value: -1 on error, 0 on normal value, 1 on OOB return. */ int jbig2_arith_int_decode(Jbig2ArithIntCtx *ctx, Jbig2ArithState *as, int32_t *p_result) { Jbig2ArithCx *IAx = ctx->IAx; int PREV = 1; int S, V; int bit; int n_tail, offset; int i; S = jbig2_arith_decode(as, &IAx[PREV]); if (S < 0) return -1; PREV = (PREV << 1) | S; bit = jbig2_arith_decode(as, &IAx[PREV]); if (bit < 0) return -1; PREV = (PREV << 1) | bit; if (bit) { bit = jbig2_arith_decode(as, &IAx[PREV]); if (bit < 0) return -1; PREV = (PREV << 1) | bit; if (bit) { bit = jbig2_arith_decode(as, &IAx[PREV]); if (bit < 0) return -1; PREV = (PREV << 1) | bit; if (bit) { bit = jbig2_arith_decode(as, &IAx[PREV]); if (bit < 0) return -1; PREV = (PREV << 1) | bit; if (bit) { bit = jbig2_arith_decode(as, &IAx[PREV]); if (bit < 0) return -1; PREV = (PREV << 1) | bit; if (bit) { n_tail = 32; offset = 4436; } else { n_tail = 12; offset = 340; } } else { n_tail = 8; offset = 84; } } else { n_tail = 6; offset = 20; } } else { n_tail = 4; offset = 4; } } else { n_tail = 2; offset = 0; } V = 0; for (i = 0; i < n_tail; i++) { bit = jbig2_arith_decode(as, &IAx[PREV]); if (bit < 0) return -1; PREV = ((PREV << 1) & 511) | (PREV & 256) | bit; V = (V << 1) | bit; } V += offset; V = S ? -V : V; *p_result = V; return S && V == 0 ? 1 : 0; } void jbig2_arith_int_ctx_free(Jbig2Ctx *ctx, Jbig2ArithIntCtx *iax) { jbig2_free(ctx->allocator, iax); } jbig2dec-0.13/jbig2_arith_int.h000066400000000000000000000015561270170036400163240ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ typedef struct _Jbig2ArithIntCtx Jbig2ArithIntCtx; Jbig2ArithIntCtx *jbig2_arith_int_ctx_new(Jbig2Ctx *ctx); int jbig2_arith_int_decode(Jbig2ArithIntCtx *ctx, Jbig2ArithState *as, int32_t *p_result); void jbig2_arith_int_ctx_free(Jbig2Ctx *ctx, Jbig2ArithIntCtx *iax); jbig2dec-0.13/jbig2_generic.c000066400000000000000000000731171270170036400157540ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /** * Generic region handlers. **/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include /* memcpy(), memset() */ #ifdef OUTPUT_PBM #include #endif #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_image.h" #include "jbig2_arith.h" #include "jbig2_generic.h" #include "jbig2_mmr.h" /* return the appropriate context size for the given template */ int jbig2_generic_stats_size(Jbig2Ctx *ctx, int template) { int stats_size = template == 0 ? 1 << 16 : template == 1 ? 1 << 1 << 13 : 1 << 10; return stats_size; } static int jbig2_decode_generic_template0(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; const int rowstride = image->stride; int x, y; byte *gbreg_line = (byte *) image->data; /* todo: currently we only handle the nominal gbat location */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 6 : 0; CONTEXT = (line_m1 & 0x7f0) | (line_m2 & 0xf800); /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); if (y >= 2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 6 : 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x7bf7) << 1) | bit | ((line_m1 >> (7 - x_minor)) & 0x10) | ((line_m2 >> (7 - x_minor)) & 0x800); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template0_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; /* this version is generic and easy to understand, but very slow */ for (y = 0; y < GBH; y++) { for (x = 0; x < GBW; x++) { CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 13; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } return 0; } static int jbig2_decode_generic_template1(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; const int rowstride = image->stride; int x, y; byte *gbreg_line = (byte *) image->data; /* todo: currently we only handle the nominal gbat location */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 5 : 0; CONTEXT = ((line_m1 >> 1) & 0x1f8) | ((line_m2 >> 1) & 0x1e00); /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); if (y >= 2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 5 : 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0xefb) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x8) | ((line_m2 >> (8 - x_minor)) & 0x200); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template2(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; const int rowstride = image->stride; int x, y; byte *gbreg_line = (byte *) image->data; /* todo: currently we only handle the nominal gbat location */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 4 : 0; CONTEXT = ((line_m1 >> 3) & 0x7c) | ((line_m2 >> 3) & 0x380); /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); if (y >= 2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 4 : 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1bd) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } static int jbig2_decode_generic_template2a(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; const int rowstride = image->stride; int x, y; byte *gbreg_line = (byte *) image->data; /* This is a special case for GBATX1 = 3, GBATY1 = -1 */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; uint32_t line_m2; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 4 : 0; CONTEXT = ((line_m1 >> 3) & 0x78) | ((line_m1 >> 2) & 0x4) | ((line_m2 >> 3) & 0x380); /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); if (y >= 2) line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 4 : 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1b9) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x8) | ((line_m1 >> (9 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } #ifdef UNUSED static int jbig2_decode_generic_template3(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; const int rowstride = image->stride; byte *gbreg_line = (byte *) image->data; int x, y; /* this routine only handles the nominal AT location */ #ifdef OUTPUT_PBM printf("P4\n%d %d\n", GBW, GBH); #endif if (GBW <= 0) return 0; for (y = 0; y < GBH; y++) { uint32_t CONTEXT; uint32_t line_m1; int padded_width = (GBW + 7) & -8; line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0; CONTEXT = (line_m1 >> 1) & 0x3f0; /* 6.2.5.7 3d */ for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; int minor_width = GBW - x > 8 ? 8 : GBW - x; if (y >= 1) line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0); /* This is the speed-critical inner loop. */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x1f7) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x010); } gbreg_line[x >> 3] = result; } #ifdef OUTPUT_PBM fwrite(gbreg_line, 1, rowstride, stdout); #endif gbreg_line += rowstride; } return 0; } #endif static int jbig2_decode_generic_template3_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; /* this version is generic and easy to understand, but very slow */ for (y = 0; y < GBH; y++) { for (x = 0; x < GBW; x++) { CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } return 0; } static void copy_prev_row(Jbig2Image *image, int row) { if (!row) { /* no previous row */ memset(image->data, 0, image->stride); } else { /* duplicate data from the previous row */ uint8_t *src = image->data + (row - 1) * image->stride; memcpy(src + image->stride, src, image->stride); } } static int jbig2_decode_generic_template0_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { bit = jbig2_arith_decode(as, &GB_stats[0x9B25]); if (bit < 0) return -1; LTP ^= bit; if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12; CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 13; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } else { copy_prev_row(image, y); } } return 0; } static int jbig2_decode_generic_template1_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { bit = jbig2_arith_decode(as, &GB_stats[0x0795]); if (bit < 0) return -1; LTP ^= bit; if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 2) << 9; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 10; CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 11; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 12; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } else { copy_prev_row(image, y); } } return 0; } static int jbig2_decode_generic_template2_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { bit = jbig2_arith_decode(as, &GB_stats[0xE5]); if (bit < 0) return -1; LTP ^= bit; if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3; CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 4; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7; CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } else { copy_prev_row(image, y); } } return 0; } static int jbig2_decode_generic_template3_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int GBW = image->width; const int GBH = image->height; uint32_t CONTEXT; int x, y; bool bit; int LTP = 0; for (y = 0; y < GBH; y++) { bit = jbig2_arith_decode(as, &GB_stats[0x0195]); if (bit < 0) return -1; LTP ^= bit; if (!LTP) { for (x = 0; x < GBW; x++) { CONTEXT = jbig2_image_get_pixel(image, x - 1, y); CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3; CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5; CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7; CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8; CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9; bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } else { copy_prev_row(image, y); } } return 0; } static int jbig2_decode_generic_region_TPGDON(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { switch (params->GBTEMPLATE) { case 0: return jbig2_decode_generic_template0_TPGDON(ctx, segment, params, as, image, GB_stats); case 1: return jbig2_decode_generic_template1_TPGDON(ctx, segment, params, as, image, GB_stats); case 2: return jbig2_decode_generic_template2_TPGDON(ctx, segment, params, as, image, GB_stats); case 3: return jbig2_decode_generic_template3_TPGDON(ctx, segment, params, as, image, GB_stats); } return -1; } /** * jbig2_decode_generic_region: Decode a generic region. * @ctx: The context for allocation and error reporting. * @segment: A segment reference for error reporting. * @params: Decoding parameter set. * @as: Arithmetic decoder state. * @image: Where to store the decoded data. * @GB_stats: Arithmetic stats. * * Decodes a generic region, according to section 6.2. The caller should * pass an already allocated Jbig2Image object for @image * * Because this API is based on an arithmetic decoding state, it is * not suitable for MMR decoding. * * Return code: 0 on success. **/ int jbig2_decode_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats) { const int8_t *gbat = params->gbat; if (image->stride * image->height > (1 << 24) && segment->data_length < image->stride * image->height / 256) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "region is far larger than data provided (%d << %d), aborting to prevent DOS", segment->data_length, image->stride * image->height); } if (!params->MMR && params->TPGDON) return jbig2_decode_generic_region_TPGDON(ctx, segment, params, as, image, GB_stats); if (!params->MMR && params->GBTEMPLATE == 0) { if (gbat[0] == +3 && gbat[1] == -1 && gbat[2] == -3 && gbat[3] == -1 && gbat[4] == +2 && gbat[5] == -2 && gbat[6] == -2 && gbat[7] == -2) return jbig2_decode_generic_template0(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template0_unopt(ctx, segment, params, as, image, GB_stats); } else if (!params->MMR && params->GBTEMPLATE == 1) return jbig2_decode_generic_template1(ctx, segment, params, as, image, GB_stats); else if (!params->MMR && params->GBTEMPLATE == 2) { if (gbat[0] == 3 && gbat[1] == -1) return jbig2_decode_generic_template2a(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template2(ctx, segment, params, as, image, GB_stats); } else if (!params->MMR && params->GBTEMPLATE == 3) { if (gbat[0] == 2 && gbat[1] == -1) return jbig2_decode_generic_template3_unopt(ctx, segment, params, as, image, GB_stats); else return jbig2_decode_generic_template3_unopt(ctx, segment, params, as, image, GB_stats); } { int i; for (i = 0; i < 8; i++) jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "gbat[%d] = %d", i, params->gbat[i]); } jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "decode_generic_region: MMR=%d, GBTEMPLATE=%d NYI", params->MMR, params->GBTEMPLATE); return -1; } /** * Handler for immediate generic region segments */ int jbig2_immediate_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2RegionSegmentInfo rsi; byte seg_flags; int8_t gbat[8]; int offset; int gbat_bytes = 0; Jbig2GenericRegionParams params; int code = 0; Jbig2Image *image = NULL; Jbig2WordStream *ws = NULL; Jbig2ArithState *as = NULL; Jbig2ArithCx *GB_stats = NULL; /* 7.4.6 */ if (segment->data_length < 18) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); jbig2_get_region_segment_info(&rsi, segment_data); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "generic region: %d x %d @ (%d, %d), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags); /* 7.4.6.2 */ seg_flags = segment_data[17]; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "segment flags = %02x", seg_flags); if ((seg_flags & 1) && (seg_flags & 6)) jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "MMR is 1, but GBTEMPLATE is not 0"); /* 7.4.6.3 */ if (!(seg_flags & 1)) { gbat_bytes = (seg_flags & 6) ? 2 : 8; if (18 + gbat_bytes > segment->data_length) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); memcpy(gbat, segment_data + 18, gbat_bytes); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "gbat: %d, %d", gbat[0], gbat[1]); } offset = 18 + gbat_bytes; /* Table 34 */ params.MMR = seg_flags & 1; params.GBTEMPLATE = (seg_flags & 6) >> 1; params.TPGDON = (seg_flags & 8) >> 3; params.USESKIP = 0; memcpy(params.gbat, gbat, gbat_bytes); image = jbig2_image_new(ctx, rsi.width, rsi.height); if (image == NULL) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to allocate generic image"); jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, rsi.height); if (params.MMR) { code = jbig2_decode_generic_mmr(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, image); } else { int stats_size = jbig2_generic_stats_size(ctx, params.GBTEMPLATE); GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GB_stats == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to allocate GB_stats in jbig2_immediate_generic_region"); goto cleanup; } memset(GB_stats, 0, stats_size); ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset); if (ws == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to allocate ws in jbig2_immediate_generic_region"); goto cleanup; } as = jbig2_arith_new(ctx, ws); if (as == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to allocate as in jbig2_immediate_generic_region"); goto cleanup; } code = jbig2_decode_generic_region(ctx, segment, ¶ms, as, image, GB_stats); } if (code >= 0) jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, rsi.x, rsi.y, rsi.op); else jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error while decoding immediate_generic_region"); cleanup: jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); jbig2_free(ctx->allocator, GB_stats); jbig2_image_release(ctx, image); return code; } jbig2dec-0.13/jbig2_generic.h000066400000000000000000000031561270170036400157550ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /** * Headers for Generic and Generic Refinement region handling **/ /* 6.4 Table 2 */ typedef struct { bool MMR; /* GBW */ /* GBH */ int GBTEMPLATE; bool TPGDON; bool USESKIP; /* SKIP */ int8_t gbat[8]; } Jbig2GenericRegionParams; /* return the appropriate context size for the given template */ int jbig2_generic_stats_size(Jbig2Ctx *ctx, int template); int jbig2_decode_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats); /* 6.3 Table 6 */ typedef struct { /* GRW */ /* GRH */ bool GRTEMPLATE; Jbig2Image *reference; int32_t DX, DY; bool TPGRON; int8_t grat[4]; } Jbig2RefinementRegionParams; int jbig2_decode_refinement_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats); jbig2dec-0.13/jbig2_halftone.c000066400000000000000000000510541270170036400161340ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* JBIG2 Pattern Dictionary and Halftone Region decoding */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include /* memset() */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_generic.h" #include "jbig2_mmr.h" #include "jbig2_image.h" #include "jbig2_halftone.h" /** * jbig2_hd_new: create a new dictionary from a collective bitmap */ Jbig2PatternDict * jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *image) { Jbig2PatternDict *new; const int N = params->GRAYMAX + 1; const int HPW = params->HDPW; const int HPH = params->HDPH; int i; /* allocate a new struct */ new = jbig2_new(ctx, Jbig2PatternDict, 1); if (new != NULL) { new->patterns = jbig2_new(ctx, Jbig2Image *, N); if (new->patterns == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate pattern in collective bitmap dictionary"); jbig2_free(ctx->allocator, new); return NULL; } new->n_patterns = N; new->HPW = HPW; new->HPH = HPH; /* 6.7.5(4) - copy out the individual pattern images */ for (i = 0; i < N; i++) { new->patterns[i] = jbig2_image_new(ctx, HPW, HPH); if (new->patterns[i] == NULL) { int j; jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate pattern element image"); for (j = 0; j < i; j++) jbig2_free(ctx->allocator, new->patterns[j]); jbig2_free(ctx->allocator, new); return NULL; } /* compose with the REPLACE operator; the source will be clipped to the destintion, selecting the proper sub image */ jbig2_image_compose(ctx, new->patterns[i], image, -i * HPW, 0, JBIG2_COMPOSE_REPLACE); } } else { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate collective bitmap dictionary"); } return new; } /** * jbig2_hd_release: release a pattern dictionary */ void jbig2_hd_release(Jbig2Ctx *ctx, Jbig2PatternDict *dict) { int i; if (dict == NULL) return; for (i = 0; i < dict->n_patterns; i++) if (dict->patterns[i]) jbig2_image_release(ctx, dict->patterns[i]); jbig2_free(ctx->allocator, dict->patterns); jbig2_free(ctx->allocator, dict); } /** * jbig2_decode_pattern_dict: decode pattern dictionary data * * @ctx: jbig2 decoder context * @segment: jbig2 segment (header) structure * @params: parameters from the pattern dictionary header * @data: pointer to text region data to be decoded * @size: length of text region data * @GB_stats: artimetic coding context to use * * Implements the patten dictionary decoding proceedure * described in section 6.7 of the JBIG2 spec. * * returns: a pointer to the resulting dictionary on success * returns: 0 on failure **/ static Jbig2PatternDict * jbig2_decode_pattern_dict(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2PatternDictParams *params, const byte *data, const size_t size, Jbig2ArithCx *GB_stats) { Jbig2PatternDict *hd = NULL; Jbig2Image *image = NULL; Jbig2GenericRegionParams rparams; int code = 0; /* allocate the collective image */ image = jbig2_image_new(ctx, params->HDPW * (params->GRAYMAX + 1), params->HDPH); if (image == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate collective bitmap for halftone dict!"); return NULL; } /* fill out the generic region decoder parameters */ rparams.MMR = params->HDMMR; rparams.GBTEMPLATE = params->HDTEMPLATE; rparams.TPGDON = 0; /* not used if HDMMR = 1 */ rparams.USESKIP = 0; rparams.gbat[0] = -(int8_t) params->HDPW; rparams.gbat[1] = 0; rparams.gbat[2] = -3; rparams.gbat[3] = -1; rparams.gbat[4] = 2; rparams.gbat[5] = -2; rparams.gbat[6] = -2; rparams.gbat[7] = -2; if (params->HDMMR) { code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data, size, image); } else { Jbig2WordStream *ws = jbig2_word_stream_buf_new(ctx, data, size); if (ws != NULL) { Jbig2ArithState *as = jbig2_arith_new(ctx, ws); if (as != NULL) { code = jbig2_decode_generic_region(ctx, segment, &rparams, as, image, GB_stats); } else { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for as in halftone dict!"); } jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); } else { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for ws in halftone dict!"); } } if (code == 0) hd = jbig2_hd_new(ctx, params, image); jbig2_image_release(ctx, image); return hd; } /* 7.4.4 */ int jbig2_pattern_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2PatternDictParams params; Jbig2ArithCx *GB_stats = NULL; byte flags; int offset = 0; /* 7.4.4.1 - Data header */ if (segment->data_length < 7) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); } flags = segment_data[0]; params.HDMMR = flags & 1; params.HDTEMPLATE = (flags & 6) >> 1; params.HDPW = segment_data[1]; params.HDPH = segment_data[2]; params.GRAYMAX = jbig2_get_uint32(segment_data + 3); offset += 7; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "pattern dictionary, flags=%02x, %d grays (%dx%d cell)", flags, params.GRAYMAX + 1, params.HDPW, params.HDPH); if (params.HDMMR && params.HDTEMPLATE) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HDTEMPLATE is %d when HDMMR is %d, contrary to spec", params.HDTEMPLATE, params.HDMMR); } if (flags & 0xf8) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "Reserved flag bits non-zero"); } /* 7.4.4.2 */ if (!params.HDMMR) { /* allocate and zero arithmetic coding stats */ int stats_size = jbig2_generic_stats_size(ctx, params.HDTEMPLATE); GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GB_stats == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GB_stats in pattern dictionary"); return 0; } memset(GB_stats, 0, stats_size); } segment->result = jbig2_decode_pattern_dict(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, GB_stats); /* todo: retain GB_stats? */ if (!params.HDMMR) { jbig2_free(ctx->allocator, GB_stats); } return (segment->result != NULL) ? 0 : -1; } /** * jbig2_decode_gray_scale_image: decode gray-scale image * * @ctx: jbig2 decoder context * @segment: jbig2 segment (header) structure * @data: pointer to text region data to be decoded * @size: length of text region data * @GSMMR: if MMR is used * @GSW: width of gray-scale image * @GSH: height of gray-scale image * @GSBPP: number of bitplanes/Jbig2Images to use * @GSKIP: mask indicating which values should be skipped * @GSTEMPLATE: template used to code the gray-scale bitplanes * @GB_stats: artimetic coding context to use * * Implements the decoding a gray-scale image described in * annex C.5. This is part of the halftone region decoding. * * returns: array of gray-scale values with GSW x GSH width/height * 0 on failure **/ uint8_t ** jbig2_decode_gray_scale_image(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *data, const size_t size, bool GSMMR, uint32_t GSW, uint32_t GSH, uint32_t GSBPP, bool GSUSESKIP, Jbig2Image *GSKIP, int GSTEMPLATE, Jbig2ArithCx *GB_stats) { uint8_t **GSVALS = NULL; size_t consumed_bytes = 0; int i, j, code, stride; int x, y; Jbig2Image **GSPLANES; Jbig2GenericRegionParams rparams; Jbig2WordStream *ws = NULL; Jbig2ArithState *as = NULL; /* allocate GSPLANES */ GSPLANES = jbig2_new(ctx, Jbig2Image *, GSBPP); if (GSPLANES == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate %d bytes for GSPLANES", GSBPP); return NULL; } for (i = 0; i < GSBPP; ++i) { GSPLANES[i] = jbig2_image_new(ctx, GSW, GSH); if (GSPLANES[i] == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate %dx%d image for GSPLANES", GSW, GSH); /* free already allocated */ for (j = i - 1; j >= 0; --j) { jbig2_image_release(ctx, GSPLANES[j]); } jbig2_free(ctx->allocator, GSPLANES); return NULL; } } /* C.5 step 1. Decode GSPLANES[GSBPP-1] */ /* fill generic region decoder parameters */ rparams.MMR = GSMMR; rparams.GBTEMPLATE = GSTEMPLATE; rparams.TPGDON = 0; rparams.USESKIP = GSUSESKIP; rparams.gbat[0] = (GSTEMPLATE <= 1 ? 3 : 2); rparams.gbat[1] = -1; rparams.gbat[2] = -3; rparams.gbat[3] = -1; rparams.gbat[4] = 2; rparams.gbat[5] = -2; rparams.gbat[6] = -2; rparams.gbat[7] = -2; if (GSMMR) { code = jbig2_decode_halftone_mmr(ctx, &rparams, data, size, GSPLANES[GSBPP - 1], &consumed_bytes); } else { ws = jbig2_word_stream_buf_new(ctx, data, size); if (ws == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate ws in jbig2_decode_gray_scale_image"); goto cleanup; } as = jbig2_arith_new(ctx, ws); if (as == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate as in jbig2_decode_gray_scale_image"); goto cleanup; } code = jbig2_decode_generic_region(ctx, segment, &rparams, as, GSPLANES[GSBPP - 1], GB_stats); } if (code != 0) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding GSPLANES for halftone image"); goto cleanup; } /* C.5 step 2. Set j = GSBPP-2 */ j = GSBPP - 2; /* C.5 step 3. decode loop */ while (j >= 0) { /* C.5 step 3. (a) */ if (GSMMR) { code = jbig2_decode_halftone_mmr(ctx, &rparams, data + consumed_bytes, size - consumed_bytes, GSPLANES[j], &consumed_bytes); } else { code = jbig2_decode_generic_region(ctx, segment, &rparams, as, GSPLANES[j], GB_stats); } if (code != 0) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding GSPLANES for halftone image"); goto cleanup; } /* C.5 step 3. (b): * for each [x,y] * GSPLANES[j][x][y] = GSPLANES[j+1][x][y] XOR GSPLANES[j][x][y] */ stride = GSPLANES[0]->stride; for (i = 0; i < stride * GSH; ++i) GSPLANES[j]->data[i] ^= GSPLANES[j + 1]->data[i]; /* C.5 step 3. (c) */ --j; } /* allocate GSVALS */ GSVALS = jbig2_new(ctx, uint8_t *, GSW); if (GSVALS == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GSVALS: %d bytes", GSW); goto cleanup; } for (i = 0; i < GSW; ++i) { GSVALS[i] = jbig2_new(ctx, uint8_t, GSH); if (GSVALS[i] == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GSVALS: %d bytes", GSH * GSW); /* free already allocated */ for (j = i - 1; j >= 0; --j) { jbig2_free(ctx->allocator, GSVALS[j]); } jbig2_free(ctx->allocator, GSVALS); GSVALS = NULL; goto cleanup; } } /* C.5 step 4. */ for (x = 0; x < GSW; ++x) { for (y = 0; y < GSH; ++y) { GSVALS[x][y] = 0; for (j = 0; j < GSBPP; ++j) GSVALS[x][y] += jbig2_image_get_pixel(GSPLANES[j], x, y) << j; } } cleanup: /* free memory */ if (!GSMMR) { jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); } for (i = 0; i < GSBPP; ++i) jbig2_image_release(ctx, GSPLANES[i]); jbig2_free(ctx->allocator, GSPLANES); return GSVALS; } /** * jbig2_decode_ht_region_get_hpats: get pattern dictionary * * @ctx: jbig2 decoder context * @segment: jbig2 halftone region segment * * Returns the first referred pattern dictionary of segment * * returns: pattern dictionary * 0 if search failed **/ Jbig2PatternDict * jbig2_decode_ht_region_get_hpats(Jbig2Ctx *ctx, Jbig2Segment *segment) { int index = 0; Jbig2PatternDict *pattern_dict = NULL; Jbig2Segment *rsegment = NULL; /* loop through all referred segments */ while (!pattern_dict && segment->referred_to_segment_count > index) { rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]); if (rsegment) { /* segment type is pattern dictionary and result is not empty */ if ((rsegment->flags & 0x3f) == 16 && rsegment->result) { pattern_dict = (Jbig2PatternDict *) rsegment->result; return pattern_dict; } } index++; } return pattern_dict; } /** * jbig2_decode_halftone_region: decode a halftone region * * @ctx: jbig2 decoder context * @segment: jbig2 halftone region segment * @params: parameters * @data: pointer to halftone region data to be decoded * @size: length of halftone region data * @GB_stats: artimetic coding context to use * * Implements the halftone region decoding proceedure * described in section 6.6.5 of the JBIG2 spec. * * returns: 0 on success * <0 on failure **/ int jbig2_decode_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2HalftoneRegionParams *params, const byte *data, const size_t size, Jbig2Image *image, Jbig2ArithCx *GB_stats) { uint32_t HBPP; uint32_t HNUMPATS; uint8_t **GI; Jbig2Image *HSKIP = NULL; Jbig2PatternDict *HPATS; int i; uint32_t mg, ng; int32_t x, y; uint8_t gray_val; /* 6.6.5 point 1. Fill bitmap with HDEFPIXEL */ memset(image->data, params->HDEFPIXEL, image->stride * image->height); /* 6.6.5 point 2. compute HSKIP */ if (params->HENABLESKIP == 1) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled option HENABLESKIP"); } /* 6.6.5 point 3. set HBPP to ceil(log2(HNUMPATS)): * we need the number of patterns used in this region (HNUMPATS) * get it from referred pattern dictionary */ HPATS = jbig2_decode_ht_region_get_hpats(ctx, segment); if (!HPATS) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "no pattern dictionary found, skipping halftone image"); return -1; } HNUMPATS = HPATS->n_patterns; /* calculate ceil(log2(HNUMPATS)) */ HBPP = 0; while (HNUMPATS > (1 << ++HBPP)); /* 6.6.5 point 4. decode gray-scale image as mentioned in annex C */ GI = jbig2_decode_gray_scale_image(ctx, segment, data, size, params->HMMR, params->HGW, params->HGH, HBPP, params->HENABLESKIP, HSKIP, params->HTEMPLATE, GB_stats); if (!GI) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to acquire gray-scale image, skipping halftone image"); return -1; } /* 6.6.5 point 5. place patterns with procedure mentioned in 6.6.5.2 */ for (mg = 0; mg < params->HGH; ++mg) { for (ng = 0; ng < params->HGW; ++ng) { x = (params->HGX + mg * params->HRY + ng * params->HRX) >> 8; y = (params->HGY + mg * params->HRX - ng * params->HRY) >> 8; /* prevent pattern index >= HNUMPATS */ gray_val = GI[ng][mg]; if (gray_val >= HNUMPATS) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "gray-scale image uses value %d which larger than pattern dictionary", gray_val); /* use highest aviable pattern */ gray_val = HNUMPATS - 1; } jbig2_image_compose(ctx, image, HPATS->patterns[gray_val], x, y, params->op); } } /* free GI */ for (i = 0; i < params->HGW; ++i) { jbig2_free(ctx->allocator, GI[i]); } jbig2_free(ctx->allocator, GI); return 0; } /** * jbig2_halftone_region: read a halftone region segment header **/ int jbig2_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { int offset = 0; Jbig2RegionSegmentInfo region_info; Jbig2HalftoneRegionParams params; Jbig2Image *image = NULL; Jbig2ArithCx *GB_stats = NULL; int code = 0; /* 7.4.5.1 */ if (segment->data_length < 17) goto too_short; jbig2_get_region_segment_info(®ion_info, segment_data); offset += 17; if (segment->data_length < 18) goto too_short; /* 7.4.5.1.1 */ params.flags = segment_data[offset]; params.HMMR = params.flags & 1; params.HTEMPLATE = (params.flags & 6) >> 1; params.HENABLESKIP = (params.flags & 8) >> 3; params.op = (Jbig2ComposeOp)((params.flags & 0x70) >> 4); params.HDEFPIXEL = (params.flags & 0x80) >> 7; offset += 1; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "halftone region: %d x %d @ (%x,%d) flags=%02x", region_info.width, region_info.height, region_info.x, region_info.y, params.flags); if (params.HMMR && params.HTEMPLATE) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HTEMPLATE is %d when HMMR is %d, contrary to spec", params.HTEMPLATE, params.HMMR); } if (params.HMMR && params.HENABLESKIP) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HENABLESKIP is %d when HMMR is %d, contrary to spec", params.HENABLESKIP, params.HMMR); } /* Figure 43 */ if (segment->data_length - offset < 16) goto too_short; params.HGW = jbig2_get_uint32(segment_data + offset); params.HGH = jbig2_get_uint32(segment_data + offset + 4); params.HGX = jbig2_get_int32(segment_data + offset + 8); params.HGY = jbig2_get_int32(segment_data + offset + 12); offset += 16; /* Figure 44 */ if (segment->data_length - offset < 4) goto too_short; params.HRX = jbig2_get_uint16(segment_data + offset); params.HRY = jbig2_get_uint16(segment_data + offset + 2); offset += 4; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, " grid %d x %d @ (%d.%d,%d.%d) vector (%d.%d,%d.%d)", params.HGW, params.HGH, params.HGX >> 8, params.HGX & 0xff, params.HGY >> 8, params.HGY & 0xff, params.HRX >> 8, params.HRX & 0xff, params.HRY >> 8, params.HRY & 0xff); /* 7.4.5.2.2 */ if (!params.HMMR) { /* allocate and zero arithmetic coding stats */ int stats_size = jbig2_generic_stats_size(ctx, params.HTEMPLATE); GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GB_stats == NULL) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GB_stats in halftone region"); } memset(GB_stats, 0, stats_size); } image = jbig2_image_new(ctx, region_info.width, region_info.height); if (image == NULL) { jbig2_free(ctx->allocator, GB_stats); return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to allocate halftone image"); } code = jbig2_decode_halftone_region(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, image, GB_stats); /* todo: retain GB_stats? */ if (!params.HMMR) { jbig2_free(ctx->allocator, GB_stats); } jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, region_info.x, region_info.y, region_info.op); jbig2_image_release(ctx, image); return code; too_short: return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); } jbig2dec-0.13/jbig2_halftone.h000066400000000000000000000040331270170036400161340ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifndef _JBIG2_HALFTONE_H #define _JBIG2_HALFTONE_H typedef struct { int n_patterns; Jbig2Image **patterns; int HPW, HPH; } Jbig2PatternDict; /* Table 24 */ typedef struct { bool HDMMR; uint32_t HDPW; uint32_t HDPH; uint32_t GRAYMAX; int HDTEMPLATE; } Jbig2PatternDictParams; /* Table 33 */ typedef struct { byte flags; uint32_t HGW; uint32_t HGH; int32_t HGX; int32_t HGY; uint16_t HRX; uint16_t HRY; bool HMMR; int HTEMPLATE; bool HENABLESKIP; Jbig2ComposeOp op; bool HDEFPIXEL; } Jbig2HalftoneRegionParams; Jbig2PatternDict *jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *image); void jbig2_hd_release(Jbig2Ctx *ctx, Jbig2PatternDict *dict); uint8_t **jbig2_decode_gray_scale_image(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *data, const size_t size, bool GSMMR, uint32_t GSW, uint32_t GSH, uint32_t GSBPP, bool GSUSESKIP, Jbig2Image *GSKIP, int GSTEMPLATE, Jbig2ArithCx *GB_stats); Jbig2PatternDict *jbig2_decode_ht_region_get_hpats(Jbig2Ctx *ctx, Jbig2Segment *segment); int jbig2_decode_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2HalftoneRegionParams *params, const byte *data, const size_t size, Jbig2Image *image, Jbig2ArithCx *GB_stats); #endif /* _JBIG2_HALFTONE_H */ jbig2dec-0.13/jbig2_huffman.c000066400000000000000000002251041270170036400157570ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* Huffman table decoding procedures -- See Annex B of the JBIG2 specification */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #ifdef JBIG2_DEBUG #include #endif #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_huffman.h" #include "jbig2_hufftab.h" #define JBIG2_HUFFMAN_FLAGS_ISOOB 1 #define JBIG2_HUFFMAN_FLAGS_ISLOW 2 #define JBIG2_HUFFMAN_FLAGS_ISEXT 4 struct _Jbig2HuffmanState { /* The current bit offset is equal to (offset * 8) + offset_bits. The MSB of this_word is the current bit offset. The MSB of next_word is (offset + 4) * 8. */ uint32_t this_word; uint32_t next_word; int offset_bits; int offset; int offset_limit; Jbig2WordStream *ws; Jbig2Ctx *ctx; }; static uint32_t huff_get_next_word(Jbig2HuffmanState *hs, int offset) { uint32_t word = 0; Jbig2WordStream *ws = hs->ws; if ((ws->get_next_word(ws, offset, &word)) && ((hs->offset_limit == 0) || (offset < hs->offset_limit))) hs->offset_limit = offset; return word; } /** Allocate and initialize a new huffman coding state * the returned pointer can simply be freed; this does * not affect the associated Jbig2WordStream. */ Jbig2HuffmanState * jbig2_huffman_new(Jbig2Ctx *ctx, Jbig2WordStream *ws) { Jbig2HuffmanState *result = NULL; result = jbig2_new(ctx, Jbig2HuffmanState, 1); if (result != NULL) { result->offset = 0; result->offset_bits = 0; result->offset_limit = 0; result->ws = ws; result->ctx = ctx; result->this_word = huff_get_next_word(result, 0); result->next_word = huff_get_next_word(result, 4); } else { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate new huffman coding state"); } return result; } /** Free an allocated huffman coding state. * This just calls jbig2_free() if the pointer is not NULL */ void jbig2_huffman_free(Jbig2Ctx *ctx, Jbig2HuffmanState *hs) { if (hs != NULL) jbig2_free(ctx->allocator, hs); return; } /** debug routines **/ #ifdef JBIG2_DEBUG /** print current huffman state */ void jbig2_dump_huffman_state(Jbig2HuffmanState *hs) { fprintf(stderr, "huffman state %08x %08x offset %d.%d\n", hs->this_word, hs->next_word, hs->offset, hs->offset_bits); } /** print the binary string we're reading from */ void jbig2_dump_huffman_binary(Jbig2HuffmanState *hs) { const uint32_t word = hs->this_word; int i; fprintf(stderr, "huffman binary "); for (i = 31; i >= 0; i--) fprintf(stderr, ((word >> i) & 1) ? "1" : "0"); fprintf(stderr, "\n"); } /** print huffman table */ void jbig2_dump_huffman_table(const Jbig2HuffmanTable *table) { int i; int table_size = (1 << table->log_table_size); fprintf(stderr, "huffman table %p (log_table_size=%d, %d entries, entryies=%p):\n", table, table->log_table_size, table_size, table->entries); for (i = 0; i < table_size; i++) { fprintf(stderr, "%6d: PREFLEN=%d, RANGELEN=%d, ", i, table->entries[i].PREFLEN, table->entries[i].RANGELEN); if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISEXT) { fprintf(stderr, "ext=%p", table->entries[i].u.ext_table); } else { fprintf(stderr, "RANGELOW=%d", table->entries[i].u.RANGELOW); } if (table->entries[i].flags) { int need_comma = 0; fprintf(stderr, ", flags=0x%x(", table->entries[i].flags); if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISOOB) { fprintf(stderr, "OOB"); need_comma = 1; } if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISLOW) { if (need_comma) fprintf(stderr, ","); fprintf(stderr, "LOW"); need_comma = 1; } if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISEXT) { if (need_comma) fprintf(stderr, ","); fprintf(stderr, "EXT"); } fprintf(stderr, ")"); } fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } #endif /* JBIG2_DEBUG */ /** Skip bits up to the next byte boundary */ void jbig2_huffman_skip(Jbig2HuffmanState *hs) { int bits = hs->offset_bits & 7; if (bits) { bits = 8 - bits; hs->offset_bits += bits; hs->this_word = (hs->this_word << bits) | (hs->next_word >> (32 - hs->offset_bits)); } if (hs->offset_bits >= 32) { hs->this_word = hs->next_word; hs->offset += 4; hs->next_word = huff_get_next_word(hs, hs->offset + 4); hs->offset_bits -= 32; if (hs->offset_bits) { hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits)); } } } /* skip ahead a specified number of bytes in the word stream */ void jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset) { hs->offset += offset & ~3; hs->offset_bits += (offset & 3) << 3; if (hs->offset_bits >= 32) { hs->offset += 4; hs->offset_bits -= 32; } hs->this_word = huff_get_next_word(hs, hs->offset); hs->next_word = huff_get_next_word(hs, hs->offset + 4); if (hs->offset_bits > 0) hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits)); } /* return the offset of the huffman decode pointer (in bytes) * from the beginning of the WordStream */ int jbig2_huffman_offset(Jbig2HuffmanState *hs) { return hs->offset + (hs->offset_bits >> 3); } /* read a number of bits directly from the huffman state * without decoding against a table */ int32_t jbig2_huffman_get_bits(Jbig2HuffmanState *hs, const int bits, int *err) { uint32_t this_word = hs->this_word; int32_t result; if (hs->offset_limit && hs->offset >= hs->offset_limit) { jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "end of jbig2 buffer reached at offset %d", hs->offset); *err = -1; return -1; } result = this_word >> (32 - bits); hs->offset_bits += bits; if (hs->offset_bits >= 32) { hs->offset += 4; hs->offset_bits -= 32; hs->this_word = hs->next_word; hs->next_word = huff_get_next_word(hs, hs->offset + 4); if (hs->offset_bits) { hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits)); } else { hs->this_word = (hs->this_word << hs->offset_bits); } } else { hs->this_word = (this_word << bits) | (hs->next_word >> (32 - hs->offset_bits)); } return result; } int32_t jbig2_huffman_get(Jbig2HuffmanState *hs, const Jbig2HuffmanTable *table, bool *oob) { Jbig2HuffmanEntry *entry; byte flags; int offset_bits = hs->offset_bits; uint32_t this_word = hs->this_word; uint32_t next_word; int RANGELEN; int32_t result; if (hs->offset_limit && hs->offset >= hs->offset_limit) { jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "end of Jbig2WordStream reached at offset %d", hs->offset); if (oob) *oob = -1; return -1; } for (;;) { int log_table_size = table->log_table_size; int PREFLEN; /* SumatraPDF: shifting by the size of the operand is undefined */ entry = &table->entries[log_table_size > 0 ? this_word >> (32 - log_table_size) : 0]; flags = entry->flags; PREFLEN = entry->PREFLEN; if ((flags == (byte) - 1) && (PREFLEN == (byte) - 1) && (entry->u.RANGELOW == -1)) { if (oob) *oob = -1; return -1; } next_word = hs->next_word; offset_bits += PREFLEN; if (offset_bits >= 32) { this_word = next_word; hs->offset += 4; next_word = huff_get_next_word(hs, hs->offset + 4); offset_bits -= 32; hs->next_word = next_word; PREFLEN = offset_bits; } if (PREFLEN) this_word = (this_word << PREFLEN) | (next_word >> (32 - offset_bits)); if (flags & JBIG2_HUFFMAN_FLAGS_ISEXT) { table = entry->u.ext_table; } else break; } result = entry->u.RANGELOW; RANGELEN = entry->RANGELEN; if (RANGELEN > 0) { int32_t HTOFFSET; HTOFFSET = this_word >> (32 - RANGELEN); if (flags & JBIG2_HUFFMAN_FLAGS_ISLOW) result -= HTOFFSET; else result += HTOFFSET; offset_bits += RANGELEN; if (offset_bits >= 32) { this_word = next_word; hs->offset += 4; next_word = huff_get_next_word(hs, hs->offset + 4); offset_bits -= 32; hs->next_word = next_word; RANGELEN = offset_bits; } if (RANGELEN) this_word = (this_word << RANGELEN) | (next_word >> (32 - offset_bits)); } hs->this_word = this_word; hs->offset_bits = offset_bits; if (oob != NULL) *oob = (flags & JBIG2_HUFFMAN_FLAGS_ISOOB); return result; } /* TODO: more than 8 bits here is wasteful of memory. We have support for sub-trees in jbig2_huffman_get() above, but don't use it here. We should, and then revert to 8 bits */ #define LOG_TABLE_SIZE_MAX 16 /** Build an in-memory representation of a Huffman table from the * set of template params provided by the spec or a table segment */ Jbig2HuffmanTable * jbig2_build_huffman_table(Jbig2Ctx *ctx, const Jbig2HuffmanParams *params) { int *LENCOUNT; int LENMAX = -1; const int lencountcount = 256; const Jbig2HuffmanLine *lines = params->lines; int n_lines = params->n_lines; int i, j; int max_j; int log_table_size = 0; Jbig2HuffmanTable *result; Jbig2HuffmanEntry *entries; int CURLEN; int firstcode = 0; int CURCODE; int CURTEMP; LENCOUNT = jbig2_new(ctx, int, lencountcount); if (LENCOUNT == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "couldn't allocate storage for huffman histogram"); return NULL; } memset(LENCOUNT, 0, sizeof(int) * lencountcount); /* B.3, 1. */ for (i = 0; i < params->n_lines; i++) { int PREFLEN = lines[i].PREFLEN; int lts; if (PREFLEN > LENMAX) { for (j = LENMAX + 1; j < PREFLEN + 1; j++) LENCOUNT[j] = 0; LENMAX = PREFLEN; } LENCOUNT[PREFLEN]++; lts = PREFLEN + lines[i].RANGELEN; if (lts > LOG_TABLE_SIZE_MAX) lts = PREFLEN; if (lts <= LOG_TABLE_SIZE_MAX && log_table_size < lts) log_table_size = lts; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "constructing huffman table log size %d", log_table_size); max_j = 1 << log_table_size; result = jbig2_new(ctx, Jbig2HuffmanTable, 1); if (result == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "couldn't allocate result storage in jbig2_build_huffman_table"); jbig2_free(ctx->allocator, LENCOUNT); return NULL; } result->log_table_size = log_table_size; entries = jbig2_new(ctx, Jbig2HuffmanEntry, max_j); if (entries == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "couldn't allocate entries storage in jbig2_build_huffman_table"); jbig2_free(ctx->allocator, result); jbig2_free(ctx->allocator, LENCOUNT); return NULL; } /* fill now to catch missing JBIG2Globals later */ memset(entries, 0xFF, sizeof(Jbig2HuffmanEntry) * max_j); result->entries = entries; LENCOUNT[0] = 0; for (CURLEN = 1; CURLEN <= LENMAX; CURLEN++) { int shift = log_table_size - CURLEN; /* B.3 3.(a) */ firstcode = (firstcode + LENCOUNT[CURLEN - 1]) << 1; CURCODE = firstcode; /* B.3 3.(b) */ for (CURTEMP = 0; CURTEMP < n_lines; CURTEMP++) { int PREFLEN = lines[CURTEMP].PREFLEN; if (PREFLEN == CURLEN) { int RANGELEN = lines[CURTEMP].RANGELEN; int start_j = CURCODE << shift; int end_j = (CURCODE + 1) << shift; byte eflags = 0; if (end_j > max_j) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "ran off the end of the entries table! (%d >= %d)", end_j, max_j); jbig2_free(ctx->allocator, result->entries); jbig2_free(ctx->allocator, result); jbig2_free(ctx->allocator, LENCOUNT); return NULL; } /* todo: build extension tables */ if (params->HTOOB && CURTEMP == n_lines - 1) eflags |= JBIG2_HUFFMAN_FLAGS_ISOOB; if (CURTEMP == n_lines - (params->HTOOB ? 3 : 2)) eflags |= JBIG2_HUFFMAN_FLAGS_ISLOW; if (PREFLEN + RANGELEN > LOG_TABLE_SIZE_MAX) { for (j = start_j; j < end_j; j++) { entries[j].u.RANGELOW = lines[CURTEMP].RANGELOW; entries[j].PREFLEN = PREFLEN; entries[j].RANGELEN = RANGELEN; entries[j].flags = eflags; } } else { for (j = start_j; j < end_j; j++) { int32_t HTOFFSET = (j >> (shift - RANGELEN)) & ((1 << RANGELEN) - 1); if (eflags & JBIG2_HUFFMAN_FLAGS_ISLOW) entries[j].u.RANGELOW = lines[CURTEMP].RANGELOW - HTOFFSET; else entries[j].u.RANGELOW = lines[CURTEMP].RANGELOW + HTOFFSET; entries[j].PREFLEN = PREFLEN + RANGELEN; entries[j].RANGELEN = 0; entries[j].flags = eflags; } } CURCODE++; } } } jbig2_free(ctx->allocator, LENCOUNT); return result; } /** Free the memory associated with the representation of table */ void jbig2_release_huffman_table(Jbig2Ctx *ctx, Jbig2HuffmanTable *table) { if (table != NULL) { jbig2_free(ctx->allocator, table->entries); jbig2_free(ctx->allocator, table); } return; } /* Routines to handle "code table segment (53)" */ /* return 'bitlen' bits from 'bitoffset' of 'data' */ static uint32_t jbig2_table_read_bits(const byte *data, size_t *bitoffset, const int bitlen) { uint32_t result = 0; uint32_t byte_offset = *bitoffset / 8; const int endbit = (*bitoffset & 7) + bitlen; const int n_proc_bytes = (endbit + 7) / 8; const int rshift = n_proc_bytes * 8 - endbit; int i; for (i = n_proc_bytes - 1; i >= 0; i--) { uint32_t d = data[byte_offset++]; const int nshift = i * 8 - rshift; if (nshift > 0) d <<= nshift; else if (nshift < 0) d >>= -nshift; result |= d; } result &= ~(-1 << bitlen); *bitoffset += bitlen; return result; } /* Parse a code table segment, store Jbig2HuffmanParams in segment->result */ int jbig2_table(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2HuffmanParams *params = NULL; Jbig2HuffmanLine *line = NULL; segment->result = NULL; if (segment->data_length < 10) goto too_short; { /* B.2 1) (B.2.1) Code table flags */ const int code_table_flags = segment_data[0]; const int HTOOB = code_table_flags & 0x01; /* Bit 0: HTOOB */ /* Bits 1-3: Number of bits used in code table line prefix size fields */ const int HTPS = (code_table_flags >> 1 & 0x07) + 1; /* Bits 4-6: Number of bits used in code table line range size fields */ const int HTRS = (code_table_flags >> 4 & 0x07) + 1; /* B.2 2) (B.2.2) The lower bound of the first table line in the encoded table */ const int32_t HTLOW = jbig2_get_int32(segment_data + 1); /* B.2 3) (B.2.3) One larger than the upeer bound of the last normal table line in the encoded table */ const int32_t HTHIGH = jbig2_get_int32(segment_data + 5); /* estimated number of lines int this table, used for alloacting memory for lines */ const size_t lines_max = (segment->data_length * 8 - HTPS * (HTOOB ? 3 : 2)) / (HTPS + HTRS) + (HTOOB ? 3 : 2); /* points to a first table line data */ const byte *lines_data = segment_data + 9; const size_t lines_data_bitlen = (segment->data_length - 9) * 8; /* length in bit */ /* bit offset: controls bit reading */ size_t boffset = 0; /* B.2 4) */ int32_t CURRANGELOW = HTLOW; size_t NTEMP = 0; #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "DECODING USER TABLE... Flags: %d, HTOOB: %d, HTPS: %d, HTRS: %d, HTLOW: %d, HTHIGH: %d", code_table_flags, HTOOB, HTPS, HTRS, HTLOW, HTHIGH); #endif /* allocate HuffmanParams & HuffmanLine */ params = jbig2_new(ctx, Jbig2HuffmanParams, 1); if (params == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Could not allocate Huffman Table Parameter"); goto error_exit; } line = jbig2_new(ctx, Jbig2HuffmanLine, lines_max); if (line == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Could not allocate Huffman Table Lines"); goto error_exit; } /* B.2 5) */ while (CURRANGELOW < HTHIGH) { /* B.2 5) a) */ if (boffset + HTPS >= lines_data_bitlen) goto too_short; line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS); /* B.2 5) b) */ if (boffset + HTRS >= lines_data_bitlen) goto too_short; line[NTEMP].RANGELEN = jbig2_table_read_bits(lines_data, &boffset, HTRS); /* B.2 5) c) */ line[NTEMP].RANGELOW = CURRANGELOW; CURRANGELOW += (1 << line[NTEMP].RANGELEN); NTEMP++; } /* B.2 6), B.2 7) lower range table line */ if (boffset + HTPS >= lines_data_bitlen) goto too_short; line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS); line[NTEMP].RANGELEN = 32; line[NTEMP].RANGELOW = HTLOW - 1; NTEMP++; /* B.2 8), B.2 9) upper range table line */ if (boffset + HTPS >= lines_data_bitlen) goto too_short; line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS); line[NTEMP].RANGELEN = 32; line[NTEMP].RANGELOW = HTHIGH; NTEMP++; /* B.2 10) */ if (HTOOB) { /* B.2 10) a), B.2 10) b) out-of-bound table line */ if (boffset + HTPS >= lines_data_bitlen) goto too_short; line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS); line[NTEMP].RANGELEN = 0; line[NTEMP].RANGELOW = 0; NTEMP++; } if (NTEMP != lines_max) { Jbig2HuffmanLine *new_line = jbig2_renew(ctx, line, Jbig2HuffmanLine, NTEMP); if (new_line == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Could not reallocate Huffman Table Lines"); goto error_exit; } line = new_line; } params->HTOOB = HTOOB; params->n_lines = NTEMP; params->lines = line; segment->result = params; #ifdef JBIG2_DEBUG { int i; for (i = 0; i < NTEMP; i++) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "Line: %d, PREFLEN: %d, RANGELEN: %d, RANGELOW: %d", i, params->lines[i].PREFLEN, params->lines[i].RANGELEN, params->lines[i].RANGELOW); } } #endif } return 0; too_short: jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); error_exit: if (line != NULL) { jbig2_free(ctx->allocator, line); } if (params != NULL) { jbig2_free(ctx->allocator, params); } return -1; } /* free Jbig2HuffmanParams allocated by jbig2_huffman_table() */ void jbig2_table_free(Jbig2Ctx *ctx, Jbig2HuffmanParams *params) { if (params != NULL) { if (params->lines != NULL) jbig2_free(ctx->allocator, (void *)params->lines); jbig2_free(ctx->allocator, params); } } /* find a user supplied table used by 'segment' and by 'index' */ const Jbig2HuffmanParams * jbig2_find_table(Jbig2Ctx *ctx, Jbig2Segment *segment, int index) { int i, table_index = 0; for (i = 0; i < segment->referred_to_segment_count; i++) { const Jbig2Segment *const rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[i]); if (rsegment && (rsegment->flags & 63) == 53) { if (table_index == index) return (const Jbig2HuffmanParams *)rsegment->result; ++table_index; } } return NULL; } #ifdef TEST #include /* cc -g -o jbig2_huffman.test1 -DTEST jbig2_huffman.c .libs/libjbig2dec.a */ /* a test bitstream, and a list of the table indicies to use in decoding it. 1 = table B.1 (A), 2 = table B.2 (B), and so on */ /* this test stream should decode to { 8, 5, oob, 8 } */ const byte test_stream[] = { 0xe9, 0xcb, 0xf4, 0x00 }; const byte test_tabindex[] = { 4, 2, 2, 1 }; static int test_get_word(Jbig2WordStream *self, int offset, uint32_t *word) { /* assume test_stream[] is at least 4 bytes */ if (offset + 3 > sizeof(test_stream)) return -1; *word = ((test_stream[offset] << 24) | (test_stream[offset + 1] << 16) | (test_stream[offset + 2] << 8) | (test_stream[offset + 3])); return 0; } int main(int argc, char **argv) { Jbig2Ctx *ctx; Jbig2HuffmanTable *tables[5]; Jbig2HuffmanState *hs; Jbig2WordStream ws; bool oob; int32_t code; ctx = jbig2_ctx_new(NULL, 0, NULL, NULL, NULL); tables[0] = NULL; tables[1] = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); tables[2] = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_B); tables[3] = NULL; tables[4] = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_D); ws.get_next_word = test_get_word; hs = jbig2_huffman_new(ctx, &ws); printf("testing jbig2 huffmann decoding..."); printf("\t(should be 8 5 (oob) 8)\n"); { int i; int sequence_length = sizeof(test_tabindex); for (i = 0; i < sequence_length; i++) { code = jbig2_huffman_get(hs, tables[test_tabindex[i]], &oob); if (oob) printf("(oob) "); else printf("%d ", code); } } printf("\n"); jbig2_ctx_free(ctx); return 0; } #endif #ifdef TEST2 #include /* cc -g -o jbig2_huffman.test2 -DTEST2 jbig2_huffman.c .libs/libjbig2dec.a */ /* a decoding test of each line from each standard table */ /* test code for Table B.1 - Standard Huffman table A */ const int32_t test_output_A[] = { /* line 0, PREFLEN=1, RANGELEN=4, VAL=0..15, 0+VAL */ 0, /* 0 0000 */ 1, /* 0 0001 */ 14, /* 0 1110 */ 15, /* 0 1111 */ /* line 1, PREFLEN=2, RANGELEN=8, VAL=16..271, 10+(VAL-16) */ 16, /* 10 00000000 */ 17, /* 10 00000001 */ 270, /* 10 11111110 */ 271, /* 10 11111111 */ /* line 2, PREFLEN=3, RANGELEN=16, VAL=272..65807, 110+(VAL-272) */ 272, /* 110 00000000 00000000 */ 273, /* 110 00000000 00000001 */ 65806, /* 110 11111111 11111110 */ 65807, /* 110 11111111 11111111 */ /* line 3, PREFLEN=3, RANGELEN=32, VAL=65808..INF, 111+(VAL-65808) */ 65808, /* 111 00000000 00000000 00000000 00000000 */ 65809, /* 111 00000000 00000000 00000000 00000001 */ }; const byte test_input_A[] = { /* 0000 0000 0101 1100 1111 1000 0000 0010 */ 0x00, 0x5c, 0xf8, 0x02, /* 0000 0001 1011 1111 1010 1111 1111 1100 */ 0x01, 0xbf, 0xaf, 0xfc, /* 0000 0000 0000 0001 1000 0000 0000 0000 */ 0x00, 0x01, 0x80, 0x00, /* 0111 0111 1111 1111 1111 0110 1111 1111 */ 0x77, 0xff, 0xf6, 0xff, /* 1111 1111 1110 0000 0000 0000 0000 0000 */ 0xff, 0xe0, 0x00, 0x00, /* 0000 0000 0001 1100 0000 0000 0000 0000 */ 0x00, 0x1c, 0x00, 0x00, /* 0000 0000 0000 01 */ 0x00, 0x04, }; /* test code for Table B.2 - Standard Huffman table B */ const int32_t test_output_B[] = { /* line 0, PREFLEN=1, RANGELEN=0, VAL=0, 0 */ 0, /* 0 */ /* line 1, PREFLEN=2, RANGELEN=0, VAL=1, 10 */ 1, /* 10 */ /* line 2, PREFLEN=3, RANGELEN=0, VAL=2, 110 */ 2, /* 110 */ /* line 3, PREFLEN=4, RANGELEN=3, VAL=3..10, 1110+(VAL-3) */ 3, /* 1110 000 */ 4, /* 1110 001 */ 9, /* 1110 110 */ 10, /* 1110 111 */ /* line 4, PREFLEN=5, RANGELEN=6, VAL=11..74, 11110+(VAL-11) */ 11, /* 11110 000000 */ 12, /* 11110 000001 */ 73, /* 11110 111110 */ 74, /* 11110 111111 */ /* line 5, PREFLEN=6, RANGELEN=32, VAL=75..INF, 111110+(VAL-75) */ 75, /* 111110 00000000 00000000 00000000 00000000 */ 76, /* 111110 00000000 00000000 00000000 00000001 */ /* line 6, PREFLEN=6, VAL=OOB, 111111 */ /*OOB*/ /* 111111 */ }; const byte test_input_B[] = { /* 0101 1011 1000 0111 0001 1110 1101 1101 */ 0x5b, 0x87, 0x1e, 0xdd, /* 1111 1100 0000 0111 1000 0001 1111 0111 */ 0xfc, 0x07, 0x81, 0xf7, /* 1101 1110 1111 1111 1110 0000 0000 0000 */ 0xde, 0xff, 0xe0, 0x00, /* 0000 0000 0000 0000 0000 1111 1000 0000 */ 0x00, 0x00, 0x0f, 0x80, /* 0000 0000 0000 0000 0000 0000 0111 1111 */ 0x00, 0x00, 0x00, 0x7f, }; /* test code for Table B.3 - Standard Huffman table C */ const int32_t test_output_C[] = { /* line 0, PREFLEN=8, RANGELEN=8, VAL=-256..-1, 11111110+(VAL+256) */ -256, /* 11111110 00000000 */ -255, /* 11111110 00000001 */ -2, /* 11111110 11111110 */ -1, /* 11111110 11111111 */ /* line 1, PREFLEN=1, RANGELEN=0, VAL=0, 0 */ 0, /* 0 */ /* line 2, PREFLEN=2, RANGELEN=0, VAL=1, 10 */ 1, /* 10 */ /* line 3, PREFLEN=3, RANGELEN=0, VAL=2, 110 */ 2, /* 110 */ /* line 4, PREFLEN=4, RANGELEN=3, VAL=3..10, 1110+(VAL-3) */ 3, /* 1110 000 */ 4, /* 1110 001 */ 9, /* 1110 110 */ 10, /* 1110 111 */ /* line 5, PREFLEN=5, RANGELEN=6, VAL=11..74, 11110+(VAL-11) */ 11, /* 11110 000000 */ 12, /* 11110 000001 */ 73, /* 11110 111110 */ 74, /* 11110 111111 */ /* line 6, PREFLEN=8, RANGELEN=32, VAL=-INF..-257, 11111111+(-257-VAL) */ -257, /* 11111111 00000000 00000000 00000000 00000000 */ -258, /* 11111111 00000000 00000000 00000000 00000001 */ /* line 7, PREFLEN=7, RANGELEN=32, VAL=75..INF, 1111110+(VAL-75) */ 75, /* 1111110 00000000 00000000 00000000 00000000 */ 76, /* 1111110 00000000 00000000 00000000 00000001 */ /* line 8, PREFLEN=6, VAL=OOB, 111110 */ /*OOB*/ /* 111110 */ }; const byte test_input_C[] = { /* 1111 1110 0000 0000 1111 1110 0000 0001 */ 0xfe, 0x00, 0xfe, 0x01, /* 1111 1110 1111 1110 1111 1110 1111 1111 */ 0xfe, 0xfe, 0xfe, 0xff, /* 0101 1011 1000 0111 0001 1110 1101 1101 */ 0x5b, 0x87, 0x1e, 0xdd, /* 1111 1100 0000 0111 1000 0001 1111 0111 */ 0xfc, 0x07, 0x81, 0xf7, /* 1101 1110 1111 1111 1111 1100 0000 0000 */ 0xde, 0xff, 0xfc, 0x00, /* 0000 0000 0000 0000 0000 0011 1111 1100 */ 0x00, 0x00, 0x03, 0xfc, /* 0000 0000 0000 0000 0000 0000 0000 0111 */ 0x00, 0x00, 0x00, 0x07, /* 1111 0000 0000 0000 0000 0000 0000 0000 */ 0xf0, 0x00, 0x00, 0x00, /* 0000 0111 1110 0000 0000 0000 0000 0000 */ 0x07, 0xe0, 0x00, 0x00, /* 0000 0000 0001 1111 10 */ 0x00, 0x1f, 0x80, }; /* test code for Table B.4 - Standard Huffman table D */ const int32_t test_output_D[] = { /* line 0, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 1, /* 0 */ /* line 1, PREFLEN=2, RANGELEN=0, VAL=2, 10 */ 2, /* 10 */ /* line 2, PREFLEN=3, RANGELEN=0, VAL=3, 110 */ 3, /* 110 */ /* line 3, PREFLEN=4, RANGELEN=3, VAL=4..11, 1110+(VAL-4) */ 4, /* 1110 000 */ 5, /* 1110 001 */ 10, /* 1110 110 */ 11, /* 1110 111 */ /* line 4, PREFLEN=5, RANGELEN=6, VAL=12..75, 11110+(VAL-12) */ 12, /* 11110 000000 */ 13, /* 11110 000001 */ 74, /* 11110 111110 */ 75, /* 11110 111111 */ /* line 5, PREFLEN=5, RANGELEN=32, VAL=76..INF, 11111+(VAL-76) */ 76, /* 11111 00000000 00000000 00000000 00000000 */ 77, /* 11111 00000000 00000000 00000000 00000001 */ }; const byte test_input_D[] = { /* 0101 1011 1000 0111 0001 1110 1101 1101 */ 0x5b, 0x87, 0x1e, 0xdd, /* 1111 1100 0000 0111 1000 0001 1111 0111 */ 0xfc, 0x07, 0x81, 0xf7, /* 1101 1110 1111 1111 1110 0000 0000 0000 */ 0xde, 0xff, 0xe0, 0x00, /* 0000 0000 0000 0000 0001 1111 0000 0000 */ 0x00, 0x00, 0x1f, 0x00, /* 0000 0000 0000 0000 0000 0001 */ 0x00, 0x00, 0x01, }; /* test code for Table B.5 - Standard Huffman table E */ const int32_t test_output_E[] = { /* line 0, PREFLEN=7, RANGELEN=8, VAL=-255..0, 1111110+(VAL+255) */ -255, /* 1111110 00000000 */ -254, /* 1111110 00000001 */ -1, /* 1111110 11111110 */ 0, /* 1111110 11111111 */ /* line 1, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 1, /* 0 */ /* line 2, PREFLEN=2, RANGELEN=0, VAL=2, 10 */ 2, /* 10 */ /* line 3, PREFLEN=3, RANGELEN=0, VAL=3, 110 */ 3, /* 110 */ /* line 4, PREFLEN=4, RANGELEN=3, VAL=4..11, 1110+(VAL-4) */ 4, /* 1110 000 */ 5, /* 1110 001 */ 10, /* 1110 110 */ 11, /* 1110 111 */ /* line 5, PREFLEN=5, RANGELEN=6, VAL=12..75, 11110+(VAL-12) */ 12, /* 11110 000000 */ 13, /* 11110 000001 */ 74, /* 11110 111110 */ 75, /* 11110 111111 */ /* line 6, PREFLEN=7, RANGELEN=32, VAL=-INF..-256, 1111111+(-256-VAL) */ -256, /* 1111111 00000000 00000000 00000000 00000000 */ -257, /* 1111111 00000000 00000000 00000000 00000001 */ /* line 6, PREFLEN=6, RANGELEN=32, VAL=76..INF, 111110+(VAL-76) */ 76, /* 111110 00000000 00000000 00000000 00000000 */ 77, /* 111110 00000000 00000000 00000000 00000001 */ }; const byte test_input_E[] = { /* 1111 1100 0000 0001 1111 1000 0000 0111 */ 0xfc, 0x01, 0xf8, 0x07, /* 1111 0111 1111 0111 1110 1111 1111 0101 */ 0xf7, 0xf7, 0xef, 0xf5, /* 1011 1000 0111 0001 1110 1101 1101 1111 */ 0xb8, 0x71, 0xed, 0xdf, /* 1100 0000 0111 1000 0001 1111 0111 1101 */ 0xc0, 0x78, 0x1f, 0x7d, /* 1110 1111 1111 1111 1000 0000 0000 0000 */ 0xef, 0xff, 0x80, 0x00, /* 0000 0000 0000 0000 0111 1111 0000 0000 */ 0x00, 0x00, 0x7f, 0x00, /* 0000 0000 0000 0000 0000 0001 1111 1000 */ 0x00, 0x00, 0x01, 0xf8, /* 0000 0000 0000 0000 0000 0000 0000 0011 */ 0x00, 0x00, 0x00, 0x03, /* 1110 0000 0000 0000 0000 0000 0000 0000 */ 0xe0, 0x00, 0x00, 0x00, /* 0001 */ 0x10, }; /* test code for Table B.6 - Standard Huffman table F */ const int32_t test_output_F[] = { /* line 0, PREFLEN=5, RANGELEN=10, VAL=-2048..-1025, 11100+(VAL+2048) */ -2048, /* 11100 00000000 00 */ -2047, /* 11100 00000000 01 */ -1026, /* 11100 11111111 10 */ -1025, /* 11100 11111111 11 */ /* line 1, PREFLEN=4, RANGELEN=9, VAL=-1024..-513, 1000+(VAL+1024) */ -1024, /* 1000 00000000 0 */ -1023, /* 1000 00000000 1 */ -514, /* 1000 11111111 0 */ -513, /* 1000 11111111 1 */ /* line 2, PREFLEN=4, RANGELEN=8, VAL=-512..-257, 1001+(VAL+512) */ -512, /* 1001 00000000 */ -511, /* 1001 00000001 */ -258, /* 1001 11111110 */ -257, /* 1001 11111111 */ /* line 3, PREFLEN=4, RANGELEN=7, VAL=-256..-129, 1010+(VAL+256) */ -256, /* 1010 0000000 */ -255, /* 1010 0000001 */ -130, /* 1010 1111110 */ -129, /* 1010 1111111 */ /* line 4, PREFLEN=5, RANGELEN=6, VAL=-128..-65, 11101+(VAL+128) */ -128, /* 11101 000000 */ -127, /* 11101 000001 */ -66, /* 11101 111110 */ -65, /* 11101 111111 */ /* line 5, PREFLEN=5, RANGELEN=5, VAL=-64..-33, 11110+(VAL+64) */ -64, /* 11110 00000 */ -63, /* 11110 00001 */ -34, /* 11110 11110 */ -33, /* 11110 11111 */ /* line 6, PREFLEN=4, RANGELEN=5, VAL=-32..-1, 1011+(VAL+32) */ -32, /* 1011 00000 */ -31, /* 1011 00001 */ -2, /* 1011 11110 */ -1, /* 1011 11111 */ /* line 7, PREFLEN=2, RANGELEN=7, VAL=0..127, 00+VAL */ 0, /* 00 0000000 */ 1, /* 00 0000001 */ 126, /* 00 1111110 */ 127, /* 00 1111111 */ /* line 8, PREFLEN=3, RANGELEN=7, VAL=128..255, 010+(VAL-128) */ 128, /* 010 0000000 */ 129, /* 010 0000001 */ 254, /* 010 1111110 */ 255, /* 010 1111111 */ /* line 9, PREFLEN=3, RANGELEN=8, VAL=256..511, 011+(VAL-256) */ 256, /* 011 00000000 */ 257, /* 011 00000001 */ 510, /* 011 11111110 */ 511, /* 011 11111111 */ /* line 10, PREFLEN=4, RANGELEN=9, VAL=512..1023, 1100+(VAL-512) */ 512, /* 1100 00000000 0 */ 513, /* 1100 00000000 1 */ 1022, /* 1100 11111111 0 */ 1023, /* 1100 11111111 1 */ /* line 11, PREFLEN=4, RANGELEN=10, VAL=1024..2047, 1101+(VAL-1024) */ 1024, /* 1101 00000000 00 */ 1025, /* 1101 00000000 01 */ 2046, /* 1101 11111111 10 */ 2047, /* 1101 11111111 11 */ /* line 12, PREFLEN=6, RANGELEN=32, VAL=-INF..-2049, 111110+(-2049-VAL) */ -2049, /* 111110 00000000 00000000 00000000 00000000 */ -2050, /* 111110 00000000 00000000 00000000 00000001 */ /* line 13, PREFLEN=6, RANGELEN=32, VAL=2048..INF, 111111+(VAL-2048) */ 2048, /* 111111 00000000 00000000 00000000 00000000 */ 2049, /* 111111 00000000 00000000 00000000 00000001 */ }; const byte test_input_F[] = { /* 1110 0000 0000 0001 1100 0000 0000 0111 */ 0xe0, 0x01, 0xc0, 0x07, /* 1001 1111 1111 0111 0011 1111 1111 1000 */ 0x9f, 0xf7, 0x3f, 0xf8, /* 0000 0000 0100 0000 0000 0110 0011 1111 */ 0x00, 0x40, 0x06, 0x3f, /* 1101 0001 1111 1111 1001 0000 0000 1001 */ 0xd1, 0xff, 0x90, 0x09, /* 0000 0001 1001 1111 1110 1001 1111 1111 */ 0x01, 0x9f, 0xe9, 0xff, /* 1010 0000 0001 0100 0000 0110 1011 1111 */ 0xa0, 0x14, 0x06, 0xbf, /* 0101 0111 1111 1110 1000 0001 1101 0000 */ 0x57, 0xfe, 0x81, 0xd0, /* 0111 1011 1111 0111 0111 1111 1111 0000 */ 0x7b, 0xf7, 0x7f, 0xf0, /* 0011 1100 0001 1111 0111 1011 1101 1111 */ 0x3c, 0x1f, 0x7b, 0xdf, /* 1011 0000 0101 1000 0110 1111 1101 0111 */ 0xb0, 0x58, 0x6f, 0xd7, /* 1111 0000 0000 0000 0000 0100 1111 1100 */ 0xf0, 0x00, 0x04, 0xfc, /* 0111 1111 0100 0000 0001 0000 0001 0101 */ 0x7f, 0x40, 0x10, 0x15, /* 1111 1001 0111 1111 0110 0000 0000 1100 */ 0xf9, 0x7f, 0x60, 0x0c, /* 0000 0101 1111 1111 0011 1111 1111 1100 */ 0x05, 0xff, 0x3f, 0xfc, /* 0000 0000 0110 0000 0000 0111 0011 1111 */ 0x00, 0x60, 0x07, 0x3f, /* 1101 1001 1111 1111 1101 0000 0000 0011 */ 0xd9, 0xff, 0xd0, 0x03, /* 0100 0000 0001 1101 1111 1111 1011 0111 */ 0x40, 0x1d, 0xff, 0xb7, /* 1111 1111 1111 1000 0000 0000 0000 0000 */ 0xff, 0xf8, 0x00, 0x00, /* 0000 0000 0000 0011 1110 0000 0000 0000 */ 0x00, 0x03, 0xe0, 0x00, /* 0000 0000 0000 0000 0001 1111 1100 0000 */ 0x00, 0x00, 0x1f, 0xc0, /* 0000 0000 0000 0000 0000 0000 0011 1111 */ 0x00, 0x00, 0x00, 0x3f, /* 0000 0000 0000 0000 0000 0000 0000 0001 */ 0x00, 0x00, 0x00, 0x01, }; /* test code for Table B.7 - Standard Huffman table G */ const int32_t test_output_G[] = { /* line 0, PREFLEN=4, RANGELEN=9, VAL=-1024..-513, 1000+(VAL+1024) */ -1024, /* 1000 00000000 0 */ -1023, /* 1000 00000000 1 */ -514, /* 1000 11111111 0 */ -513, /* 1000 11111111 1 */ /* line 1, PREFLEN=3, RANGELEN=8, VAL=-512..-257, 000+(VAL+512) */ -512, /* 000 00000000 */ -511, /* 000 00000001 */ -258, /* 000 11111110 */ -257, /* 000 11111111 */ /* line 2, PREFLEN=4, RANGELEN=7, VAL=-256..-129, 1001+(VAL+256) */ -256, /* 1001 0000000 */ -255, /* 1001 0000001 */ -130, /* 1001 1111110 */ -129, /* 1001 1111111 */ /* line 3, PREFLEN=5, RANGELEN=6, VAL=-128..-65, 11010+(VAL+128) */ -128, /* 11010 000000 */ -127, /* 11010 000001 */ -66, /* 11010 111110 */ -65, /* 11010 111111 */ /* line 4, PREFLEN=5, RANGELEN=5, VAL=-64..-33, 11011+(VAL+64) */ -64, /* 11011 00000 */ -63, /* 11011 00001 */ -34, /* 11011 11110 */ -33, /* 11011 11111 */ /* line 5, PREFLEN=4, RANGELEN=5, VAL=-32..-1, 1010+(VAL+32) */ -32, /* 1010 00000 */ -31, /* 1010 00001 */ -2, /* 1010 11110 */ -1, /* 1010 11111 */ /* line 6, PREFLEN=4, RANGELEN=5, VAL=0..31, 1011+VAL */ 0, /* 1011 00000 */ 1, /* 1011 00001 */ 30, /* 1011 11110 */ 31, /* 1011 11111 */ /* line 7, PREFLEN=5, RANGELEN=5, VAL=32..63, 11100+(VAL-32) */ 32, /* 11100 00000 */ 33, /* 11100 00001 */ 62, /* 11100 11110 */ 63, /* 11100 11111 */ /* line 8, PREFLEN=5, RANGELEN=6, VAL=64..127, 11101+(VAL-64) */ 64, /* 11101 000000 */ 65, /* 11101 000001 */ 126, /* 11101 111110 */ 127, /* 11101 111111 */ /* line 9, PREFLEN=4, RANGELEN=7, VAL=128..255, 1100+(VAL-128) */ 128, /* 1100 0000000 */ 129, /* 1100 0000001 */ 254, /* 1100 1111110 */ 255, /* 1100 1111111 */ /* line 10, PREFLEN=3, RANGELEN=8, VAL=256..511, 001+(VAL-256) */ 256, /* 001 00000000 */ 257, /* 001 00000001 */ 510, /* 001 11111110 */ 511, /* 001 11111111 */ /* line 11, PREFLEN=3, RANGELEN=9, VAL=512..1023, 010+(VAL-512) */ 512, /* 010 00000000 0 */ 513, /* 010 00000000 1 */ 1022, /* 010 11111111 0 */ 1023, /* 010 11111111 1 */ /* line 12, PREFLEN=3, RANGELEN=10, VAL=1024..2047, 011+(VAL-1024) */ 1024, /* 011 00000000 00 */ 1025, /* 011 00000000 01 */ 2046, /* 011 11111111 10 */ 2047, /* 011 11111111 11 */ /* line 13, PREFLEN=5, RANGELEN=32, VAL=-INF..-1025, 11110+(-1025-VAL) */ -1025, /* 11110 00000000 00000000 00000000 00000000 */ -1026, /* 11110 00000000 00000000 00000000 00000001 */ /* line 14, PREFLEN=5, RANGELEN=32, VAL=2048..INF, 11111+(VAL-2048) */ 2048, /* 11111 00000000 00000000 00000000 00000000 */ 2049, /* 11111 00000000 00000000 00000000 00000001 */ }; const byte test_input_G[] = { /* 1000 0000 0000 0100 0000 0000 0110 0011 */ 0x80, 0x04, 0x00, 0x63, /* 1111 1101 0001 1111 1111 0000 0000 0000 */ 0xfd, 0x1f, 0xf0, 0x00, /* 0000 0000 0100 0111 1111 0000 1111 1111 */ 0x00, 0x47, 0xf0, 0xff, /* 1001 0000 0001 0010 0000 0110 0111 1111 */ 0x90, 0x12, 0x06, 0x7f, /* 0100 1111 1111 1101 0000 0001 1010 0000 */ 0x4f, 0xfd, 0x01, 0xa0, /* 0111 0101 1111 0110 1011 1111 1101 1000 */ 0x75, 0xf6, 0xbf, 0xd8, /* 0011 0110 0001 1101 1111 1011 0111 1111 */ 0x36, 0x1d, 0xfb, 0x7f, /* 1010 0000 0101 0000 0110 1011 1101 0101 */ 0xa0, 0x50, 0x6b, 0xd5, /* 1111 1011 0000 0101 1000 0110 1111 1101 */ 0xfb, 0x05, 0x86, 0xfd, /* 0111 1111 1110 0000 0011 1000 0001 1110 */ 0x7f, 0xe0, 0x38, 0x1e, /* 0111 1011 1001 1111 1110 1000 0001 1101 */ 0x7b, 0x9f, 0xe8, 0x1d, /* 0000 0111 1011 1111 0111 0111 1111 1100 */ 0x07, 0xbf, 0x77, 0xfc, /* 0000 0001 1000 0000 0111 0011 1111 0110 */ 0x01, 0x80, 0x73, 0xf6, /* 0111 1111 0010 0000 0000 0100 0000 0100 */ 0x7f, 0x20, 0x04, 0x04, /* 1111 1111 0001 1111 1111 0100 0000 0000 */ 0xff, 0x1f, 0xf4, 0x00, /* 0100 0000 0001 0101 1111 1110 0101 1111 */ 0x40, 0x15, 0xfe, 0x5f, /* 1111 0110 0000 0000 0011 0000 0000 0101 */ 0xf6, 0x00, 0x30, 0x05, /* 1111 1111 1100 1111 1111 1111 1111 0000 */ 0xff, 0xcf, 0xff, 0xf0, /* 0000 0000 0000 0000 0000 0000 0000 0111 */ 0x00, 0x00, 0x00, 0x07, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ 0x80, 0x00, 0x00, 0x00, /* 0111 1110 0000 0000 0000 0000 0000 0000 */ 0x7e, 0x00, 0x00, 0x00, /* 0000 0001 1111 0000 0000 0000 0000 0000 */ 0x01, 0xf0, 0x00, 0x00, /* 0000 0000 0001 */ 0x00, 0x10, }; /* test code for Table B.8 - Standard Huffman table H */ const int32_t test_output_H[] = { /* line 0, PREFLEN=8, RANGELEN=3, VAL=-15..-8, 11111100+(VAL+15) */ -15, /* 11111100 000 */ -14, /* 11111100 001 */ -9, /* 11111100 110 */ -8, /* 11111100 111 */ /* line 1, PREFLEN=9, RANGELEN=1, VAL=-7..-6, 111111100+(VAL+7) */ -7, /* 111111100 0 */ -6, /* 111111100 1 */ /* line 2, PREFLEN=8, RANGELEN=1, VAL=-5..-4, 11111101+(VAL+5) */ -5, /* 11111101 0 */ -4, /* 11111101 1 */ /* line 3, PREFLEN=9, RANGELEN=0, VAL=-3, 111111101 */ -3, /* 111111101 */ /* line 4, PREFLEN=7, RANGELEN=0, VAL=-2, 1111100 */ -2, /* 1111100 */ /* line 5, PREFLEN=4, RANGELEN=0, VAL=-1, 1010 */ -1, /* 1010 */ /* line 6, PREFLEN=2, RANGELEN=1, VAL=0..1, 00+VAL */ 0, /* 00 0 */ 1, /* 00 1 */ /* line 7, PREFLEN=5, RANGELEN=0, VAL=2, 11010 */ 2, /* 11010 */ /* line 8, PREFLEN=6, RANGELEN=0, VAL=3, 111010 */ 3, /* 111010 */ /* line 9, PREFLEN=3, RANGELEN=4, VAL=4..19, 100+(VAL-4) */ 4, /* 100 0000 */ 5, /* 100 0001 */ 18, /* 100 1110 */ 19, /* 100 1111 */ /* line 10, PREFLEN=6, RANGELEN=1, VAL=20..21, 111011+(VAL-20) */ 20, /* 111011 0 */ 21, /* 111011 1 */ /* line 11, PREFLEN=4, RANGELEN=4, VAL=22..37, 1011+(VAL-22) */ 22, /* 1011 0000 */ 23, /* 1011 0001 */ 36, /* 1011 1110 */ 37, /* 1011 1111 */ /* line 12, PREFLEN=4, RANGELEN=5, VAL=38..69, 1100+(VAL-38) */ 38, /* 1100 00000 */ 39, /* 1100 00001 */ 68, /* 1100 11110 */ 69, /* 1100 11111 */ /* line 13, PREFLEN=5, RANGELEN=6, VAL=70..133, 11011+(VAL-70) */ 70, /* 11011 000000 */ 71, /* 11011 000001 */ 132, /* 11011 111110 */ 133, /* 11011 111111 */ /* line 14, PREFLEN=5, RANGELEN=7, VAL=134..261, 11100+(VAL-134) */ 134, /* 11100 0000000 */ 135, /* 11100 0000001 */ 260, /* 11100 1111110 */ 261, /* 11100 1111111 */ /* line 15, PREFLEN=6, RANGELEN=7, VAL=262..389, 111100+(VAL-262) */ 262, /* 111100 0000000 */ 263, /* 111100 0000001 */ 388, /* 111100 1111110 */ 389, /* 111100 1111111 */ /* line 16, PREFLEN=7, RANGELEN=8, VAL=390..645, 1111101+(VAL-390) */ 390, /* 1111101 00000000 */ 391, /* 1111101 00000001 */ 644, /* 1111101 11111110 */ 645, /* 1111101 11111111 */ /* line 17, PREFLEN=6, RANGELEN=10, VAL=646..1669, 111101+(VAL-646) */ 646, /* 111101 00000000 00 */ 647, /* 111101 00000000 01 */ 1668, /* 111101 11111111 10 */ 1669, /* 111101 11111111 11 */ /* line 18, PREFLEN=9, RANGELEN=32, VAL=-INF..-16, 111111110+(-16-VAL) */ -16, /* 111111110 00000000 00000000 00000000 00000000 */ -17, /* 111111110 00000000 00000000 00000000 00000001 */ /* line 19, PREFLEN=9, RANGELEN=32, VAL=1670..INF, 111111111+(VAL-1670) */ 1670, /* 111111111 00000000 00000000 00000000 00000000 */ 1671, /* 111111111 00000000 00000000 00000000 00000001 */ /* line 20, PREFLEN=2, VAL=OOB, 01 */ /*OOB*/ /* 01 */ }; const byte test_input_H[] = { /* 1111 1100 0001 1111 1000 0111 1111 0011 */ 0xfc, 0x1f, 0x87, 0xf3, /* 0111 1110 0111 1111 1110 0011 1111 1001 */ 0x7e, 0x7f, 0xe3, 0xf9, /* 1111 1101 0111 1110 1111 1111 1011 1111 */ 0xfd, 0x7e, 0xff, 0xbf, /* 0010 1000 0001 1101 0111 0101 0000 0010 */ 0x28, 0x1d, 0x75, 0x02, /* 0000 1100 1110 1001 1111 1101 1011 1011 */ 0x0c, 0xe9, 0xfd, 0xbb, /* 1101 1000 0101 1000 1101 1111 0101 1111 */ 0xd8, 0x58, 0xdf, 0x5f, /* 1110 0000 0011 0000 0011 1001 1110 1100 */ 0xe0, 0x30, 0x39, 0xec, /* 1111 1110 1100 0000 1101 1000 0011 1011 */ 0xfe, 0xc0, 0xd8, 0x3b, /* 1111 1011 0111 1111 1111 0000 0000 0111 */ 0xfb, 0x7f, 0xf0, 0x07, /* 0000 0000 1111 0011 1111 0111 0011 1111 */ 0x00, 0xf3, 0xf7, 0x3f, /* 1111 1000 0000 0011 1100 0000 0011 1110 */ 0xf8, 0x03, 0xc0, 0x3e, /* 0111 1110 1111 0011 1111 1111 1101 0000 */ 0x7e, 0xf3, 0xff, 0xd0, /* 0000 1111 1010 0000 0011 1111 0111 1111 */ 0x0f, 0xa0, 0x3f, 0x7f, /* 1011 1110 1111 1111 1111 1010 0000 0000 */ 0xbe, 0xff, 0xfa, 0x00, /* 0111 1010 0000 0000 1111 1011 1111 1111 */ 0x7a, 0x00, 0xfb, 0xff, /* 0111 1011 1111 1111 1111 1111 1000 0000 */ 0x7b, 0xff, 0xff, 0x80, /* 0000 0000 0000 0000 0000 0000 0011 1111 */ 0x00, 0x00, 0x00, 0x3f, /* 1100 0000 0000 0000 0000 0000 0000 0000 */ 0xc0, 0x00, 0x00, 0x00, /* 0011 1111 1111 0000 0000 0000 0000 0000 */ 0x3f, 0xf0, 0x00, 0x00, /* 0000 0000 0000 1111 1111 1000 0000 0000 */ 0x00, 0x0f, 0xf8, 0x00, /* 0000 0000 0000 0000 0000 101 */ 0x00, 0x00, 0x0a, }; /* test code for Table B.9 - Standard Huffman table I */ const int32_t test_output_I[] = { /* line 0, PREFLEN=8, RANGELEN=4, VAL=-31..-16, 11111100+(VAL+31) */ -31, /* 11111100 0000 */ -30, /* 11111100 0001 */ -17, /* 11111100 1110 */ -16, /* 11111100 1111 */ /* line 1, PREFLEN=9, RANGELEN=2, VAL=-15..-12, 111111100+(VAL+15) */ -15, /* 111111100 00 */ -14, /* 111111100 01 */ -13, /* 111111100 10 */ -12, /* 111111100 11 */ /* line 2, PREFLEN=8, RANGELEN=2, VAL=-11..-8, 11111101+(VAL+11) */ -11, /* 11111101 00 */ -10, /* 11111101 01 */ -9, /* 11111101 10 */ -8, /* 11111101 11 */ /* line 3, PREFLEN=9, RANGELEN=1, VAL=-7..-6, 111111101+(VAL+7) */ -7, /* 111111101 0 */ -6, /* 111111101 1 */ /* line 4, PREFLEN=7, RANGELEN=1, VAL=-5..-4, 1111100+(VAL+5) */ -5, /* 1111100 0 */ -4, /* 1111100 1 */ /* line 5, PREFLEN=4, RANGELEN=1, VAL=-3..-2, 1010+(VAL+3) */ -3, /* 1010 0 */ -2, /* 1010 1 */ /* line 6, PREFLEN=3, RANGELEN=1, VAL=-1..0, 010+(VAL+1) */ -1, /* 010 0 */ 0, /* 010 1 */ /* line 7, PREFLEN=3, RANGELEN=1, VAL=1..2, 011+(VAL-1) */ 1, /* 011 0 */ 2, /* 011 1 */ /* line 8, PREFLEN=5, RANGELEN=1, VAL=3..4, 11010+(VAL-3) */ 3, /* 11010 0 */ 4, /* 11010 1 */ /* line 9, PREFLEN=6, RANGELEN=1, VAL=5..6, 111010+(VAL-5) */ 5, /* 111010 0 */ 6, /* 111010 1 */ /* line 10, PREFLEN=3, RANGELEN=5, VAL=7..38, 100+(VAL-7) */ 7, /* 100 00000 */ 8, /* 100 00001 */ 37, /* 100 11110 */ 38, /* 100 11111 */ /* line 11, PREFLEN=6, RANGELEN=2, VAL=39..42, 111011+(VAL-39) */ 39, /* 111011 00 */ 40, /* 111011 01 */ 41, /* 111011 10 */ 42, /* 111011 11 */ /* line 12, PREFLEN=4, RANGELEN=5, VAL=43..74, 1011+(VAL-43) */ 43, /* 1011 00000 */ 44, /* 1011 00001 */ 73, /* 1011 11110 */ 74, /* 1011 11111 */ /* line 13, PREFLEN=4, RANGELEN=6, VAL=75..138, 1100+(VAL-75) */ 75, /* 1100 000000 */ 76, /* 1100 000001 */ 137, /* 1100 111110 */ 138, /* 1100 111111 */ /* line 14, PREFLEN=5, RANGELEN=7, VAL=139..266, 11011+(VAL-139) */ 139, /* 11011 0000000 */ 140, /* 11011 0000001 */ 265, /* 11011 1111110 */ 266, /* 11011 1111111 */ /* line 15, PREFLEN=5, RANGELEN=8, VAL=267..522, 11100+(VAL-267) */ 267, /* 11100 00000000 */ 268, /* 11100 00000001 */ 521, /* 11100 11111110 */ 522, /* 11100 11111111 */ /* line 16, PREFLEN=6, RANGELEN=8, VAL=523..778, 111100+(VAL-523) */ 523, /* 111100 00000000 */ 524, /* 111100 00000001 */ 777, /* 111100 11111110 */ 778, /* 111100 11111111 */ /* line 17, PREFLEN=7, RANGELEN=9, VAL=779..1290, 1111101+(VAL-779) */ 779, /* 1111101 00000000 0 */ 780, /* 1111101 00000000 1 */ 1289, /* 1111101 11111111 0 */ 1290, /* 1111101 11111111 1 */ /* line 18, PREFLEN=6, RANGELEN=11, VAL=1291..3338, 111101+(VAL-1291) */ 1291, /* 111101 00000000 000 */ 1292, /* 111101 00000000 001 */ 3337, /* 111101 11111111 110 */ 3338, /* 111101 11111111 111 */ /* line 19, PREFLEN=9, RANGELEN=32, VAL=-INF..-32, 111111110+(-32-VAL) */ -32, /* 111111110 00000000 00000000 00000000 00000000 */ -33, /* 111111110 00000000 00000000 00000000 00000001 */ /* line 20, PREFLEN=9, RANGELEN=32, VAL=3339..INF, 111111111+(VAL-3339) */ 3339, /* 111111111 00000000 00000000 00000000 00000000 */ 3340, /* 111111111 00000000 00000000 00000000 00000001 */ /* line 21, PREFLEN=2, VAL=OOB, 00 */ /*OOB*/ /* 00 */ }; const byte test_input_I[] = { /* 1111 1100 0000 1111 1100 0001 1111 1100 */ 0xfc, 0x0f, 0xc1, 0xfc, /* 1110 1111 1100 1111 1111 1110 0001 1111 */ 0xef, 0xcf, 0xfe, 0x1f, /* 1100 0111 1111 1001 0111 1111 0011 1111 */ 0xc7, 0xf9, 0x7f, 0x3f, /* 1101 0011 1111 0101 1111 1101 1011 1111 */ 0xd3, 0xf5, 0xfd, 0xbf, /* 0111 1111 1110 1011 1111 1011 1111 1000 */ 0x7f, 0xeb, 0xfb, 0xf8, /* 1111 1001 1010 0101 0101 0001 0101 1001 */ 0xf9, 0xa5, 0x51, 0x59, /* 1111 0100 1101 0111 1010 0111 0101 1000 */ 0xf4, 0xd7, 0xa7, 0x58, /* 0000 1000 0001 1001 1110 1001 1111 1110 */ 0x08, 0x19, 0xe9, 0xfe, /* 1100 1110 1101 1110 1110 1110 1111 1011 */ 0xce, 0xde, 0xee, 0xfb, /* 0000 0101 1000 0110 1111 1101 0111 1111 */ 0x05, 0x86, 0xfd, 0x7f, /* 1100 0000 0011 0000 0001 1100 1111 1011 */ 0xc0, 0x30, 0x1c, 0xfb, /* 0011 1111 1101 1000 0000 1101 1000 0001 */ 0x3f, 0xd8, 0x0d, 0x81, /* 1101 1111 1110 1101 1111 1111 1110 0000 */ 0xdf, 0xed, 0xff, 0xe0, /* 0000 0111 0000 0000 0111 1001 1111 1101 */ 0x07, 0x00, 0x79, 0xfd, /* 1100 1111 1111 1111 0000 0000 0011 1100 */ 0xcf, 0xff, 0x00, 0x3c, /* 0000 0001 1111 0011 1111 1011 1100 1111 */ 0x01, 0xf3, 0xfb, 0xcf, /* 1111 1111 1010 0000 0000 1111 1010 0000 */ 0xff, 0xa0, 0x0f, 0xa0, /* 0001 1111 1011 1111 1110 1111 1011 1111 */ 0x1f, 0xbf, 0xef, 0xbf, /* 1111 1111 0100 0000 0000 0111 1010 0000 */ 0xff, 0x40, 0x07, 0xa0, /* 0000 0111 1101 1111 1111 1101 1110 1111 */ 0x07, 0xdf, 0xfd, 0xef, /* 1111 1111 1111 1111 0000 0000 0000 0000 */ 0xff, 0xff, 0x00, 0x00, /* 0000 0000 0000 0000 0111 1111 1000 0000 */ 0x00, 0x00, 0x7f, 0x80, /* 0000 0000 0000 0000 0000 0000 0111 1111 */ 0x00, 0x00, 0x00, 0x7f, /* 1110 0000 0000 0000 0000 0000 0000 0000 */ 0xe0, 0x00, 0x00, 0x00, /* 0001 1111 1111 0000 0000 0000 0000 0000 */ 0x1f, 0xf0, 0x00, 0x00, /* 0000 0000 0001 00 */ 0x00, 0x10, }; /* test code for Table B.10 - Standard Huffman table J */ const int32_t test_output_J[] = { /* line 0, PREFLEN=7, RANGELEN=4, VAL=-21..-6, 1111010+(VAL+21) */ -21, /* 1111010 0000 */ -20, /* 1111010 0001 */ -7, /* 1111010 1110 */ -6, /* 1111010 1111 */ /* line 1, PREFLEN=8, RANGELEN=0, VAL=-5, 11111100 */ -5, /* 11111100 */ /* line 2, PREFLEN=7, RANGELEN=0, VAL=-5, 1111011 */ -4, /* 1111011 */ /* line 3, PREFLEN=5, RANGELEN=0, VAL=-3, 11000 */ -3, /* 11000 */ /* line 4, PREFLEN=2, RANGELEN=2, VAL=-2..1, 00+(VAL+2) */ -2, /* 00 00 */ -1, /* 00 01 */ 0, /* 00 10 */ 1, /* 00 11 */ /* line 5, PREFLEN=5, RANGELEN=0, VAL=2, 11001 */ 2, /* 11001 */ /* line 6, PREFLEN=6, RANGELEN=0, VAL=3, 110110 */ 3, /* 110110 */ /* line 7, PREFLEN=7, RANGELEN=0, VAL=4, 1111100 */ 4, /* 1111100 */ /* line 8, PREFLEN=8, RANGELEN=0, VAL=5, 11111101 */ 5, /* 11111101 */ /* line 9, PREFLEN=2, RANGELEN=6, VAL=6..69, 01+(VAL-6) */ 6, /* 01 000000 */ 7, /* 01 000001 */ 68, /* 01 111110 */ 69, /* 01 111111 */ /* line 8, PREFLEN=5, RANGELEN=5, VAL=70..101, 11010+(VAL-70) */ 70, /* 11010 00000 */ 71, /* 11010 00001 */ 100, /* 11010 11110 */ 101, /* 11010 11111 */ /* line 9, PREFLEN=6, RANGELEN=5, VAL=102..133, 110111+(VAL-102) */ 102, /* 110111 00000 */ 103, /* 110111 00001 */ 132, /* 110111 11110 */ 133, /* 110111 11111 */ /* line 10, PREFLEN=6, RANGELEN=6, VAL=134..197, 111000+(VAL-134) */ 134, /* 111000 000000 */ 135, /* 111000 000001 */ 196, /* 111000 111110 */ 197, /* 111000 111111 */ /* line 11, PREFLEN=6, RANGELEN=7, VAL=198..325, 111001+(VAL-198) */ 198, /* 111001 0000000 */ 199, /* 111001 0000001 */ 324, /* 111001 1111110 */ 325, /* 111001 1111111 */ /* line 12, PREFLEN=6, RANGELEN=8, VAL=326..581, 111010+(VAL-326) */ 326, /* 111010 00000000 */ 327, /* 111010 00000001 */ 580, /* 111010 11111110 */ 581, /* 111010 11111111 */ /* line 13, PREFLEN=6, RANGELEN=9, VAL=582..1093, 111011+(VAL-582) */ 582, /* 111011 00000000 0 */ 583, /* 111011 00000000 1 */ 1092, /* 111011 11111111 0 */ 1093, /* 111011 11111111 1 */ /* line 14, PREFLEN=6, RANGELEN=10, VAL=1094..2117, 111100+(VAL-1094) */ 1094, /* 111100 00000000 00 */ 1095, /* 111100 00000000 01 */ 2116, /* 111100 11111111 10 */ 2117, /* 111100 11111111 11 */ /* line 15, PREFLEN=7, RANGELEN=11, VAL=2118..4165, 1111101+(VAL-2118) */ 2118, /* 1111101 00000000 000 */ 2119, /* 1111101 00000000 001 */ 4164, /* 1111101 11111111 110 */ 4165, /* 1111101 11111111 111 */ /* line 16, PREFLEN=8, RANGELEN=32, VAL=-INF..-22, 11111110+(-22-VAL) */ -22, /* 11111110 00000000 00000000 00000000 00000000 */ -23, /* 11111110 00000000 00000000 00000000 00000001 */ /* line 17, PREFLEN=8, RANGELEN=32, VAL=4166..INF, 11111111+(VAL-4166) */ 4166, /* 11111111 00000000 00000000 00000000 00000000 */ 4167, /* 11111111 00000000 00000000 00000000 00000001 */ /* line 8, PREFLEN=2, VAL=OOB, 10 */ /*OOB*/ /* 10 */ }; const byte test_input_J[] = { /* 1111 0100 0001 1110 1000 0111 1101 0111 */ 0xf4, 0x1e, 0x87, 0xd7, /* 0111 1010 1111 1111 1100 1111 0111 1000 */ 0x7a, 0xff, 0xcf, 0x78, /* 0000 0001 0010 0011 1100 1110 1101 1111 */ 0x01, 0x23, 0xce, 0xdf, /* 0011 1111 0101 0000 0001 0000 0101 1111 */ 0x3f, 0x50, 0x10, 0x5f, /* 1001 1111 1111 0100 0000 1101 0000 0111 */ 0x9f, 0xf4, 0x0d, 0x07, /* 0101 1110 1101 0111 1111 0111 0000 0110 */ 0x5e, 0xd7, 0xf7, 0x06, /* 1110 0001 1101 1111 1101 1011 1111 1111 */ 0xe1, 0xdf, 0xdb, 0xff, /* 1000 0000 0011 1000 0000 0111 1000 1111 */ 0x80, 0x38, 0x07, 0x8f, /* 1011 1000 1111 1111 1001 0000 0001 1100 */ 0xb8, 0xff, 0x90, 0x1c, /* 1000 0001 1110 0111 1111 0111 0011 1111 */ 0x81, 0xe7, 0xf7, 0x3f, /* 1111 1010 0000 0000 1110 1000 0000 0111 */ 0xfa, 0x00, 0xe8, 0x07, /* 1010 1111 1110 1110 1011 1111 1111 1011 */ 0xaf, 0xee, 0xbf, 0xfb, /* 0000 0000 0111 0110 0000 0001 1110 1111 */ 0x00, 0x76, 0x01, 0xef, /* 1111 1101 1101 1111 1111 1111 1100 0000 */ 0xfd, 0xdf, 0xff, 0xc0, /* 0000 0011 1100 0000 0000 0111 1100 1111 */ 0x03, 0xc0, 0x07, 0xcf, /* 1111 1011 1100 1111 1111 1111 1110 1000 */ 0xfb, 0xcf, 0xff, 0xe8, /* 0000 0000 1111 1010 0000 0000 0111 1110 */ 0x00, 0xfa, 0x00, 0x7e, /* 1111 1111 1110 1111 1011 1111 1111 1111 */ 0xff, 0xef, 0xbf, 0xff, /* 1111 1000 0000 0000 0000 0000 0000 0000 */ 0xf8, 0x00, 0x00, 0x00, /* 0000 0011 1111 1000 0000 0000 0000 0000 */ 0x03, 0xf8, 0x00, 0x00, /* 0000 0000 0000 0111 1111 1100 0000 0000 */ 0x00, 0x07, 0xfc, 0x00, /* 0000 0000 0000 0000 0000 0011 1111 1100 */ 0x00, 0x00, 0x03, 0xfc, /* 0000 0000 0000 0000 0000 0000 0000 0110 */ 0x00, 0x00, 0x00, 0x06, }; /* test code for Table B.11 - Standard Huffman table K */ const int32_t test_output_K[] = { /* line 0, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 1, /* 0 */ /* line 1, PREFLEN=2, RANGELEN=1, VAL=2..3, 10+(VAL-2) */ 2, /* 10 0 */ 3, /* 10 1 */ /* line 2, PREFLEN=4, RANGELEN=0, VAL=4, 1100 */ 4, /* 1100 */ /* line 3, PREFLEN=4, RANGELEN=1, VAL=5..6, 1101+(VAL-5) */ 5, /* 1101 0 */ 6, /* 1101 1 */ /* line 4, PREFLEN=5, RANGELEN=1, VAL=7..8, 11100+(VAL-7) */ 7, /* 11100 0 */ 8, /* 11100 1 */ /* line 5, PREFLEN=5, RANGELEN=2, VAL=9..12, 11101+(VAL-9) */ 9, /* 11101 00 */ 10, /* 11101 01 */ 11, /* 11101 10 */ 12, /* 11101 11 */ /* line 6, PREFLEN=6, RANGELEN=2, VAL=13..16, 111100+(VAL-13) */ 13, /* 111100 00 */ 14, /* 111100 01 */ 15, /* 111100 10 */ 16, /* 111100 11 */ /* line 7, PREFLEN=7, RANGELEN=2, VAL=17..20, 1111010+(VAL-17) */ 17, /* 1111010 00 */ 18, /* 1111010 01 */ 19, /* 1111010 10 */ 20, /* 1111010 11 */ /* line 8, PREFLEN=7, RANGELEN=3, VAL=21..28, 1111011+(VAL-21) */ 21, /* 1111011 000 */ 22, /* 1111011 001 */ 27, /* 1111011 110 */ 28, /* 1111011 111 */ /* line 9, PREFLEN=7, RANGELEN=4, VAL=29..44, 1111100+(VAL-29) */ 29, /* 1111100 0000 */ 30, /* 1111100 0001 */ 43, /* 1111100 1110 */ 44, /* 1111100 1111 */ /* line 10, PREFLEN=7, RANGELEN=5, VAL=45..76, 1111101+(VAL-45) */ 45, /* 1111101 00000 */ 46, /* 1111101 00001 */ 75, /* 1111101 11110 */ 76, /* 1111101 11111 */ /* line 11, PREFLEN=7, RANGELEN=6, VAL=77..140, 1111110+(VAL-77) */ 77, /* 1111110 000000 */ 78, /* 1111110 000001 */ 139, /* 1111110 111110 */ 140, /* 1111110 111111 */ /* line 12, PREFLEN=7, RANGELEN=32, VAL=141..INF, 1111111+(VAL-141) */ 141, /* 1111111 00000000 00000000 00000000 00000000 */ 142, /* 1111111 00000000 00000000 00000000 00000001 */ }; const byte test_input_K[] = { /* 0100 1011 1001 1010 1101 1111 0001 1100 */ 0x4b, 0x9a, 0xdf, 0x1c, /* 1111 0100 1110 1011 1101 1011 1011 1111 */ 0xf4, 0xeb, 0xdb, 0xbf, /* 1000 0111 1000 1111 1001 0111 1001 1111 */ 0x87, 0x8f, 0x97, 0x9f, /* 1010 0011 1101 0011 1110 1010 1111 0101 */ 0xa3, 0xd3, 0xea, 0xf5, /* 1111 1011 0001 1110 1100 1111 1011 1101 */ 0xfb, 0x1e, 0xcf, 0xbd, /* 1110 1111 1111 1100 0000 1111 1000 0011 */ 0xef, 0xfc, 0x0f, 0x83, /* 1111 0011 1011 1110 0111 1111 1101 0000 */ 0xf3, 0xbe, 0x7f, 0xd0, /* 0111 1101 0000 1111 1101 1111 0111 1101 */ 0x7d, 0x0f, 0xdf, 0x7d, /* 1111 1111 1110 0000 0011 1111 0000 0011 */ 0xff, 0xe0, 0x3f, 0x03, /* 1111 1011 1110 1111 1101 1111 1111 1111 */ 0xfb, 0xef, 0xdf, 0xff, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ 0x00, 0x00, 0x00, 0x00, /* 1111 1110 0000 0000 0000 0000 0000 0000 */ 0xfe, 0x00, 0x00, 0x00, /* 0000 001 */ 0x02, }; /* test code for Table B.12 - Standard Huffman table L */ const int32_t test_output_L[] = { /* line 0, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 1, /* 0 */ /* line 1, PREFLEN=2, RANGELEN=0, VAL=2, 10 */ 2, /* 10 */ /* line 2, PREFLEN=3, RANGELEN=1, VAL=3..4, 110+(VAL-3) */ 3, /* 110 0 */ 4, /* 110 1 */ /* line 3, PREFLEN=5, RANGELEN=0, VAL=5, 11100 */ 5, /* 11100 */ /* line 4, PREFLEN=5, RANGELEN=1, VAL=6..7, 11101+(VAL-7) */ 6, /* 11101 0 */ 7, /* 11101 1 */ /* line 5, PREFLEN=6, RANGELEN=1, VAL=8..9, 111100+(VAL-8) */ 8, /* 111100 0 */ 9, /* 111100 1 */ /* line 6, PREFLEN=7, RANGELEN=0, VAL=10, 1111010 */ 10, /* 1111010 */ /* line 7, PREFLEN=7, RANGELEN=1, VAL=11..12, 1111011+(VAL-11) */ 11, /* 1111011 0 */ 12, /* 1111011 1 */ /* line 8, PREFLEN=7, RANGELEN=2, VAL=13..16, 1111100+(VAL-13) */ 13, /* 1111100 00 */ 14, /* 1111100 01 */ 15, /* 1111100 10 */ 16, /* 1111100 11 */ /* line 9, PREFLEN=7, RANGELEN=3, VAL=17..24, 1111101+(VAL-17) */ 17, /* 1111101 000 */ 18, /* 1111101 001 */ 23, /* 1111101 110 */ 24, /* 1111101 111 */ /* line 10, PREFLEN=7, RANGELEN=4, VAL=25..40, 1111110+(VAL-25) */ 25, /* 1111110 0000 */ 26, /* 1111110 0001 */ 39, /* 1111110 1110 */ 40, /* 1111110 1111 */ /* line 11, PREFLEN=8, RANGELEN=5, VAL=41..72, 11111110+(VAL-41) */ 41, /* 11111110 00000 */ 42, /* 11111110 00001 */ 71, /* 11111110 11110 */ 72, /* 11111110 11111 */ /* line 12, PREFLEN=8, RANGELEN=32, VAL=73..INF, 11111111+(VAL-73) */ 73, /* 11111111 00000000 00000000 00000000 00000000 */ 74, /* 11111111 00000000 00000000 00000000 00000001 */ }; const byte test_input_L[] = { /* 0101 1001 1011 1100 1110 1011 1011 1111 */ 0x59, 0xbc, 0xeb, 0xbf, /* 0001 1110 0111 1101 0111 1011 0111 1011 */ 0x1e, 0x7d, 0x7b, 0x7b, /* 1111 1100 0011 1110 0011 1111 0010 1111 */ 0xfc, 0x3e, 0x3f, 0x2f, /* 1001 1111 1101 0001 1111 0100 1111 1101 */ 0x9f, 0xd1, 0xf4, 0xfd, /* 1101 1111 0111 1111 1110 0000 1111 1100 */ 0xdf, 0x7f, 0xe0, 0xfc, /* 0011 1111 1011 1011 1111 0111 1111 1111 */ 0x3f, 0xbb, 0xf7, 0xff, /* 0000 0011 1111 1000 0011 1111 1101 1110 */ 0x03, 0xf8, 0x3f, 0xde, /* 1111 1110 1111 1111 1111 1000 0000 0000 */ 0xfe, 0xff, 0xf8, 0x00, /* 0000 0000 0000 0000 0000 0111 1111 1000 */ 0x00, 0x00, 0x07, 0xf8, /* 0000 0000 0000 0000 0000 0000 0000 1 */ 0x00, 0x00, 0x00, 0x08, }; /* test code for Table B.13 - Standard Huffman table M */ const int32_t test_output_M[] = { /* line 0, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 1, /* 0 */ /* line 1, PREFLEN=3, RANGELEN=0, VAL=2, 100 */ 2, /* 100 */ /* line 2, PREFLEN=3, RANGELEN=0, VAL=3, 1100 */ 3, /* 1100 */ /* line 3, PREFLEN=5, RANGELEN=0, VAL=4, 11100 */ 4, /* 11100 */ /* line 4, PREFLEN=4, RANGELEN=1, VAL=5..6, 1101+(VAL-5) */ 5, /* 1101 0 */ 6, /* 1101 1 */ /* line 5, PREFLEN=3, RANGELEN=3, VAL=7..14, 101+(VAL-7) */ 7, /* 101 000 */ 8, /* 101 001 */ 13, /* 101 110 */ 14, /* 101 111 */ /* line 6, PREFLEN=6, RANGELEN=1, VAL=15..16, 111010+(VAL-15) */ 15, /* 111010 0 */ 16, /* 111010 1 */ /* line 7, PREFLEN=6, RANGELEN=2, VAL=17..20, 111011+(VAL-17) */ 17, /* 111011 00 */ 18, /* 111011 01 */ 19, /* 111011 10 */ 20, /* 111011 11 */ /* line 8, PREFLEN=6, RANGELEN=3, VAL=21..28, 111100+(VAL-21) */ 21, /* 111100 000 */ 22, /* 111100 001 */ 27, /* 111100 110 */ 28, /* 111100 111 */ /* line 9, PREFLEN=6, RANGELEN=4, VAL=29..44, 111101+(VAL-29) */ 29, /* 111101 0000 */ 30, /* 111101 0001 */ 43, /* 111101 1110 */ 44, /* 111101 1111 */ /* line 10, PREFLEN=6, RANGELEN=5, VAL=45..76, 111110+(VAL-45) */ 45, /* 111110 00000 */ 46, /* 111110 00001 */ 75, /* 111110 11110 */ 76, /* 111110 11111 */ /* line 11, PREFLEN=7, RANGELEN=6, VAL=77..140, 1111110+(VAL-77) */ 77, /* 1111110 000000 */ 78, /* 1111110 000001 */ 139, /* 1111110 111110 */ 140, /* 1111110 111111 */ /* line 12, PREFLEN=7, RANGELEN=32, VAL=141..INF, 1111111+(VAL-141) */ 141, /* 1111111 00000000 00000000 00000000 00000000 */ 142, /* 1111111 00000000 00000000 00000000 00000001 */ }; const byte test_input_M[] = { /* 0100 1100 1110 0110 1011 0111 0100 0101 */ 0x4c, 0xe6, 0xb7, 0x45, /* 0011 0111 0101 1111 1101 0011 1010 1111 */ 0x37, 0x5f, 0xd3, 0xaf, /* 0110 0111 0110 1111 0111 0111 0111 1111 */ 0x67, 0x6f, 0x77, 0x7f, /* 1000 0011 1100 0011 1110 0110 1111 0011 */ 0x83, 0xc3, 0xe6, 0xf3, /* 1111 1010 0001 1110 1000 1111 1011 1101 */ 0xfa, 0x1e, 0x8f, 0xbd, /* 1110 1111 1111 1100 0000 1111 1000 0011 */ 0xef, 0xfc, 0x0f, 0x83, /* 1111 0111 1011 1110 1111 1111 1110 0000 */ 0xf7, 0xbe, 0xff, 0xe0, /* 0011 1111 0000 0011 1111 1011 1110 1111 */ 0x3f, 0x03, 0xfb, 0xef, /* 1101 1111 1111 1111 0000 0000 0000 0000 */ 0xdf, 0xff, 0x00, 0x00, /* 0000 0000 0000 0000 1111 1110 0000 0000 */ 0x00, 0x00, 0xfe, 0x00, /* 0000 0000 0000 0000 0000 001 */ 0x00, 0x00, 0x02, }; /* test code for Table B.14 - Standard Huffman table N */ const int32_t test_output_N[] = { /* line 0, PREFLEN=3, RANGELEN=0, VAL=-2, 100 */ -2, /* 100 */ /* line 1, PREFLEN=3, RANGELEN=0, VAL=-1, 101 */ -1, /* 101 */ /* line 2, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 0, /* 0 */ /* line 3, PREFLEN=3, RANGELEN=0, VAL=1, 110 */ 1, /* 110 */ /* line 4, PREFLEN=3, RANGELEN=0, VAL=2, 111 */ 2, /* 111 */ }; const byte test_input_N[] = { /* 1001 0101 1011 1 */ 0x95, 0xb8, }; /* test code for Table B.15 - Standard Huffman table O */ const int32_t test_output_O[] = { /* line 0, PREFLEN=7, RANGELEN=4, VAL=-24..-9, 1111100+(VAL+24) */ -24, /* 1111100 0000 */ -23, /* 1111100 0001 */ -10, /* 1111100 1110 */ -9, /* 1111100 1111 */ /* line 1, PREFLEN=6, RANGELEN=2, VAL=-8..-5, 111100+(VAL+8) */ -8, /* 111100 00 */ -7, /* 111100 01 */ -6, /* 111100 10 */ -5, /* 111100 11 */ /* line 2, PREFLEN=5, RANGELEN=1, VAL=-4..-3, 11100+(VAL+4) */ -4, /* 11100 0 */ -3, /* 11100 1 */ /* line 3, PREFLEN=4, RANGELEN=0, VAL=-2, 1100 */ -2, /* 1100 */ /* line 4, PREFLEN=3, RANGELEN=0, VAL=-1, 100 */ -1, /* 100 */ /* line 5, PREFLEN=1, RANGELEN=0, VAL=1, 0 */ 0, /* 0 */ /* line 6, PREFLEN=3, RANGELEN=0, VAL=1, 101 */ 1, /* 101 */ /* line 7, PREFLEN=4, RANGELEN=0, VAL=2, 1101 */ 2, /* 1101 */ /* line 8, PREFLEN=5, RANGELEN=1, VAL=3..4, 11101+(VAL-3) */ 3, /* 11101 0 */ 4, /* 11101 1 */ /* line 9, PREFLEN=6, RANGELEN=2, VAL=5..8, 111101+(VAL-5) */ 5, /* 111101 00 */ 6, /* 111101 01 */ 7, /* 111101 10 */ 8, /* 111101 11 */ /* line 10, PREFLEN=7, RANGELEN=4, VAL=9..24, 1111101+(VAL-9) */ 9, /* 1111101 0000 */ 10, /* 1111101 0001 */ 23, /* 1111101 1110 */ 24, /* 1111101 1111 */ /* line 11, PREFLEN=7, RANGELEN=32, VAL=-INF..-25, 1111110+(-25-VAL) */ -25, /* 1111110 00000000 00000000 00000000 00000000 */ -26, /* 1111110 00000000 00000000 00000000 00000001 */ /* line 12, PREFLEN=7, RANGELEN=32, VAL=25..INF, 1111111+(VAL-25) */ 25, /* 1111111 00000000 00000000 00000000 00000000 */ 26, /* 1111111 00000000 00000000 00000000 00000001 */ }; const byte test_input_O[] = { /* 1111 1000 0001 1111 0000 0111 1110 0111 */ 0xf8, 0x1f, 0x07, 0xe7, /* 0111 1100 1111 1111 0000 1111 0001 1111 */ 0x7c, 0xff, 0x0f, 0x1f, /* 0010 1111 0011 1110 0011 1001 1100 1000 */ 0x2f, 0x3e, 0x39, 0xc8, /* 1011 1011 1101 0111 0111 1110 1001 1110 */ 0xbb, 0xd7, 0x7e, 0x9e, /* 1011 1110 1101 1110 1111 1111 0100 0011 */ 0xbe, 0xde, 0xff, 0x43, /* 1110 1000 1111 1101 1110 1111 1011 1111 */ 0xe8, 0xfd, 0xef, 0xbf, /* 1111 1000 0000 0000 0000 0000 0000 0000 */ 0xf8, 0x00, 0x00, 0x00, /* 0000 0011 1111 0000 0000 0000 0000 0000 */ 0x03, 0xf0, 0x00, 0x00, /* 0000 0000 0000 1111 1111 0000 0000 0000 */ 0x00, 0x0f, 0xf0, 0x00, /* 0000 0000 0000 0000 0000 1111 1110 0000 */ 0x00, 0x00, 0x0f, 0xe0, /* 0000 0000 0000 0000 0000 0000 001 */ 0x00, 0x00, 0x00, 0x20, }; typedef struct test_huffmancodes { const char *name; const Jbig2HuffmanParams *params; const byte *input; const size_t input_len; const int32_t *output; const size_t output_len; } test_huffmancodes_t; #define countof(x) (sizeof((x)) / sizeof((x)[0])) #define DEF_TEST_HUFFMANCODES(x) { \ #x, \ &jbig2_huffman_params_##x, \ test_input_##x, countof(test_input_##x), \ test_output_##x, countof(test_output_##x), \ } test_huffmancodes_t tests[] = { DEF_TEST_HUFFMANCODES(A), DEF_TEST_HUFFMANCODES(B), DEF_TEST_HUFFMANCODES(C), DEF_TEST_HUFFMANCODES(D), DEF_TEST_HUFFMANCODES(E), DEF_TEST_HUFFMANCODES(F), DEF_TEST_HUFFMANCODES(G), DEF_TEST_HUFFMANCODES(H), DEF_TEST_HUFFMANCODES(I), DEF_TEST_HUFFMANCODES(J), DEF_TEST_HUFFMANCODES(K), DEF_TEST_HUFFMANCODES(L), DEF_TEST_HUFFMANCODES(M), DEF_TEST_HUFFMANCODES(N), DEF_TEST_HUFFMANCODES(O), }; typedef struct test_stream { Jbig2WordStream ws; test_huffmancodes_t *h; } test_stream_t; static int test_get_word(Jbig2WordStream *self, int offset, uint32_t *word) { uint32_t val = 0; test_stream_t *st = (test_stream_t *) self; if (st != NULL) { if (st->h != NULL) { if (offset >= st->h->input_len) return -1; if (offset < st->h->input_len) { val |= (st->h->input[offset] << 24); } if (offset + 1 < st->h->input_len) { val |= (st->h->input[offset + 1] << 16); } if (offset + 2 < st->h->input_len) { val |= (st->h->input[offset + 2] << 8); } if (offset + 3 < st->h->input_len) { val |= st->h->input[offset + 3]; } } } *word = val; return 0; } int main(int argc, char **argv) { Jbig2Ctx *ctx = jbig2_ctx_new(NULL, 0, NULL, NULL, NULL); int i; for (i = 0; i < countof(tests); i++) { Jbig2HuffmanTable *table; Jbig2HuffmanState *hs; test_stream_t st; int32_t code; bool oob; int j; st.ws.get_next_word = test_get_word; st.h = &tests[i]; printf("testing Standard Huffman table %s: ", st.h->name); table = jbig2_build_huffman_table(ctx, st.h->params); if (table == NULL) { printf("jbig2_build_huffman_table() returned NULL!\n"); } else { /* jbig2_dump_huffman_table(table); */ hs = jbig2_huffman_new(ctx, &st.ws); if (hs == NULL) { printf("jbig2_huffman_new() returned NULL!\n"); } else { for (j = 0; j < st.h->output_len; j++) { printf("%d...", st.h->output[j]); code = jbig2_huffman_get(hs, table, &oob); if (code == st.h->output[j] && !oob) { printf("ok, "); } else { int need_comma = 0; printf("NG("); if (code != st.h->output[j]) { printf("%d", code); need_comma = 1; } if (oob) { if (need_comma) printf(","); printf("OOB"); } printf("), "); } } if (st.h->params->HTOOB) { printf("OOB..."); code = jbig2_huffman_get(hs, table, &oob); if (oob) { printf("ok"); } else { printf("NG(%d)", code); } } printf("\n"); jbig2_huffman_free(ctx, hs); } jbig2_release_huffman_table(ctx, table); } } jbig2_ctx_free(ctx); return 0; } #endif jbig2dec-0.13/jbig2_huffman.h000066400000000000000000000074411270170036400157660ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifndef JBIG2_HUFFMAN_H #define JBIG2_HUFFMAN_H /* Huffman coder interface */ typedef struct _Jbig2HuffmanEntry Jbig2HuffmanEntry; typedef struct _Jbig2HuffmanState Jbig2HuffmanState; typedef struct _Jbig2HuffmanTable Jbig2HuffmanTable; typedef struct _Jbig2HuffmanParams Jbig2HuffmanParams; struct _Jbig2HuffmanEntry { union { int32_t RANGELOW; Jbig2HuffmanTable *ext_table; } u; byte PREFLEN; byte RANGELEN; byte flags; }; struct _Jbig2HuffmanTable { int log_table_size; Jbig2HuffmanEntry *entries; }; typedef struct _Jbig2HuffmanLine Jbig2HuffmanLine; struct _Jbig2HuffmanLine { int PREFLEN; int RANGELEN; int RANGELOW; }; struct _Jbig2HuffmanParams { bool HTOOB; int n_lines; const Jbig2HuffmanLine *lines; }; Jbig2HuffmanState *jbig2_huffman_new(Jbig2Ctx *ctx, Jbig2WordStream *ws); void jbig2_huffman_free(Jbig2Ctx *ctx, Jbig2HuffmanState *hs); void jbig2_huffman_skip(Jbig2HuffmanState *hs); void jbig2_huffman_advance(Jbig2HuffmanState *hs, int offset); int jbig2_huffman_offset(Jbig2HuffmanState *hs); int32_t jbig2_huffman_get(Jbig2HuffmanState *hs, const Jbig2HuffmanTable *table, bool *oob); int32_t jbig2_huffman_get_bits(Jbig2HuffmanState *hs, const int bits, int *err); #ifdef JBIG2_DEBUG void jbig2_dump_huffman_state(Jbig2HuffmanState *hs); void jbig2_dump_huffman_binary(Jbig2HuffmanState *hs); #endif Jbig2HuffmanTable *jbig2_build_huffman_table(Jbig2Ctx *ctx, const Jbig2HuffmanParams *params); void jbig2_release_huffman_table(Jbig2Ctx *ctx, Jbig2HuffmanTable *table); /* standard Huffman templates defined by the specification */ extern const Jbig2HuffmanParams jbig2_huffman_params_A; /* Table B.1 */ extern const Jbig2HuffmanParams jbig2_huffman_params_B; /* Table B.2 */ extern const Jbig2HuffmanParams jbig2_huffman_params_C; /* Table B.3 */ extern const Jbig2HuffmanParams jbig2_huffman_params_D; /* Table B.4 */ extern const Jbig2HuffmanParams jbig2_huffman_params_E; /* Table B.5 */ extern const Jbig2HuffmanParams jbig2_huffman_params_F; /* Table B.6 */ extern const Jbig2HuffmanParams jbig2_huffman_params_G; /* Table B.7 */ extern const Jbig2HuffmanParams jbig2_huffman_params_H; /* Table B.8 */ extern const Jbig2HuffmanParams jbig2_huffman_params_I; /* Table B.9 */ extern const Jbig2HuffmanParams jbig2_huffman_params_J; /* Table B.10 */ extern const Jbig2HuffmanParams jbig2_huffman_params_K; /* Table B.11 */ extern const Jbig2HuffmanParams jbig2_huffman_params_L; /* Table B.12 */ extern const Jbig2HuffmanParams jbig2_huffman_params_M; /* Table B.13 */ extern const Jbig2HuffmanParams jbig2_huffman_params_N; /* Table B.14 */ extern const Jbig2HuffmanParams jbig2_huffman_params_O; /* Table B.15 */ /* Routines to handle "code table segment (53)" */ /* Parse a code table segment, store Jbig2HuffmanParams in segment->result */ int jbig2_table(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data); /* free Jbig2HuffmanParams allocated by jbig2_huffman_table() */ void jbig2_table_free(Jbig2Ctx *ctx, Jbig2HuffmanParams *params); /* find a user supplied table used by 'segment' and by 'index' */ const Jbig2HuffmanParams *jbig2_find_table(Jbig2Ctx *ctx, Jbig2Segment *segment, int index); #endif /* JBIG2_HUFFMAN_H */ jbig2dec-0.13/jbig2_hufftab.h000066400000000000000000000172611270170036400157620ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* predefined Huffman table definitions -- See Annex B of the JBIG2 specification */ #ifndef JBIG2_HUFFTAB_H #define JBIG2_HUFFTAB_H /* types are in jbig2_huffman.h, you must include that first */ #define JBIG2_COUNTOF(x) (sizeof((x)) / sizeof((x)[0])) /* Table B.1 */ const Jbig2HuffmanLine jbig2_huffman_lines_A[] = { {1, 4, 0}, {2, 8, 16}, {3, 16, 272}, {0, 32, -1}, /* low */ {3, 32, 65808} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_A = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_A), jbig2_huffman_lines_A }; /* Table B.2 */ const Jbig2HuffmanLine jbig2_huffman_lines_B[] = { {1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 3, 3}, {5, 6, 11}, {0, 32, -1}, /* low */ {6, 32, 75}, /* high */ {6, 0, 0} /* OOB */ }; const Jbig2HuffmanParams jbig2_huffman_params_B = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_B), jbig2_huffman_lines_B }; /* Table B.3 */ const Jbig2HuffmanLine jbig2_huffman_lines_C[] = { {8, 8, -256}, {1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 3, 3}, {5, 6, 11}, {8, 32, -257}, /* low */ {7, 32, 75}, /* high */ {6, 0, 0} /* OOB */ }; const Jbig2HuffmanParams jbig2_huffman_params_C = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_C), jbig2_huffman_lines_C }; /* Table B.4 */ const Jbig2HuffmanLine jbig2_huffman_lines_D[] = { {1, 0, 1}, {2, 0, 2}, {3, 0, 3}, {4, 3, 4}, {5, 6, 12}, {0, 32, -1}, /* low */ {5, 32, 76}, /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_D = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_D), jbig2_huffman_lines_D }; /* Table B.5 */ const Jbig2HuffmanLine jbig2_huffman_lines_E[] = { {7, 8, -255}, {1, 0, 1}, {2, 0, 2}, {3, 0, 3}, {4, 3, 4}, {5, 6, 12}, {7, 32, -256}, /* low */ {6, 32, 76} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_E = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_E), jbig2_huffman_lines_E }; /* Table B.6 */ const Jbig2HuffmanLine jbig2_huffman_lines_F[] = { {5, 10, -2048}, {4, 9, -1024}, {4, 8, -512}, {4, 7, -256}, {5, 6, -128}, {5, 5, -64}, {4, 5, -32}, {2, 7, 0}, {3, 7, 128}, {3, 8, 256}, {4, 9, 512}, {4, 10, 1024}, {6, 32, -2049}, /* low */ {6, 32, 2048} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_F = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_F), jbig2_huffman_lines_F }; /* Table B.7 */ const Jbig2HuffmanLine jbig2_huffman_lines_G[] = { {4, 9, -1024}, {3, 8, -512}, {4, 7, -256}, {5, 6, -128}, {5, 5, -64}, {4, 5, -32}, {4, 5, 0}, {5, 5, 32}, {5, 6, 64}, {4, 7, 128}, {3, 8, 256}, {3, 9, 512}, {3, 10, 1024}, {5, 32, -1025}, /* low */ {5, 32, 2048} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_G = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_G), jbig2_huffman_lines_G }; /* Table B.8 */ const Jbig2HuffmanLine jbig2_huffman_lines_H[] = { {8, 3, -15}, {9, 1, -7}, {8, 1, -5}, {9, 0, -3}, {7, 0, -2}, {4, 0, -1}, {2, 1, 0}, {5, 0, 2}, {6, 0, 3}, {3, 4, 4}, {6, 1, 20}, {4, 4, 22}, {4, 5, 38}, {5, 6, 70}, {5, 7, 134}, {6, 7, 262}, {7, 8, 390}, {6, 10, 646}, {9, 32, -16}, /* low */ {9, 32, 1670}, /* high */ {2, 0, 0} /* OOB */ }; const Jbig2HuffmanParams jbig2_huffman_params_H = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_H), jbig2_huffman_lines_H }; /* Table B.9 */ const Jbig2HuffmanLine jbig2_huffman_lines_I[] = { {8, 4, -31}, {9, 2, -15}, {8, 2, -11}, {9, 1, -7}, {7, 1, -5}, {4, 1, -3}, {3, 1, -1}, {3, 1, 1}, {5, 1, 3}, {6, 1, 5}, {3, 5, 7}, {6, 2, 39}, {4, 5, 43}, {4, 6, 75}, {5, 7, 139}, {5, 8, 267}, {6, 8, 523}, {7, 9, 779}, {6, 11, 1291}, {9, 32, -32}, /* low */ {9, 32, 3339}, /* high */ {2, 0, 0} /* OOB */ }; const Jbig2HuffmanParams jbig2_huffman_params_I = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_I), jbig2_huffman_lines_I }; /* Table B.10 */ const Jbig2HuffmanLine jbig2_huffman_lines_J[] = { {7, 4, -21}, {8, 0, -5}, {7, 0, -4}, {5, 0, -3}, {2, 2, -2}, {5, 0, 2}, {6, 0, 3}, {7, 0, 4}, {8, 0, 5}, {2, 6, 6}, {5, 5, 70}, {6, 5, 102}, {6, 6, 134}, {6, 7, 198}, {6, 8, 326}, {6, 9, 582}, {6, 10, 1094}, {7, 11, 2118}, {8, 32, -22}, /* low */ {8, 32, 4166}, /* high */ {2, 0, 0} /* OOB */ }; const Jbig2HuffmanParams jbig2_huffman_params_J = { TRUE, JBIG2_COUNTOF(jbig2_huffman_lines_J), jbig2_huffman_lines_J }; /* Table B.11 */ const Jbig2HuffmanLine jbig2_huffman_lines_K[] = { {1, 0, 1}, {2, 1, 2}, {4, 0, 4}, {4, 1, 5}, {5, 1, 7}, {5, 2, 9}, {6, 2, 13}, {7, 2, 17}, {7, 3, 21}, {7, 4, 29}, {7, 5, 45}, {7, 6, 77}, {0, 32, -1}, /* low */ {7, 32, 141} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_K = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_K), jbig2_huffman_lines_K }; /* Table B.12 */ const Jbig2HuffmanLine jbig2_huffman_lines_L[] = { {1, 0, 1}, {2, 0, 2}, {3, 1, 3}, {5, 0, 5}, {5, 1, 6}, {6, 1, 8}, {7, 0, 10}, {7, 1, 11}, {7, 2, 13}, {7, 3, 17}, {7, 4, 25}, {8, 5, 41}, {8, 32, 73}, {0, 32, -1}, /* low */ {0, 32, 0} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_L = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_L), jbig2_huffman_lines_L }; /* Table B.13 */ const Jbig2HuffmanLine jbig2_huffman_lines_M[] = { {1, 0, 1}, {3, 0, 2}, {4, 0, 3}, {5, 0, 4}, {4, 1, 5}, {3, 3, 7}, {6, 1, 15}, {6, 2, 17}, {6, 3, 21}, {6, 4, 29}, {6, 5, 45}, {7, 6, 77}, {0, 32, -1}, /* low */ {7, 32, 141} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_M = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_M), jbig2_huffman_lines_M }; /* Table B.14 */ const Jbig2HuffmanLine jbig2_huffman_lines_N[] = { {3, 0, -2}, {3, 0, -1}, {1, 0, 0}, {3, 0, 1}, {3, 0, 2}, {0, 32, -1}, /* low */ {0, 32, 3}, /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_N = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_N), jbig2_huffman_lines_N }; /* Table B.15 */ const Jbig2HuffmanLine jbig2_huffman_lines_O[] = { {7, 4, -24}, {6, 2, -8}, {5, 1, -4}, {4, 0, -2}, {3, 0, -1}, {1, 0, 0}, {3, 0, 1}, {4, 0, 2}, {5, 1, 3}, {6, 2, 5}, {7, 4, 9}, {7, 32, -25}, /* low */ {7, 32, 25} /* high */ }; const Jbig2HuffmanParams jbig2_huffman_params_O = { FALSE, JBIG2_COUNTOF(jbig2_huffman_lines_O), jbig2_huffman_lines_O }; #undef JBIG2_COUNTOF #endif /* JBIG2_HUFFTAB_H */ jbig2dec-0.13/jbig2_image.c000066400000000000000000000243341270170036400154170ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include /* memcpy() */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_image.h" /* allocate a Jbig2Image structure and its associated bitmap */ Jbig2Image * jbig2_image_new(Jbig2Ctx *ctx, int width, int height) { Jbig2Image *image; int stride; int64_t check; image = jbig2_new(ctx, Jbig2Image, 1); if (image == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not allocate image structure in jbig2_image_new"); return NULL; } stride = ((width - 1) >> 3) + 1; /* generate a byte-aligned stride */ /* check for integer multiplication overflow */ check = ((int64_t) stride) * ((int64_t) height); if (check != (int)check) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow from stride(%d)*height(%d)", stride, height); jbig2_free(ctx->allocator, image); return NULL; } /* Add 1 to accept runs that exceed image width and clamped to width+1 */ image->data = jbig2_new(ctx, uint8_t, (int)check + 1); if (image->data == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not allocate image data buffer! [stride(%d)*height(%d) bytes]", stride, height); jbig2_free(ctx->allocator, image); return NULL; } image->width = width; image->height = height; image->stride = stride; image->refcount = 1; return image; } /* clone an image pointer by bumping its reference count */ Jbig2Image * jbig2_image_clone(Jbig2Ctx *ctx, Jbig2Image *image) { if (image) image->refcount++; return image; } /* release an image pointer, freeing it it appropriate */ void jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image) { if (image == NULL) return; image->refcount--; if (!image->refcount) jbig2_image_free(ctx, image); } /* free a Jbig2Image structure and its associated memory */ void jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image) { if (image) jbig2_free(ctx->allocator, image->data); jbig2_free(ctx->allocator, image); } /* resize a Jbig2Image */ Jbig2Image * jbig2_image_resize(Jbig2Ctx *ctx, Jbig2Image *image, int width, int height) { if (width == image->width) { /* check for integer multiplication overflow */ int64_t check = ((int64_t) image->stride) * ((int64_t) height); if (check != (int)check) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "integer multiplication overflow during resize stride(%d)*height(%d)", image->stride, height); return NULL; } /* use the same stride, just change the length */ image->data = jbig2_renew(ctx, image->data, uint8_t, (int)check); if (image->data == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not resize image buffer!"); return NULL; } if (height > image->height) { memset(image->data + image->height * image->stride, 0, (height - image->height) * image->stride); } image->height = height; } else { /* we must allocate a new image buffer and copy */ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "jbig2_image_resize called with a different width (NYI)"); } return NULL; } /* composite one jbig2_image onto another slow but general version */ static int jbig2_image_compose_unopt(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op) { int i, j; int sw = src->width; int sh = src->height; int sx = 0; int sy = 0; /* clip to the dst image boundaries */ if (x < 0) { sx += -x; sw -= -x; x = 0; } if (y < 0) { sy += -y; sh -= -y; y = 0; } if (x + sw >= dst->width) sw = dst->width - x; if (y + sh >= dst->height) sh = dst->height - y; switch (op) { case JBIG2_COMPOSE_OR: for (j = 0; j < sh; j++) { for (i = 0; i < sw; i++) { jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) | jbig2_image_get_pixel(dst, i + x, j + y)); } } break; case JBIG2_COMPOSE_AND: for (j = 0; j < sh; j++) { for (i = 0; i < sw; i++) { jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) & jbig2_image_get_pixel(dst, i + x, j + y)); } } break; case JBIG2_COMPOSE_XOR: for (j = 0; j < sh; j++) { for (i = 0; i < sw; i++) { jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy) ^ jbig2_image_get_pixel(dst, i + x, j + y)); } } break; case JBIG2_COMPOSE_XNOR: for (j = 0; j < sh; j++) { for (i = 0; i < sw; i++) { jbig2_image_set_pixel(dst, i + x, j + y, (jbig2_image_get_pixel(src, i + sx, j + sy) == jbig2_image_get_pixel(dst, i + x, j + y))); } } break; case JBIG2_COMPOSE_REPLACE: for (j = 0; j < sh; j++) { for (i = 0; i < sw; i++) { jbig2_image_set_pixel(dst, i + x, j + y, jbig2_image_get_pixel(src, i + sx, j + sy)); } } break; } return 0; } /* composite one jbig2_image onto another */ int jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op) { int i, j; int w, h; int leftbyte, rightbyte; int shift; uint8_t *s, *ss; uint8_t *d, *dd; uint8_t mask, rightmask; if (op != JBIG2_COMPOSE_OR) { /* hand off the the general routine */ return jbig2_image_compose_unopt(ctx, dst, src, x, y, op); } /* clip */ w = src->width; h = src->height; ss = src->data; if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } w = (x + w < dst->width) ? w : dst->width - x; h = (y + h < dst->height) ? h : dst->height - y; #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "compositing %dx%d at (%d, %d) after clipping\n", w, h, x, y); #endif /* check for zero clipping region */ if ((w <= 0) || (h <= 0)) { #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "zero clipping region"); #endif return 0; } #if 0 /* special case complete/strip replacement */ /* disabled because it's only safe to do when the destination buffer is all-blank. */ if ((x == 0) && (w == src->width)) { memcpy(dst->data + y * dst->stride, src->data, h * src->stride); return 0; } #endif leftbyte = x >> 3; rightbyte = (x + w - 1) >> 3; shift = x & 7; /* general OR case */ s = ss; d = dd = dst->data + y * dst->stride + leftbyte; if (d < dst->data || leftbyte > dst->stride || h * dst->stride < 0 || d - leftbyte + h * dst->stride > dst->data + dst->height * dst->stride) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "preventing heap overflow in jbig2_image_compose"); } if (leftbyte == rightbyte) { mask = 0x100 - (0x100 >> w); for (j = 0; j < h; j++) { *d |= (*s & mask) >> shift; d += dst->stride; s += src->stride; } } else if (shift == 0) { rightmask = (w & 7) ? 0x100 - (1 << (8 - (w & 7))) : 0xFF; for (j = 0; j < h; j++) { for (i = leftbyte; i < rightbyte; i++) *d++ |= *s++; *d |= *s & rightmask; d = (dd += dst->stride); s = (ss += src->stride); } } else { bool overlap = (((w + 7) >> 3) < ((x + w + 7) >> 3) - (x >> 3)); mask = 0x100 - (1 << shift); if (overlap) rightmask = (0x100 - (0x100 >> ((x + w) & 7))) >> (8 - shift); else rightmask = 0x100 - (0x100 >> (w & 7)); for (j = 0; j < h; j++) { *d++ |= (*s & mask) >> shift; for (i = leftbyte; i < rightbyte - 1; i++) { *d |= ((*s++ & ~mask) << (8 - shift)); *d++ |= ((*s & mask) >> shift); } if (overlap) *d |= (*s & rightmask) << (8 - shift); else *d |= ((s[0] & ~mask) << (8 - shift)) | ((s[1] & rightmask) >> shift); d = (dd += dst->stride); s = (ss += src->stride); } } return 0; } /* initialize an image bitmap to a constant value */ void jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value) { const uint8_t fill = value ? 0xFF : 0x00; memset(image->data, fill, image->stride * image->height); } /* look up a pixel value in an image. returns 0 outside the image frame for the convenience of the template code */ int jbig2_image_get_pixel(Jbig2Image *image, int x, int y) { const int w = image->width; const int h = image->height; const int byte = (x >> 3) + y * image->stride; const int bit = 7 - (x & 7); if ((x < 0) || (x >= w)) return 0; if ((y < 0) || (y >= h)) return 0; return ((image->data[byte] >> bit) & 1); } /* set an individual pixel value in an image */ int jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value) { const int w = image->width; const int h = image->height; int scratch, mask; int bit, byte; if ((x < 0) || (x >= w)) return 0; if ((y < 0) || (y >= h)) return 0; byte = (x >> 3) + y * image->stride; bit = 7 - (x & 7); mask = (1 << bit) ^ 0xff; scratch = image->data[byte] & mask; image->data[byte] = scratch | (value << bit); return 1; } jbig2dec-0.13/jbig2_image.h000066400000000000000000000025111270170036400154150ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifndef _JBIG2_IMAGE_H #define _JBIG2_IMAGE_H int jbig2_image_get_pixel(Jbig2Image *image, int x, int y); int jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value); /* routines for dumping the image data in various formats */ /* FIXME: should these be in the client instead? */ #include int jbig2_image_write_pbm_file(Jbig2Image *image, char *filename); int jbig2_image_write_pbm(Jbig2Image *image, FILE *out); Jbig2Image *jbig2_image_read_pbm_file(Jbig2Ctx *ctx, char *filename); Jbig2Image *jbig2_image_read_pbm(Jbig2Ctx *ctx, FILE *in); #ifdef HAVE_LIBPNG int jbig2_image_write_png_file(Jbig2Image *image, char *filename); int jbig2_image_write_png(Jbig2Image *image, FILE *out); #endif #endif /* _JBIG2_IMAGE_H */ jbig2dec-0.13/jbig2_image_pbm.c000066400000000000000000000102671270170036400162550ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_image.h" /* take an image structure and write it to a file in pbm format */ int jbig2_image_write_pbm_file(Jbig2Image *image, char *filename) { FILE *out; int error; if ((out = fopen(filename, "wb")) == NULL) { fprintf(stderr, "unable to open '%s' for writing", filename); return 1; } error = jbig2_image_write_pbm(image, out); fclose(out); return (error); } /* write out an image struct as a pbm stream to an open file pointer */ int jbig2_image_write_pbm(Jbig2Image *image, FILE *out) { /* pbm header */ fprintf(out, "P4\n%d %d\n", image->width, image->height); /* pbm format pads to a byte boundary, so we can just write out the whole data buffer NB: this assumes minimal stride for the width */ fwrite(image->data, 1, image->height * image->stride, out); /* success */ return 0; } /* take an image from a file in pbm format */ Jbig2Image * jbig2_image_read_pbm_file(Jbig2Ctx *ctx, char *filename) { FILE *in; Jbig2Image *image; if ((in = fopen(filename, "rb")) == NULL) { fprintf(stderr, "unable to open '%s' for reading\n", filename); return NULL; } image = jbig2_image_read_pbm(ctx, in); fclose(in); return (image); } /* FIXME: should handle multi-image files */ Jbig2Image * jbig2_image_read_pbm(Jbig2Ctx *ctx, FILE *in) { int i, dim[2]; int done; Jbig2Image *image; int c; char buf[32]; /* look for 'P4' magic */ while ((c = fgetc(in)) != 'P') { if (feof(in)) return NULL; } if ((c = fgetc(in)) != '4') { fprintf(stderr, "not a binary pbm file.\n"); return NULL; } /* read size. we must find two decimal numbers representing the image dimensions. 'done' will index whether we're looking for the width or the height and 'i' will be our array index for copying strings into our buffer */ done = 0; i = 0; while (done < 2) { c = fgetc(in); /* skip whitespace */ if (c == ' ' || c == '\t' || c == '\r' || c == '\n') continue; /* skip comments */ if (c == '#') { while ((c = fgetc(in)) != '\n'); continue; } /* report unexpected eof */ if (c == EOF) { fprintf(stderr, "end-of-file parsing pbm header\n"); return NULL; } if (isdigit(c)) { buf[i++] = c; while (isdigit(c = fgetc(in))) { if (i >= 32) { fprintf(stderr, "pbm parsing error\n"); return NULL; } buf[i++] = c; } buf[i] = '\0'; if (sscanf(buf, "%d", &dim[done]) != 1) { fprintf(stderr, "couldn't read pbm image dimensions\n"); return NULL; } i = 0; done++; } } /* allocate image structure */ image = jbig2_image_new(ctx, dim[0], dim[1]); if (image == NULL) { fprintf(stderr, "could not allocate %dx%d image for pbm file\n", dim[0], dim[1]); return NULL; } /* the pbm data is byte-aligned, so we can do a simple block read */ (void)fread(image->data, 1, image->height * image->stride, in); if (feof(in)) { fprintf(stderr, "unexpected end of pbm file.\n"); jbig2_image_release(ctx, image); return NULL; } /* success */ return image; } jbig2dec-0.13/jbig2_image_png.c000066400000000000000000000074251270170036400162650ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include #ifndef OLD_LIB_PNG # if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 2 # define OLD_LIB_PNG 1 # else # define OLD_LIB_PNG 0 # endif #endif #if OLD_LIB_PNG #include #endif #define CVT_PTR(ptr) (ptr) #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_image.h" /* take an image structure and write it out in png format */ static void jbig2_png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { png_size_t check; #if OLD_LIB_PNG png_FILE_p f = (png_FILE_p) png_ptr->io_ptr; #else png_FILE_p f = (png_FILE_p) png_get_io_ptr(png_ptr); #endif check = fwrite(data, 1, length, f); if (check != length) { png_error(png_ptr, "Write Error"); } } static void jbig2_png_flush(png_structp png_ptr) { #if OLD_LIB_PNG png_FILE_p f = (png_FILE_p) png_ptr->io_ptr; #else png_FILE_p f = (png_FILE_p) png_get_io_ptr(png_ptr); #endif if (f != NULL) fflush(f); } int jbig2_image_write_png_file(Jbig2Image *image, char *filename) { FILE *out; int error; if ((out = fopen(filename, "wb")) == NULL) { fprintf(stderr, "unable to open '%s' for writing\n", filename); return 1; } error = jbig2_image_write_png(image, out); fclose(out); return (error); } /* write out an image struct in png format to an open file pointer */ int jbig2_image_write_png(Jbig2Image *image, FILE *out) { int i; png_structp png; png_infop info; png_bytep rowpointer; png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { fprintf(stderr, "unable to create png structure\n"); return 2; } info = png_create_info_struct(png); if (info == NULL) { fprintf(stderr, "unable to create png info structure\n"); png_destroy_write_struct(&png, (png_infopp) NULL); return 3; } /* set/check error handling */ if (setjmp(png_jmpbuf(png))) { /* we've returned here after an internal error */ fprintf(stderr, "internal error in libpng saving file\n"); png_destroy_write_struct(&png, &info); return 4; } /* png_init_io() doesn't work linking dynamically to libpng on win32 one has to either link statically or use callbacks because of runtime variations */ /* png_init_io(png, out); */ png_set_write_fn(png, (png_voidp) out, jbig2_png_write_data, jbig2_png_flush); /* now we fill out the info structure with our format data */ png_set_IHDR(png, info, image->width, image->height, 1, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png, info); /* png natively treates 0 as black. This will convert for us */ png_set_invert_mono(png); /* write out each row in turn */ rowpointer = (png_bytep) image->data; for (i = 0; i < image->height; i++) { png_write_row(png, rowpointer); rowpointer += image->stride; } /* finish and clean up */ png_write_end(png, info); png_destroy_write_struct(&png, &info); return 0; } jbig2dec-0.13/jbig2_metadata.c000066400000000000000000000113621270170036400161120ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_metadata.h" /* metadata key,value list object */ Jbig2Metadata * jbig2_metadata_new(Jbig2Ctx *ctx, Jbig2Encoding encoding) { Jbig2Metadata *md = jbig2_new(ctx, Jbig2Metadata, 1); if (md != NULL) { md->encoding = encoding; md->entries = 0; md->max_entries = 4; md->keys = jbig2_new(ctx, char *, md->max_entries); md->values = jbig2_new(ctx, char *, md->max_entries); if (md->keys == NULL || md->values == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate storage for metadata keys/values"); jbig2_metadata_free(ctx, md); md = NULL; } } else { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate storage for metadata"); } return md; } void jbig2_metadata_free(Jbig2Ctx *ctx, Jbig2Metadata *md) { int i; if (md->keys) { /* assume we own the pointers */ for (i = 0; i < md->entries; i++) jbig2_free(ctx->allocator, md->keys[i]); jbig2_free(ctx->allocator, md->keys); } if (md->values) { for (i = 0; i < md->entries; i++) jbig2_free(ctx->allocator, md->values[i]); jbig2_free(ctx->allocator, md->values); } jbig2_free(ctx->allocator, md); } static char * jbig2_strndup(Jbig2Ctx *ctx, const char *c, const int len) { char *s = jbig2_new(ctx, char, len); if (s == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to duplicate comment string"); } else { memcpy(s, c, len); } return s; } int jbig2_metadata_add(Jbig2Ctx *ctx, Jbig2Metadata *md, const char *key, const int key_length, const char *value, const int value_length) { char **keys, **values; /* grow the array if necessary */ if (md->entries == md->max_entries) { md->max_entries <<= 1; keys = jbig2_renew(ctx, md->keys, char *, md->max_entries); values = jbig2_renew(ctx, md->values, char *, md->max_entries); if (keys == NULL || values == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to resize metadata structure"); return -1; } md->keys = keys; md->values = values; } /* copy the passed key,value pair */ md->keys[md->entries] = jbig2_strndup(ctx, key, key_length); md->values[md->entries] = jbig2_strndup(ctx, value, value_length); md->entries++; return 0; } /* decode an ascii comment segment 7.4.15.1 */ int jbig2_comment_ascii(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { char *s = (char *)(segment_data + 4); char *end = (char *)(segment_data + segment->data_length); Jbig2Metadata *comment; char *key, *value; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "ASCII comment data"); comment = jbig2_metadata_new(ctx, JBIG2_ENCODING_ASCII); if (comment == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to allocate comment structure"); return -1; } /* loop over the segment data pulling out the key,value pairs */ while (s < end && *s) { key = s; value = memchr(key, '\0', end - key); if (!value) goto too_short; value++; s = memchr(value, '\0', end - value); if (!s) goto too_short; s++; jbig2_metadata_add(ctx, comment, key, value - key, value, s - value); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "'%s'\t'%s'", key, value); } /* TODO: associate with ctx, page, or referred-to segment(s) */ segment->result = comment; return 0; too_short: jbig2_metadata_free(ctx, comment); return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unexpected end of comment segment"); } /* decode a UCS-16 comment segement 7.4.15.2 */ int jbig2_comment_unicode(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled unicode comment segment"); } jbig2dec-0.13/jbig2_metadata.h000066400000000000000000000030021270170036400161070ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifndef _JBIG2_METADATA_H #define _JBIG2_METADATA_H /* metadata from extension segments */ /* these bits should be moved to jbig2.h for public access */ typedef enum { JBIG2_ENCODING_ASCII, JBIG2_ENCODING_UCS16 } Jbig2Encoding; typedef struct _Jbig2Metadata Jbig2Metadata; Jbig2Metadata *jbig2_metadata_new(Jbig2Ctx *ctx, Jbig2Encoding encoding); void jbig2_metadata_free(Jbig2Ctx *ctx, Jbig2Metadata *md); int jbig2_metadata_add(Jbig2Ctx *ctx, Jbig2Metadata *md, const char *key, const int key_length, const char *value, const int value_length); struct _Jbig2Metadata { Jbig2Encoding encoding; char **keys, * *values; int entries, max_entries; }; /* these bits can go to jbig2_priv.h */ int jbig2_comment_ascii(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); int jbig2_comment_unicode(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); #endif /* _JBIG2_METADATA_H */ jbig2dec-0.13/jbig2_mmr.c000066400000000000000000000477161270170036400151410ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* An implementation of MMR decoding. This is based on the implementation in Fitz, which in turn is based on the one in Ghostscript. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include #include #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_generic.h" #include "jbig2_mmr.h" typedef struct { int width; int height; const byte *data; size_t size; int data_index; int bit_index; uint32_t word; } Jbig2MmrCtx; static void jbig2_decode_mmr_init(Jbig2MmrCtx *mmr, int width, int height, const byte *data, size_t size) { int i; uint32_t word = 0; mmr->width = width; mmr->height = height; mmr->data = data; mmr->size = size; mmr->data_index = 0; mmr->bit_index = 0; for (i = 0; i < size && i < 4; i++) word |= (data[i] << ((3 - i) << 3)); mmr->word = word; } static void jbig2_decode_mmr_consume(Jbig2MmrCtx *mmr, int n_bits) { mmr->word <<= n_bits; mmr->bit_index += n_bits; while (mmr->bit_index >= 8) { mmr->bit_index -= 8; if (mmr->data_index + 4 < mmr->size) mmr->word |= (mmr->data[mmr->data_index + 4] << mmr->bit_index); mmr->data_index++; } } /* the first 2^(initialbits) entries map bit patterns to decodes let's say initial_bits is 8 for the sake of example and that the code is 1001 that means that entries 0x90 .. 0x9f have the entry { val, 4 } because those are all the bytes that start with the code and the 4 is the length of the code ... if (n_bits > initial_bits) ... anyway, in that case, it basically points to a mini table the n_bits is the maximum length of all codes beginning with that byte so 2^(n_bits - initial_bits) is the size of the mini-table peter came up with this, and it makes sense */ typedef struct { short val; short n_bits; } mmr_table_node; /* white decode table (runlength huffman codes) */ const mmr_table_node jbig2_mmr_white_decode[] = { {256, 12}, {272, 12}, {29, 8}, {30, 8}, {45, 8}, {46, 8}, {22, 7}, {22, 7}, {23, 7}, {23, 7}, {47, 8}, {48, 8}, {13, 6}, {13, 6}, {13, 6}, {13, 6}, {20, 7}, {20, 7}, {33, 8}, {34, 8}, {35, 8}, {36, 8}, {37, 8}, {38, 8}, {19, 7}, {19, 7}, {31, 8}, {32, 8}, {1, 6}, {1, 6}, {1, 6}, {1, 6}, {12, 6}, {12, 6}, {12, 6}, {12, 6}, {53, 8}, {54, 8}, {26, 7}, {26, 7}, {39, 8}, {40, 8}, {41, 8}, {42, 8}, {43, 8}, {44, 8}, {21, 7}, {21, 7}, {28, 7}, {28, 7}, {61, 8}, {62, 8}, {63, 8}, {0, 8}, {320, 8}, {384, 8}, {10, 5}, {10, 5}, {10, 5}, {10, 5}, {10, 5}, {10, 5}, {10, 5}, {10, 5}, {11, 5}, {11, 5}, {11, 5}, {11, 5}, {11, 5}, {11, 5}, {11, 5}, {11, 5}, {27, 7}, {27, 7}, {59, 8}, {60, 8}, {288, 9}, {290, 9}, {18, 7}, {18, 7}, {24, 7}, {24, 7}, {49, 8}, {50, 8}, {51, 8}, {52, 8}, {25, 7}, {25, 7}, {55, 8}, {56, 8}, {57, 8}, {58, 8}, {192, 6}, {192, 6}, {192, 6}, {192, 6}, {1664, 6}, {1664, 6}, {1664, 6}, {1664, 6}, {448, 8}, {512, 8}, {292, 9}, {640, 8}, {576, 8}, {294, 9}, {296, 9}, {298, 9}, {300, 9}, {302, 9}, {256, 7}, {256, 7}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {128, 5}, {128, 5}, {128, 5}, {128, 5}, {128, 5}, {128, 5}, {128, 5}, {128, 5}, {8, 5}, {8, 5}, {8, 5}, {8, 5}, {8, 5}, {8, 5}, {8, 5}, {8, 5}, {9, 5}, {9, 5}, {9, 5}, {9, 5}, {9, 5}, {9, 5}, {9, 5}, {9, 5}, {16, 6}, {16, 6}, {16, 6}, {16, 6}, {17, 6}, {17, 6}, {17, 6}, {17, 6}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {64, 5}, {64, 5}, {64, 5}, {64, 5}, {64, 5}, {64, 5}, {64, 5}, {64, 5}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {-2, 3}, {-2, 3}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-3, 4}, {1792, 3}, {1792, 3}, {1984, 4}, {2048, 4}, {2112, 4}, {2176, 4}, {2240, 4}, {2304, 4}, {1856, 3}, {1856, 3}, {1920, 3}, {1920, 3}, {2368, 4}, {2432, 4}, {2496, 4}, {2560, 4}, {1472, 1}, {1536, 1}, {1600, 1}, {1728, 1}, {704, 1}, {768, 1}, {832, 1}, {896, 1}, {960, 1}, {1024, 1}, {1088, 1}, {1152, 1}, {1216, 1}, {1280, 1}, {1344, 1}, {1408, 1} }; /* black decode table (runlength huffman codes) */ const mmr_table_node jbig2_mmr_black_decode[] = { {128, 12}, {160, 13}, {224, 12}, {256, 12}, {10, 7}, {11, 7}, {288, 12}, {12, 7}, {9, 6}, {9, 6}, {8, 6}, {8, 6}, {7, 5}, {7, 5}, {7, 5}, {7, 5}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {6, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {3, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {-2, 4}, {-2, 4}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-3, 5}, {1792, 4}, {1792, 4}, {1984, 5}, {2048, 5}, {2112, 5}, {2176, 5}, {2240, 5}, {2304, 5}, {1856, 4}, {1856, 4}, {1920, 4}, {1920, 4}, {2368, 5}, {2432, 5}, {2496, 5}, {2560, 5}, {18, 3}, {18, 3}, {18, 3}, {18, 3}, {18, 3}, {18, 3}, {18, 3}, {18, 3}, {52, 5}, {52, 5}, {640, 6}, {704, 6}, {768, 6}, {832, 6}, {55, 5}, {55, 5}, {56, 5}, {56, 5}, {1280, 6}, {1344, 6}, {1408, 6}, {1472, 6}, {59, 5}, {59, 5}, {60, 5}, {60, 5}, {1536, 6}, {1600, 6}, {24, 4}, {24, 4}, {24, 4}, {24, 4}, {25, 4}, {25, 4}, {25, 4}, {25, 4}, {1664, 6}, {1728, 6}, {320, 5}, {320, 5}, {384, 5}, {384, 5}, {448, 5}, {448, 5}, {512, 6}, {576, 6}, {53, 5}, {53, 5}, {54, 5}, {54, 5}, {896, 6}, {960, 6}, {1024, 6}, {1088, 6}, {1152, 6}, {1216, 6}, {64, 3}, {64, 3}, {64, 3}, {64, 3}, {64, 3}, {64, 3}, {64, 3}, {64, 3}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {13, 1}, {23, 4}, {23, 4}, {50, 5}, {51, 5}, {44, 5}, {45, 5}, {46, 5}, {47, 5}, {57, 5}, {58, 5}, {61, 5}, {256, 5}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {17, 3}, {17, 3}, {17, 3}, {17, 3}, {48, 5}, {49, 5}, {62, 5}, {63, 5}, {30, 5}, {31, 5}, {32, 5}, {33, 5}, {40, 5}, {41, 5}, {22, 4}, {22, 4}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {14, 1}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {128, 5}, {192, 5}, {26, 5}, {27, 5}, {28, 5}, {29, 5}, {19, 4}, {19, 4}, {20, 4}, {20, 4}, {34, 5}, {35, 5}, {36, 5}, {37, 5}, {38, 5}, {39, 5}, {21, 4}, {21, 4}, {42, 5}, {43, 5}, {0, 3}, {0, 3}, {0, 3}, {0, 3} }; #define getbit(buf, x) ( ( buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) static int jbig2_find_changing_element(const byte *line, int x, int w) { int a, b; if (line == 0) return w; if (x == -1) { a = 0; x = 0; } else { a = getbit(line, x); x++; } while (x < w) { b = getbit(line, x); if (a != b) break; x++; } return x; } static int jbig2_find_changing_element_of_color(const byte *line, int x, int w, int color) { if (line == 0) return w; x = jbig2_find_changing_element(line, x, w); if (x < w && getbit(line, x) != color) x = jbig2_find_changing_element(line, x, w); return x; } static const byte lm[8] = { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 }; static const byte rm[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; static void jbig2_set_bits(byte *line, int x0, int x1) { int a0, a1, b0, b1, a; a0 = x0 >> 3; a1 = x1 >> 3; b0 = x0 & 7; b1 = x1 & 7; if (a0 == a1) { line[a0] |= lm[b0] & rm[b1]; } else { line[a0] |= lm[b0]; for (a = a0 + 1; a < a1; a++) line[a] = 0xFF; if (b1) line[a1] |= rm[b1]; } } static int jbig2_decode_get_code(Jbig2MmrCtx *mmr, const mmr_table_node *table, int initial_bits) { uint32_t word = mmr->word; int table_ix = word >> (32 - initial_bits); int val = table[table_ix].val; int n_bits = table[table_ix].n_bits; if (n_bits > initial_bits) { int mask = (1 << (32 - initial_bits)) - 1; table_ix = val + ((word & mask) >> (32 - n_bits)); val = table[table_ix].val; n_bits = initial_bits + table[table_ix].n_bits; } jbig2_decode_mmr_consume(mmr, n_bits); return val; } static int jbig2_decode_get_run(Jbig2MmrCtx *mmr, const mmr_table_node *table, int initial_bits) { int result = 0; int val; do { val = jbig2_decode_get_code(mmr, table, initial_bits); result += val; } while (val >= 64); return result; } static int jbig2_decode_mmr_line(Jbig2MmrCtx *mmr, const byte *ref, byte *dst) { int a0 = -1; int a1, a2, b1, b2; int c = 0; /* 0 is white, black is 1 */ while (1) { uint32_t word = mmr->word; /* printf ("%08x\n", word); */ if (a0 >= mmr->width) break; if ((word >> (32 - 3)) == 1) { int white_run, black_run; jbig2_decode_mmr_consume(mmr, 3); if (a0 == -1) a0 = 0; if (c == 0) { white_run = jbig2_decode_get_run(mmr, jbig2_mmr_white_decode, 8); black_run = jbig2_decode_get_run(mmr, jbig2_mmr_black_decode, 7); a1 = a0 + white_run; a2 = a1 + black_run; if (a1 > mmr->width) a1 = mmr->width; if (a2 > mmr->width) a2 = mmr->width; if (a2 < a1 || a1 < 0) return -1; jbig2_set_bits(dst, a1, a2); a0 = a2; /* printf ("H %d %d\n", white_run, black_run); */ } else { black_run = jbig2_decode_get_run(mmr, jbig2_mmr_black_decode, 7); white_run = jbig2_decode_get_run(mmr, jbig2_mmr_white_decode, 8); a1 = a0 + black_run; a2 = a1 + white_run; if (a1 > mmr->width) a1 = mmr->width; if (a2 > mmr->width) a2 = mmr->width; if (a1 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, a1); a0 = a2; /* printf ("H %d %d\n", black_run, white_run); */ } } else if ((word >> (32 - 4)) == 1) { /* printf ("P\n"); */ jbig2_decode_mmr_consume(mmr, 4); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); b2 = jbig2_find_changing_element(ref, b1, mmr->width); if (c) { if (b2 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b2); } a0 = b2; } else if ((word >> (32 - 1)) == 1) { /* printf ("V(0)\n"); */ jbig2_decode_mmr_consume(mmr, 1); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (c) { if (b1 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1); } a0 = b1; c = !c; } else if ((word >> (32 - 3)) == 3) { /* printf ("VR(1)\n"); */ jbig2_decode_mmr_consume(mmr, 3); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (b1 + 1 > mmr->width) break; if (c) { if (b1 + 1 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1 + 1); } a0 = b1 + 1; c = !c; } else if ((word >> (32 - 6)) == 3) { /* printf ("VR(2)\n"); */ jbig2_decode_mmr_consume(mmr, 6); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (b1 + 2 > mmr->width) break; if (c) { if (b1 + 2 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1 + 2); } a0 = b1 + 2; c = !c; } else if ((word >> (32 - 7)) == 3) { /* printf ("VR(3)\n"); */ jbig2_decode_mmr_consume(mmr, 7); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (b1 + 3 > mmr->width) break; if (c) { if (b1 + 3 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1 + 3); } a0 = b1 + 3; c = !c; } else if ((word >> (32 - 3)) == 2) { /* printf ("VL(1)\n"); */ jbig2_decode_mmr_consume(mmr, 3); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (b1 - 1 < 0) break; if (c) { if (b1 - 1 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1 - 1); } a0 = b1 - 1; c = !c; } else if ((word >> (32 - 6)) == 2) { /* printf ("VL(2)\n"); */ jbig2_decode_mmr_consume(mmr, 6); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (b1 - 2 < 0) break; if (c) { if (b1 - 2 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1 - 2); } a0 = b1 - 2; c = !c; } else if ((word >> (32 - 7)) == 2) { /* printf ("VL(3)\n"); */ jbig2_decode_mmr_consume(mmr, 7); b1 = jbig2_find_changing_element_of_color(ref, a0, mmr->width, !c); if (b1 - 3 < 0) break; if (c) { if (b1 - 3 < a0 || a0 < 0) return -1; jbig2_set_bits(dst, a0, b1 - 3); } a0 = b1 - 3; c = !c; } else break; } return 0; } int jbig2_decode_generic_mmr(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, const byte *data, size_t size, Jbig2Image *image) { Jbig2MmrCtx mmr; const int rowstride = image->stride; byte *dst = image->data; byte *ref = NULL; int y; int code = 0; jbig2_decode_mmr_init(&mmr, image->width, image->height, data, size); for (y = 0; y < image->height; y++) { memset(dst, 0, rowstride); code = jbig2_decode_mmr_line(&mmr, ref, dst); if (code < 0) return code; ref = dst; dst += rowstride; } return code; } /** * jbig2_decode_halftone_mmr: decode mmr region inside of halftones * * @ctx: jbig2 decoder context * @params: parameters for decoding * @data: pointer to text region data to be decoded * @size: length of text region data * @image: return of decoded image * @consumed_bytes: return of consumed bytes from @data * * MMR decoding that consumes EOFB and returns consumed bytes (@consumed_bytes) * * returns: 0 **/ int jbig2_decode_halftone_mmr(Jbig2Ctx *ctx, const Jbig2GenericRegionParams *params, const byte *data, size_t size, Jbig2Image *image, size_t *consumed_bytes) { Jbig2MmrCtx mmr; const int rowstride = image->stride; byte *dst = image->data; byte *ref = NULL; int y; int code = 0; const uint32_t EOFB = 0x001001; jbig2_decode_mmr_init(&mmr, image->width, image->height, data, size); for (y = 0; y < image->height; y++) { memset(dst, 0, rowstride); code = jbig2_decode_mmr_line(&mmr, ref, dst); if (code < 0) return code; ref = dst; dst += rowstride; } /* test for EOFB (see section 6.2.6) */ if (mmr.word >> 8 == EOFB) { mmr.data_index += 3; } *consumed_bytes += mmr.data_index + (mmr.bit_index >> 3) + (mmr.bit_index > 0 ? 1 : 0); return code; } jbig2dec-0.13/jbig2_mmr.h000066400000000000000000000016351270170036400151340ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ int jbig2_decode_generic_mmr(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2GenericRegionParams *params, const byte *data, size_t size, Jbig2Image *image); int jbig2_decode_halftone_mmr(Jbig2Ctx *ctx, const Jbig2GenericRegionParams *params, const byte *data, size_t size, Jbig2Image *image, size_t *consumed_bytes); jbig2dec-0.13/jbig2_page.c000066400000000000000000000256221270170036400152520ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include "jbig2.h" #include "jbig2_priv.h" #ifdef OUTPUT_PBM #include #include "jbig2_image.h" #endif /* dump the page struct info */ static void dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page) { if (page->x_resolution == 0) { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (unknown res)", page->number, page->width, page->height); } else if (page->x_resolution == page->y_resolution) { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (%d ppm)", page->number, page->width, page->height, page->x_resolution); } else { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (%dx%d ppm)", page->number, page->width, page->height, page->x_resolution, page->y_resolution); } if (page->striped) { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "\tmaximum stripe size: %d", page->stripe_size); } } /** * jbig2_page_info: parse page info segment * * Parse the page info segment data and fill out a corresponding * Jbig2Page struct and ready it for subsequent rendered data, * including allocating an image buffer for the page (or the first stripe) **/ int jbig2_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { Jbig2Page *page; /* a new page info segment implies the previous page is finished */ page = &(ctx->pages[ctx->current_page]); if ((page->number != 0) && ((page->state == JBIG2_PAGE_NEW) || (page->state == JBIG2_PAGE_FREE))) { page->state = JBIG2_PAGE_COMPLETE; jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unexpected page info segment, marking previous page finished"); } /* find a free page */ { int index, j; index = ctx->current_page; while (ctx->pages[index].state != JBIG2_PAGE_FREE) { index++; if (index >= ctx->max_page_index) { /* grow the list */ ctx->pages = jbig2_renew(ctx, ctx->pages, Jbig2Page, (ctx->max_page_index <<= 2)); for (j = index; j < ctx->max_page_index; j++) { ctx->pages[j].state = JBIG2_PAGE_FREE; ctx->pages[j].number = 0; ctx->pages[j].image = NULL; } } } page = &(ctx->pages[index]); ctx->current_page = index; page->state = JBIG2_PAGE_NEW; page->number = segment->page_association; } /* FIXME: would be nice if we tried to work around this */ if (segment->data_length < 19) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short"); } /* 7.4.8.x */ page->width = jbig2_get_uint32(segment_data); page->height = jbig2_get_uint32(segment_data + 4); page->x_resolution = jbig2_get_uint32(segment_data + 8); page->y_resolution = jbig2_get_uint32(segment_data + 12); page->flags = segment_data[16]; /* 7.4.8.6 */ { int16_t striping = jbig2_get_int16(segment_data + 17); if (striping & 0x8000) { page->striped = TRUE; page->stripe_size = striping & 0x7FFF; } else { page->striped = FALSE; page->stripe_size = 0; /* would page->height be better? */ } } if (page->height == 0xFFFFFFFF && page->striped == FALSE) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "height is unspecified but page is not markes as striped"); page->striped = TRUE; } page->end_row = 0; if (segment->data_length > 19) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extra data in segment"); } dump_page_info(ctx, segment, page); /* allocate an approprate page image buffer */ /* 7.4.8.2 */ if (page->height == 0xFFFFFFFF) { page->image = jbig2_image_new(ctx, page->width, page->stripe_size); } else { page->image = jbig2_image_new(ctx, page->width, page->height); } if (page->image == NULL) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate buffer for page image"); } else { /* 8.2 (3) fill the page with the default pixel value */ jbig2_image_clear(ctx, page->image, (page->flags & 4)); jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %dx%d page image (%d bytes)", page->image->width, page->image->height, page->image->stride * page->image->height); } return 0; } /** * jbig2_end_of_stripe: parse and implement an end of stripe segment **/ int jbig2_end_of_stripe(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { Jbig2Page page = ctx->pages[ctx->current_page]; int end_row; end_row = jbig2_get_int32(segment_data); if (end_row < page.end_row) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "end of stripe segment with non-positive end row advance" " (new end row %d vs current end row %d)", end_row, page.end_row); } else { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of stripe: advancing end row to %d", end_row); } page.end_row = end_row; return 0; } /** * jbig2_complete_page: complete a page image * * called upon seeing an 'end of page' segment, this routine * marks a page as completed so it can be returned. * compositing will have already happened in the previous * segment handlers. **/ int jbig2_complete_page(Jbig2Ctx *ctx) { int code = 0; /* check for unfinished segments */ if (ctx->segment_index != ctx->n_segments) { Jbig2Segment *segment = ctx->segments[ctx->segment_index]; /* Some versions of Xerox Workcentre generate PDF files with the segment data length field of the last segment set to -1. Try to cope with this here. */ if ((segment->data_length & 0xffffffff) == 0xffffffff) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "File has an invalid segment data length!" " Trying to decode using the available data."); segment->data_length = ctx->buf_wr_ix - ctx->buf_rd_ix; code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix); ctx->buf_rd_ix += segment->data_length; ctx->segment_index++; } } /* ensure image exists before marking page as complete */ if (ctx->pages[ctx->current_page].image != NULL) { ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE; } return code; } /** * jbig2_end_of_page: parse and implement an end of page segment **/ int jbig2_end_of_page(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { uint32_t page_number = ctx->pages[ctx->current_page].number; if (segment->page_association != page_number) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "end of page marker for page %d doesn't match current page number %d", segment->page_association, page_number); } jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of page %d", page_number); jbig2_complete_page(ctx); #ifdef OUTPUT_PBM jbig2_image_write_pbm(ctx->pages[ctx->current_page].image, stdout); #endif return 0; } /** * jbig2_add_page_result: composite a decoding result onto a page * * this is called to add the results of segment decode (when it * is an image) to a page image buffer **/ int jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *image, int x, int y, Jbig2ComposeOp op) { /* ensure image exists first */ if (page->image == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page info possibly missing, no image defined"); return 0; } /* grow the page to accomodate a new stripe if necessary */ if (page->striped) { int new_height = y + image->height + page->end_row; if (page->image->height < new_height) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "growing page buffer to %d rows " "to accomodate new stripe", new_height); jbig2_image_resize(ctx, page->image, page->image->width, new_height); } } jbig2_image_compose(ctx, page->image, image, x, y + page->end_row, op); return 0; } /** * jbig2_get_page: return the next available page image buffer * * the client can call this at any time to check if any pages * have been decoded. If so, it returns the first available * one. The client should then call jbig2_release_page() when * it no longer needs to refer to the image buffer. * * since this is a public routine for the library clients, we * return an image structure pointer, even though the function * name refers to a page; the page structure is private. **/ Jbig2Image * jbig2_page_out(Jbig2Ctx *ctx) { int index; /* search for a completed page */ for (index = 0; index < ctx->max_page_index; index++) { if (ctx->pages[index].state == JBIG2_PAGE_COMPLETE) { Jbig2Image *img = ctx->pages[index].image; uint32_t page_number = ctx->pages[index].number; ctx->pages[index].state = JBIG2_PAGE_RETURNED; if (img != NULL) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d returned to the client", page_number); return jbig2_image_clone(ctx, img); } else { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page %d returned with no associated image", page_number); ; /* continue */ } } } /* no pages available */ return NULL; } /** * jbig2_release_page: tell the library a page can be freed **/ int jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image) { int index; /* find the matching page struct and mark it released */ for (index = 0; index < ctx->max_page_index; index++) { if (ctx->pages[index].image == image) { jbig2_image_release(ctx, image); ctx->pages[index].state = JBIG2_PAGE_RELEASED; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d released by the client", ctx->pages[index].number); return 0; } } /* no matching pages */ jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "jbig2_release_page called on unknown page"); return 1; } jbig2dec-0.13/jbig2_priv.h000066400000000000000000000131011270170036400153100ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* To enable Memento, either uncomment the following, or arrange to * predefine MEMENTO whilst building. */ /* #define MEMENTO */ /* If we are being compiled as part of a larger project that includes * Memento, that project should define JBIG_EXTERNAL_MEMENTO_H to point * to the include file to use. */ #ifdef JBIG_EXTERNAL_MEMENTO_H #include JBIG_EXTERNAL_MEMENTO_H #else #include "memento.h" #endif /* library internals */ typedef uint8_t byte; #define bool int #ifdef __cplusplus #define template template_C #define new new_C #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #ifndef NULL #define NULL ((void*)0) #endif typedef enum { JBIG2_FILE_HEADER, JBIG2_FILE_SEQUENTIAL_HEADER, JBIG2_FILE_SEQUENTIAL_BODY, JBIG2_FILE_RANDOM_HEADERS, JBIG2_FILE_RANDOM_BODIES, JBIG2_FILE_EOF } Jbig2FileState; struct _Jbig2Ctx { Jbig2Allocator *allocator; Jbig2Options options; const Jbig2Ctx *global_ctx; Jbig2ErrorCallback error_callback; void *error_callback_data; byte *buf; size_t buf_size; unsigned int buf_rd_ix; unsigned int buf_wr_ix; Jbig2FileState state; uint8_t file_header_flags; uint32_t n_pages; int n_segments_max; Jbig2Segment **segments; int n_segments; /* index of last segment header parsed */ int segment_index; /* index of last segment body parsed */ /* list of decoded pages, including the one in progress, currently stored as a contiguous, 0-indexed array. */ int current_page; int max_page_index; Jbig2Page *pages; }; uint32_t jbig2_get_uint32(const byte *bptr); int32_t jbig2_get_int32(const byte *buf); uint16_t jbig2_get_uint16(const byte *bptr); int16_t jbig2_get_int16(const byte *buf); /* dynamic memory management */ void *jbig2_alloc(Jbig2Allocator *allocator, size_t size, size_t num); void jbig2_free(Jbig2Allocator *allocator, void *p); void *jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num); #define jbig2_new(ctx, t, size) ((t *)jbig2_alloc(ctx->allocator, size, sizeof(t))) #define jbig2_renew(ctx, p, t, size) ((t *)jbig2_realloc(ctx->allocator, (p), size, sizeof(t))) int jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t seg_idx, const char *fmt, ...); /* the page structure handles decoded page results. it's allocated by a 'page info' segement and marked complete by an 'end of page' segment. */ typedef enum { JBIG2_PAGE_FREE, JBIG2_PAGE_NEW, JBIG2_PAGE_COMPLETE, JBIG2_PAGE_RETURNED, JBIG2_PAGE_RELEASED } Jbig2PageState; struct _Jbig2Page { Jbig2PageState state; uint32_t number; uint32_t height, width; /* in pixels */ uint32_t x_resolution, y_resolution; /* in pixels per meter */ uint16_t stripe_size; bool striped; int end_row; uint8_t flags; Jbig2Image *image; }; int jbig2_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); int jbig2_end_of_stripe(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); int jbig2_end_of_page(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); int jbig2_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); typedef enum { JBIG2_COMPOSE_OR = 0, JBIG2_COMPOSE_AND = 1, JBIG2_COMPOSE_XOR = 2, JBIG2_COMPOSE_XNOR = 3, JBIG2_COMPOSE_REPLACE = 4 } Jbig2ComposeOp; int jbig2_image_compose(Jbig2Ctx *ctx, Jbig2Image *dst, Jbig2Image *src, int x, int y, Jbig2ComposeOp op); int jbig2_page_add_result(Jbig2Ctx *ctx, Jbig2Page *page, Jbig2Image *src, int x, int y, Jbig2ComposeOp op); /* region segment info */ typedef struct { int32_t width; int32_t height; int32_t x; int32_t y; Jbig2ComposeOp op; uint8_t flags; } Jbig2RegionSegmentInfo; void jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const uint8_t *segment_data); int jbig2_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); /* 7.4 */ int jbig2_immediate_generic_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data); int jbig2_refinement_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data); int jbig2_pattern_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data); int jbig2_halftone_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data); /* The word stream design is a compromise between simplicity and trying to amortize the number of method calls. Each ::get_next_word invocation pulls 4 bytes from the stream, packed big-endian into a 32 bit word. The offset argument is provided as a convenience. It begins at 0 and increments by 4 for each successive invocation. */ typedef struct _Jbig2WordStream Jbig2WordStream; struct _Jbig2WordStream { int (*get_next_word)(Jbig2WordStream *self, int offset, uint32_t *word); }; Jbig2WordStream *jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size); void jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws); jbig2dec-0.13/jbig2_refinement.c000066400000000000000000000503341270170036400164700ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /** * Generic Refinement region handlers. **/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include /* memcpy(), memset() */ #include #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_generic.h" #include "jbig2_image.h" #if 0 /* currently not used */ static int jbig2_decode_refinement_template0(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "refinement region template 0 NYI"); } #endif static int jbig2_decode_refinement_template0_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats) { const int GRW = image->width; const int GRH = image->height; const int dx = params->DX; const int dy = params->DY; Jbig2Image *ref = params->reference; uint32_t CONTEXT; int x, y; bool bit; for (y = 0; y < GRH; y++) { for (x = 0; x < GRW; x++) { CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y + 0) << 0; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2; CONTEXT |= jbig2_image_get_pixel(image, x + params->grat[0], y + params->grat[1]) << 3; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 1) << 6; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 7; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 8; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 9; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12; bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } #ifdef JBIG2_DEBUG_DUMP { static count = 0; char name[32]; snprintf(name, 32, "refin-%d.pbm", count); jbig2_image_write_pbm_file(ref, name); snprintf(name, 32, "refout-%d.pbm", count); jbig2_image_write_pbm_file(image, name); count++; } #endif return 0; } static int jbig2_decode_refinement_template1_unopt(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats) { const int GRW = image->width; const int GRH = image->height; const int dx = params->DX; const int dy = params->DY; Jbig2Image *ref = params->reference; uint32_t CONTEXT; int x, y; bool bit; for (y = 0; y < GRH; y++) { for (x = 0; x < GRW; x++) { CONTEXT = 0; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y + 0) << 0; CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 3; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 6; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9; bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } #ifdef JBIG2_DEBUG_DUMP { static count = 0; char name[32]; snprintf(name, 32, "refin-%d.pbm", count); jbig2_image_write_pbm_file(ref, name); snprintf(name, 32, "refout-%d.pbm", count); jbig2_image_write_pbm_file(image, name); count++; } #endif return 0; } #if 0 /* currently not used */ static int jbig2_decode_refinement_template1(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats) { const int GRW = image->width; const int GRH = image->height; const int stride = image->stride; const int refstride = params->reference->stride; const int dy = params->DY; byte *grreg_line = (byte *) image->data; byte *grref_line = (byte *) params->reference->data; int x, y; for (y = 0; y < GRH; y++) { const int padded_width = (GRW + 7) & -8; uint32_t CONTEXT; uint32_t refline_m1; /* previous line of the reference bitmap */ uint32_t refline_0; /* current line of the reference bitmap */ uint32_t refline_1; /* next line of the reference bitmap */ uint32_t line_m1; /* previous line of the decoded bitmap */ line_m1 = (y >= 1) ? grreg_line[-stride] : 0; refline_m1 = ((y - dy) >= 1) ? grref_line[(-1 - dy) * stride] << 2 : 0; refline_0 = (((y - dy) > 0) && ((y - dy) < GRH)) ? grref_line[(0 - dy) * stride] << 4 : 0; refline_1 = (y < GRH - 1) ? grref_line[(+1 - dy) * stride] << 7 : 0; CONTEXT = ((line_m1 >> 5) & 0x00e) | ((refline_1 >> 5) & 0x030) | ((refline_0 >> 5) & 0x1c0) | ((refline_m1 >> 5) & 0x200); for (x = 0; x < padded_width; x += 8) { byte result = 0; int x_minor; const int minor_width = GRW - x > 8 ? 8 : GRW - x; if (y >= 1) { line_m1 = (line_m1 << 8) | (x + 8 < GRW ? grreg_line[-stride + (x >> 3) + 1] : 0); refline_m1 = (refline_m1 << 8) | (x + 8 < GRW ? grref_line[-refstride + (x >> 3) + 1] << 2 : 0); } refline_0 = (refline_0 << 8) | (x + 8 < GRW ? grref_line[(x >> 3) + 1] << 4 : 0); if (y < GRH - 1) refline_1 = (refline_1 << 8) | (x + 8 < GRW ? grref_line[+refstride + (x >> 3) + 1] << 7 : 0); else refline_1 = 0; /* this is the speed critical inner-loop */ for (x_minor = 0; x_minor < minor_width; x_minor++) { bool bit; bit = jbig2_arith_decode(as, &GR_stats[CONTEXT]); if (bit < 0) return -1; result |= bit << (7 - x_minor); CONTEXT = ((CONTEXT & 0x0d6) << 1) | bit | ((line_m1 >> (9 - x_minor)) & 0x002) | ((refline_1 >> (9 - x_minor)) & 0x010) | ((refline_0 >> (9 - x_minor)) & 0x040) | ((refline_m1 >> (9 - x_minor)) & 0x200); } grreg_line[x >> 3] = result; } grreg_line += stride; grref_line += refstride; } return 0; } #endif typedef uint32_t(*ContextBuilder)(const Jbig2RefinementRegionParams *, Jbig2Image *, int, int); static int implicit_value(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int x, int y) { Jbig2Image *ref = params->reference; int i = x - params->DX; int j = y - params->DY; int m = jbig2_image_get_pixel(ref, i, j); return ((jbig2_image_get_pixel(ref, i - 1, j - 1) == m) && (jbig2_image_get_pixel(ref, i, j - 1) == m) && (jbig2_image_get_pixel(ref, i + 1, j - 1) == m) && (jbig2_image_get_pixel(ref, i - 1, j) == m) && (jbig2_image_get_pixel(ref, i + 1, j) == m) && (jbig2_image_get_pixel(ref, i - 1, j + 1) == m) && (jbig2_image_get_pixel(ref, i, j + 1) == m) && (jbig2_image_get_pixel(ref, i + 1, j + 1) == m) )? m : -1; } static uint32_t mkctx0(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int x, int y) { const int dx = params->DX; const int dy = params->DY; Jbig2Image *ref = params->reference; uint32_t CONTEXT; CONTEXT = jbig2_image_get_pixel(image, x - 1, y + 0); CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2; CONTEXT |= jbig2_image_get_pixel(image, x + params->grat[0], y + params->grat[1]) << 3; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 1) << 6; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 7; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 8; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 9; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy - 1) << 10; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 11; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + params->grat[2], y - dy + params->grat[3]) << 12; return CONTEXT; } static uint32_t mkctx1(const Jbig2RefinementRegionParams *params, Jbig2Image *image, int x, int y) { const int dx = params->DX; const int dy = params->DY; Jbig2Image *ref = params->reference; uint32_t CONTEXT; CONTEXT = jbig2_image_get_pixel(image, x - 1, y + 0); CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 1; CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 2; CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 3; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 1) << 4; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 1) << 5; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 1, y - dy + 0) << 6; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy + 0) << 7; CONTEXT |= jbig2_image_get_pixel(ref, x - dx - 1, y - dy + 0) << 8; CONTEXT |= jbig2_image_get_pixel(ref, x - dx + 0, y - dy - 1) << 9; return CONTEXT; } static int jbig2_decode_refinement_TPGRON(const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats) { const int GRW = image->width; const int GRH = image->height; int x, y, iv, bit, LTP = 0; uint32_t start_context = (params->GRTEMPLATE ? 0x40 : 0x100); ContextBuilder mkctx = (params->GRTEMPLATE ? mkctx1 : mkctx0); for (y = 0; y < GRH; y++) { bit = jbig2_arith_decode(as, &GR_stats[start_context]); if (bit < 0) return -1; LTP = LTP ^ bit; if (!LTP) { for (x = 0; x < GRW; x++) { bit = jbig2_arith_decode(as, &GR_stats[mkctx(params, image, x, y)]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } } else { for (x = 0; x < GRW; x++) { iv = implicit_value(params, image, x, y); if (iv < 0) { bit = jbig2_arith_decode(as, &GR_stats[mkctx(params, image, x, y)]); if (bit < 0) return -1; jbig2_image_set_pixel(image, x, y, bit); } else jbig2_image_set_pixel(image, x, y, iv); } } } return 0; } /** * jbig2_decode_refinement_region: Decode a generic refinement region. * @ctx: The context for allocation and error reporting. * @segment: A segment reference for error reporting. * @params: Decoding parameter set. * @as: Arithmetic decoder state. * @image: Where to store the decoded image. * @GR_stats: Arithmetic stats. * * Decodes a generic refinement region, according to section 6.3. * an already allocated Jbig2Image object in @image for the result. * * Because this API is based on an arithmetic decoding state, it is * not suitable for MMR decoding. * * Return code: 0 on success. **/ int jbig2_decode_refinement_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2RefinementRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GR_stats) { { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoding generic refinement region with offset %d,%x, GRTEMPLATE=%d, TPGRON=%d", params->DX, params->DY, params->GRTEMPLATE, params->TPGRON); } if (params->TPGRON) return jbig2_decode_refinement_TPGRON(params, as, image, GR_stats); if (params->GRTEMPLATE) return jbig2_decode_refinement_template1_unopt(ctx, segment, params, as, image, GR_stats); else return jbig2_decode_refinement_template0_unopt(ctx, segment, params, as, image, GR_stats); } /** * Find the first referred-to intermediate region segment * with a non-NULL result for use as a reference image */ static Jbig2Segment * jbig2_region_find_referred(Jbig2Ctx *ctx, Jbig2Segment *segment) { const int nsegments = segment->referred_to_segment_count; Jbig2Segment *rsegment; int index; for (index = 0; index < nsegments; index++) { rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]); if (rsegment == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "could not find referred to segment %d", segment->referred_to_segments[index]); continue; } switch (rsegment->flags & 63) { case 4: /* intermediate text region */ case 20: /* intermediate halftone region */ case 36: /* intermediate generic region */ case 40: /* intermediate generic refinement region */ if (rsegment->result) return rsegment; break; default: /* keep looking */ break; } } /* no appropriate reference was found. */ return NULL; } /** * Handler for generic refinement region segments */ int jbig2_refinement_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2RefinementRegionParams params; Jbig2RegionSegmentInfo rsi; int offset = 0; byte seg_flags; int code = 0; /* 7.4.7 */ if (segment->data_length < 18) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); jbig2_get_region_segment_info(&rsi, segment_data); jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "generic region: %d x %d @ (%d, %d), flags = %02x", rsi.width, rsi.height, rsi.x, rsi.y, rsi.flags); /* 7.4.7.2 */ seg_flags = segment_data[17]; params.GRTEMPLATE = seg_flags & 0x01; params.TPGRON = seg_flags & 0x02 ? 1 : 0; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "segment flags = %02x %s%s", seg_flags, params.GRTEMPLATE ? " GRTEMPLATE" : "", params.TPGRON ? " TPGRON" : ""); if (seg_flags & 0xFC) jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "reserved segment flag bits are non-zero"); offset += 18; /* 7.4.7.3 */ if (!params.GRTEMPLATE) { if (segment->data_length < 22) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); params.grat[0] = segment_data[offset + 0]; params.grat[1] = segment_data[offset + 1]; params.grat[2] = segment_data[offset + 2]; params.grat[3] = segment_data[offset + 3]; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "grat1: (%d, %d) grat2: (%d, %d)", params.grat[0], params.grat[1], params.grat[2], params.grat[3]); offset += 4; } /* 7.4.7.4 - set up the reference image */ if (segment->referred_to_segment_count) { Jbig2Segment *ref; ref = jbig2_region_find_referred(ctx, segment); if (ref == NULL) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not find reference bitmap!"); /* the reference bitmap is the result of a previous intermediate region segment; the reference selection rules say to use the first one available, and not to reuse any intermediate result, so we simply clone it and free the original to keep track of this. */ params.reference = jbig2_image_clone(ctx, (Jbig2Image *) ref->result); jbig2_image_release(ctx, (Jbig2Image *) ref->result); ref->result = NULL; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "found reference bitmap in segment %d", ref->number); } else { /* the reference is just (a subset of) the page buffer */ params.reference = jbig2_image_clone(ctx, ctx->pages[ctx->current_page].image); if (params.reference == NULL) return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not clone reference bitmap!"); /* TODO: subset the image if appropriate */ } /* 7.4.7.5 */ params.DX = 0; params.DY = 0; { Jbig2WordStream *ws = NULL; Jbig2ArithState *as = NULL; Jbig2ArithCx *GR_stats = NULL; int stats_size; Jbig2Image *image = NULL; image = jbig2_image_new(ctx, rsi.width, rsi.height); if (image == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to allocate refinement image"); goto cleanup; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "allocated %d x %d image buffer for region decode results", rsi.width, rsi.height); stats_size = params.GRTEMPLATE ? 1 << 10 : 1 << 13; GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GR_stats == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate GR-stats in jbig2_refinement_region"); goto cleanup; } memset(GR_stats, 0, stats_size); ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset); if (ws == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate ws in jbig2_refinement_region"); goto cleanup; } as = jbig2_arith_new(ctx, ws); if (as == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate as in jbig2_refinement_region"); goto cleanup; } code = jbig2_decode_refinement_region(ctx, segment, ¶ms, as, image, GR_stats); if ((segment->flags & 63) == 40) { /* intermediate region. save the result for later */ segment->result = jbig2_image_clone(ctx, image); } else { /* immediate region. composite onto the page */ jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "composing %dx%d decoded refinement region onto page at (%d, %d)", rsi.width, rsi.height, rsi.x, rsi.y); jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, rsi.x, rsi.y, rsi.op); } cleanup: jbig2_image_release(ctx, image); jbig2_image_release(ctx, params.reference); jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); jbig2_free(ctx->allocator, GR_stats); } return code; } jbig2dec-0.13/jbig2_segment.c000066400000000000000000000242031270170036400157720ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include /* size_t */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_huffman.h" #include "jbig2_symbol_dict.h" #include "jbig2_metadata.h" #include "jbig2_arith.h" #include "jbig2_halftone.h" Jbig2Segment * jbig2_parse_segment_header(Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size, size_t *p_header_size) { Jbig2Segment *result; uint8_t rtscarf; uint32_t rtscarf_long; uint32_t *referred_to_segments; int referred_to_segment_count; int referred_to_segment_size; int pa_size; int offset; /* minimum possible size of a jbig2 segment header */ if (buf_size < 11) return NULL; result = jbig2_new(ctx, Jbig2Segment, 1); if (result == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate segment in jbig2_parse_segment_header"); return result; } /* 7.2.2 */ result->number = jbig2_get_uint32(buf); /* 7.2.3 */ result->flags = buf[4]; /* 7.2.4 referred-to segments */ rtscarf = buf[5]; if ((rtscarf & 0xe0) == 0xe0) { rtscarf_long = jbig2_get_uint32(buf + 5); referred_to_segment_count = rtscarf_long & 0x1fffffff; offset = 5 + 4 + (referred_to_segment_count + 1) / 8; } else { referred_to_segment_count = (rtscarf >> 5); offset = 5 + 1; } result->referred_to_segment_count = referred_to_segment_count; /* we now have enough information to compute the full header length */ referred_to_segment_size = result->number <= 256 ? 1 : result->number <= 65536 ? 2 : 4; /* 7.2.5 */ pa_size = result->flags & 0x40 ? 4 : 1; /* 7.2.6 */ if (offset + referred_to_segment_count * referred_to_segment_size + pa_size + 4 > buf_size) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "jbig2_parse_segment_header() called with insufficient data", -1); jbig2_free(ctx->allocator, result); return NULL; } /* 7.2.5 */ if (referred_to_segment_count) { int i; referred_to_segments = jbig2_new(ctx, uint32_t, referred_to_segment_count * referred_to_segment_size); if (referred_to_segments == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "could not allocate referred_to_segments " "in jbig2_parse_segment_header"); return NULL; } for (i = 0; i < referred_to_segment_count; i++) { referred_to_segments[i] = (referred_to_segment_size == 1) ? buf[offset] : (referred_to_segment_size == 2) ? jbig2_get_uint16(buf + offset) : jbig2_get_uint32(buf + offset); offset += referred_to_segment_size; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d refers to segment %d", result->number, referred_to_segments[i]); } result->referred_to_segments = referred_to_segments; } else { /* no referred-to segments */ result->referred_to_segments = NULL; } /* 7.2.6 */ if (result->flags & 0x40) { result->page_association = jbig2_get_uint32(buf + offset); offset += 4; } else { result->page_association = buf[offset++]; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, "segment %d is associated with page %d", result->number, result->page_association); /* 7.2.7 */ result->data_length = jbig2_get_uint32(buf + offset); *p_header_size = offset + 4; /* no body parsing results yet */ result->result = NULL; return result; } void jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment) { if (segment->referred_to_segments != NULL) { jbig2_free(ctx->allocator, segment->referred_to_segments); } /* todo: we need either some separate fields or a more complex result object rather than this brittle special casing */ switch (segment->flags & 63) { case 0: /* symbol dictionary */ if (segment->result != NULL) jbig2_sd_release(ctx, (Jbig2SymbolDict *) segment->result); break; case 4: /* intermediate text region */ case 40: /* intermediate refinement region */ if (segment->result != NULL) jbig2_image_release(ctx, (Jbig2Image *) segment->result); break; case 16: /* pattern dictionary */ if (segment->result != NULL) jbig2_hd_release(ctx, (Jbig2PatternDict *) segment->result); break; case 53: /* user-supplied huffman table */ if (segment->result != NULL) jbig2_table_free(ctx, (Jbig2HuffmanParams *) segment->result); break; case 62: if (segment->result != NULL) jbig2_metadata_free(ctx, (Jbig2Metadata *) segment->result); break; default: /* anything else is probably an undefined pointer */ break; } jbig2_free(ctx->allocator, segment); } /* find a segment by number */ Jbig2Segment * jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number) { int index, index_max = ctx->segment_index - 1; const Jbig2Ctx *global_ctx = ctx->global_ctx; /* FIXME: binary search would be better */ for (index = index_max; index >= 0; index--) if (ctx->segments[index]->number == number) return (ctx->segments[index]); if (global_ctx) for (index = global_ctx->segment_index - 1; index >= 0; index--) if (global_ctx->segments[index]->number == number) return (global_ctx->segments[index]); /* didn't find a match */ return NULL; } /* parse the generic portion of a region segment data header */ void jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const uint8_t *segment_data) { /* 7.4.1 */ info->width = jbig2_get_int32(segment_data); info->height = jbig2_get_int32(segment_data + 4); info->x = jbig2_get_int32(segment_data + 8); info->y = jbig2_get_int32(segment_data + 12); info->flags = segment_data[16]; info->op = (Jbig2ComposeOp)(info->flags & 0x7); } /* dispatch code for extension segment parsing */ static int jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { uint32_t type = jbig2_get_uint32(segment_data); bool reserved = type & 0x20000000; /* bool dependent = type & 0x40000000; (NYI) */ bool necessary = type & 0x80000000; if (necessary && !reserved) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extension segment is marked 'necessary' but " "not 'reservered' contrary to spec"); } switch (type) { case 0x20000000: return jbig2_comment_ascii(ctx, segment, segment_data); case 0x20000002: return jbig2_comment_unicode(ctx, segment, segment_data); default: if (necessary) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled necessary extension segment type 0x%08x", type); } else { return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled extension segment"); } } } /* general segment parsing dispatch */ int jbig2_parse_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data) { jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "Segment %d, flags=%x, type=%d, data_length=%d", segment->number, segment->flags, segment->flags & 63, segment->data_length); switch (segment->flags & 63) { case 0: return jbig2_symbol_dictionary(ctx, segment, segment_data); case 4: /* intermediate text region */ case 6: /* immediate text region */ case 7: /* immediate lossless text region */ return jbig2_text_region(ctx, segment, segment_data); case 16: return jbig2_pattern_dictionary(ctx, segment, segment_data); case 20: /* intermediate halftone region */ case 22: /* immediate halftone region */ case 23: /* immediate lossless halftone region */ return jbig2_halftone_region(ctx, segment, segment_data); case 36: return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled segment type 'intermediate generic region'"); case 38: /* immediate generic region */ case 39: /* immediate lossless generic region */ return jbig2_immediate_generic_region(ctx, segment, segment_data); case 40: /* intermediate generic refinement region */ case 42: /* immediate generic refinement region */ case 43: /* immediate lossless generic refinement region */ return jbig2_refinement_region(ctx, segment, segment_data); case 48: return jbig2_page_info(ctx, segment, segment_data); case 49: return jbig2_end_of_page(ctx, segment, segment_data); case 50: return jbig2_end_of_stripe(ctx, segment, segment_data); case 51: ctx->state = JBIG2_FILE_EOF; return jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "end of file"); case 52: return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled segment type 'profile'"); case 53: /* user-supplied huffman table */ return jbig2_table(ctx, segment, segment_data); case 62: return jbig2_parse_extension_segment(ctx, segment, segment_data); default: jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unknown segment type %d", segment->flags & 63); } return 0; } jbig2dec-0.13/jbig2_symbol_dict.c000066400000000000000000001242701270170036400166450ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* symbol dictionary segment decode and support */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include /* memset() */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_arith_int.h" #include "jbig2_arith_iaid.h" #include "jbig2_huffman.h" #include "jbig2_generic.h" #include "jbig2_mmr.h" #include "jbig2_symbol_dict.h" #include "jbig2_text.h" #if defined(OUTPUT_PBM) || defined(DUMP_SYMDICT) #include #include "jbig2_image.h" #endif /* Table 13 */ typedef struct { bool SDHUFF; bool SDREFAGG; uint32_t SDNUMINSYMS; Jbig2SymbolDict *SDINSYMS; uint32_t SDNUMNEWSYMS; uint32_t SDNUMEXSYMS; Jbig2HuffmanTable *SDHUFFDH; Jbig2HuffmanTable *SDHUFFDW; Jbig2HuffmanTable *SDHUFFBMSIZE; Jbig2HuffmanTable *SDHUFFAGGINST; int SDTEMPLATE; int8_t sdat[8]; bool SDRTEMPLATE; int8_t sdrat[4]; } Jbig2SymbolDictParams; /* Utility routines */ #ifdef DUMP_SYMDICT void jbig2_dump_symbol_dict(Jbig2Ctx *ctx, Jbig2Segment *segment) { Jbig2SymbolDict *dict = (Jbig2SymbolDict *) segment->result; int index; char filename[24]; if (dict == NULL) return; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "dumping symbol dict as %d individual png files\n", dict->n_symbols); for (index = 0; index < dict->n_symbols; index++) { snprintf(filename, sizeof(filename), "symbol_%02d-%04d.png", segment->number, index); jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "dumping symbol %d/%d as '%s'", index, dict->n_symbols, filename); #ifdef HAVE_LIBPNG jbig2_image_write_png_file(dict->glyphs[index], filename); #else jbig2_image_write_pbm_file(dict->glyphs[index], filename); #endif } } #endif /* DUMP_SYMDICT */ /* return a new empty symbol dict */ Jbig2SymbolDict * jbig2_sd_new(Jbig2Ctx *ctx, int n_symbols) { Jbig2SymbolDict *new = NULL; if (n_symbols < 0) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "Negative number of symbols in symbol dict: %d", n_symbols); return NULL; } new = jbig2_new(ctx, Jbig2SymbolDict, 1); if (new != NULL) { new->glyphs = jbig2_new(ctx, Jbig2Image *, n_symbols); new->n_symbols = n_symbols; } else { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to allocate new empty symbol dict"); return NULL; } if (new->glyphs != NULL) { memset(new->glyphs, 0, n_symbols * sizeof(Jbig2Image *)); } else { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "unable to allocate glyphs for new empty symbol dict"); jbig2_free(ctx->allocator, new); return NULL; } return new; } /* release the memory associated with a symbol dict */ void jbig2_sd_release(Jbig2Ctx *ctx, Jbig2SymbolDict *dict) { int i; if (dict == NULL) return; for (i = 0; i < dict->n_symbols; i++) if (dict->glyphs[i]) jbig2_image_release(ctx, dict->glyphs[i]); jbig2_free(ctx->allocator, dict->glyphs); jbig2_free(ctx->allocator, dict); } /* get a particular glyph by index */ Jbig2Image * jbig2_sd_glyph(Jbig2SymbolDict *dict, unsigned int id) { if (dict == NULL) return NULL; return dict->glyphs[id]; } /* count the number of dictionary segments referred to by the given segment */ int jbig2_sd_count_referred(Jbig2Ctx *ctx, Jbig2Segment *segment) { int index; Jbig2Segment *rsegment; int n_dicts = 0; for (index = 0; index < segment->referred_to_segment_count; index++) { rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]); if (rsegment && ((rsegment->flags & 63) == 0) && rsegment->result && (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL)) n_dicts++; } return (n_dicts); } /* return an array of pointers to symbol dictionaries referred to by the given segment */ Jbig2SymbolDict ** jbig2_sd_list_referred(Jbig2Ctx *ctx, Jbig2Segment *segment) { int index; Jbig2Segment *rsegment; Jbig2SymbolDict **dicts; int n_dicts = jbig2_sd_count_referred(ctx, segment); int dindex = 0; dicts = jbig2_new(ctx, Jbig2SymbolDict *, n_dicts); if (dicts == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate referred list of symbol dictionaries"); return NULL; } for (index = 0; index < segment->referred_to_segment_count; index++) { rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[index]); if (rsegment && ((rsegment->flags & 63) == 0) && rsegment->result && (((Jbig2SymbolDict *) rsegment->result)->n_symbols > 0) && ((*((Jbig2SymbolDict *) rsegment->result)->glyphs) != NULL)) { /* add this referred to symbol dictionary */ dicts[dindex++] = (Jbig2SymbolDict *) rsegment->result; } } if (dindex != n_dicts) { /* should never happen */ jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "counted %d symbol dictionaries but built a list with %d.\n", n_dicts, dindex); } return (dicts); } /* generate a new symbol dictionary by concatenating a list of existing dictionaries */ Jbig2SymbolDict * jbig2_sd_cat(Jbig2Ctx *ctx, int n_dicts, Jbig2SymbolDict **dicts) { int i, j, k, symbols; Jbig2SymbolDict *new = NULL; /* count the imported symbols and allocate a new array */ symbols = 0; for (i = 0; i < n_dicts; i++) symbols += dicts[i]->n_symbols; /* fill a new array with cloned glyph pointers */ new = jbig2_sd_new(ctx, symbols); if (new != NULL) { k = 0; for (i = 0; i < n_dicts; i++) for (j = 0; j < dicts[i]->n_symbols; j++) new->glyphs[k++] = jbig2_image_clone(ctx, dicts[i]->glyphs[j]); } else { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate new symbol dictionary"); } return new; } /* Decoding routines */ /* 6.5 */ static Jbig2SymbolDict * jbig2_decode_symbol_dict(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2SymbolDictParams *params, const byte *data, size_t size, Jbig2ArithCx *GB_stats, Jbig2ArithCx *GR_stats) { Jbig2SymbolDict *SDNEWSYMS = NULL; Jbig2SymbolDict *SDEXSYMS = NULL; uint32_t HCHEIGHT; uint32_t NSYMSDECODED; uint32_t SYMWIDTH, TOTWIDTH; uint32_t HCFIRSTSYM; uint32_t *SDNEWSYMWIDTHS = NULL; int SBSYMCODELEN = 0; Jbig2WordStream *ws = NULL; Jbig2HuffmanState *hs = NULL; Jbig2HuffmanTable *SDHUFFRDX = NULL; Jbig2HuffmanTable *SBHUFFRSIZE = NULL; Jbig2ArithState *as = NULL; Jbig2ArithIntCtx *IADH = NULL; Jbig2ArithIntCtx *IADW = NULL; Jbig2ArithIntCtx *IAEX = NULL; Jbig2ArithIntCtx *IAAI = NULL; Jbig2ArithIaidCtx *IAID = NULL; Jbig2ArithIntCtx *IARDX = NULL; Jbig2ArithIntCtx *IARDY = NULL; int code = 0; Jbig2SymbolDict **refagg_dicts = NULL; int n_refagg_dicts = 1; Jbig2TextRegionParams *tparams = NULL; /* 6.5.5 (3) */ HCHEIGHT = 0; NSYMSDECODED = 0; ws = jbig2_word_stream_buf_new(ctx, data, size); if (ws == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate ws in jbig2_decode_symbol_dict"); return NULL; } as = jbig2_arith_new(ctx, ws); if (as == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate as in jbig2_decode_symbol_dict"); jbig2_word_stream_buf_free(ctx, ws); return NULL; } if (!params->SDHUFF) { IADH = jbig2_arith_int_ctx_new(ctx); IADW = jbig2_arith_int_ctx_new(ctx); IAEX = jbig2_arith_int_ctx_new(ctx); IAAI = jbig2_arith_int_ctx_new(ctx); if ((IADH == NULL) || (IADW == NULL) || (IAEX == NULL) || (IAAI == NULL)) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap"); goto cleanup1; } if (params->SDREFAGG) { int64_t tmp = params->SDNUMINSYMS + params->SDNUMNEWSYMS; for (SBSYMCODELEN = 0; ((int64_t) 1 << SBSYMCODELEN) < tmp; SBSYMCODELEN++); IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN); IARDX = jbig2_arith_int_ctx_new(ctx); IARDY = jbig2_arith_int_ctx_new(ctx); if ((IAID == NULL) || (IARDX == NULL) || (IARDY == NULL)) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap"); goto cleanup2; } } } else { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded symbol dictionary"); hs = jbig2_huffman_new(ctx, ws); SDHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); if ((hs == NULL) || (SDHUFFRDX == NULL) || (SBHUFFRSIZE == NULL)) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for symbol bitmap"); goto cleanup2; } if (!params->SDREFAGG) { SDNEWSYMWIDTHS = jbig2_new(ctx, uint32_t, params->SDNUMNEWSYMS); if (SDNEWSYMWIDTHS == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate storage for (%u) symbol widths", params->SDNUMNEWSYMS); goto cleanup2; } } } SDNEWSYMS = jbig2_sd_new(ctx, params->SDNUMNEWSYMS); if (SDNEWSYMS == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "could not allocate storage for (%u) new symbols", params->SDNUMNEWSYMS); goto cleanup2; } /* 6.5.5 (4a) */ while (NSYMSDECODED < params->SDNUMNEWSYMS) { int32_t HCDH, DW; /* 6.5.6 */ if (params->SDHUFF) { HCDH = jbig2_huffman_get(hs, params->SDHUFFDH, &code); } else { code = jbig2_arith_int_decode(IADH, as, &HCDH); } if (code != 0) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "error or OOB decoding height class delta (%d)\n", code); } if (!params->SDHUFF && jbig2_arith_has_reached_marker(as)) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "prevent DOS while decoding height classes"); goto cleanup2; } /* 6.5.5 (4b) */ HCHEIGHT = HCHEIGHT + HCDH; SYMWIDTH = 0; TOTWIDTH = 0; HCFIRSTSYM = NSYMSDECODED; if ((int32_t) HCHEIGHT < 0) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Invalid HCHEIGHT value"); goto cleanup2; } #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "HCHEIGHT = %d", HCHEIGHT); #endif jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoding height class %d with %d syms decoded", HCHEIGHT, NSYMSDECODED); for (;;) { /* 6.5.7 */ if (params->SDHUFF) { DW = jbig2_huffman_get(hs, params->SDHUFFDW, &code); } else { code = jbig2_arith_int_decode(IADW, as, &DW); } if (code < 0) goto cleanup4; /* 6.5.5 (4c.i) */ if (code == 1) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, " OOB signals end of height class %d", HCHEIGHT); break; } /* check for broken symbol table */ if (NSYMSDECODED >= params->SDNUMNEWSYMS) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "No OOB signalling end of height class %d", HCHEIGHT); goto cleanup4; } SYMWIDTH = SYMWIDTH + DW; TOTWIDTH = TOTWIDTH + SYMWIDTH; if ((int32_t) SYMWIDTH < 0) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Invalid SYMWIDTH value (%d) at symbol %d", SYMWIDTH, NSYMSDECODED + 1); goto cleanup4; } #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "SYMWIDTH = %d TOTWIDTH = %d", SYMWIDTH, TOTWIDTH); #endif /* 6.5.5 (4c.ii) */ if (!params->SDHUFF || params->SDREFAGG) { #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "SDHUFF = %d; SDREFAGG = %d", params->SDHUFF, params->SDREFAGG); #endif /* 6.5.8 */ if (!params->SDREFAGG) { Jbig2GenericRegionParams region_params; int sdat_bytes; Jbig2Image *image; /* Table 16 */ region_params.MMR = 0; region_params.GBTEMPLATE = params->SDTEMPLATE; region_params.TPGDON = 0; region_params.USESKIP = 0; sdat_bytes = params->SDTEMPLATE == 0 ? 8 : 2; memcpy(region_params.gbat, params->sdat, sdat_bytes); image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT); if (image == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate image in jbig2_decode_symbol_dict"); goto cleanup4; } code = jbig2_decode_generic_region(ctx, segment, ®ion_params, as, image, GB_stats); if (code < 0) { jbig2_image_release(ctx, image); goto cleanup4; } SDNEWSYMS->glyphs[NSYMSDECODED] = image; } else { /* 6.5.8.2 refinement/aggregate symbol */ uint32_t REFAGGNINST; if (params->SDHUFF) { REFAGGNINST = jbig2_huffman_get(hs, params->SDHUFFAGGINST, &code); } else { code = jbig2_arith_int_decode(IAAI, as, (int32_t *) & REFAGGNINST); } if (code || (int32_t) REFAGGNINST <= 0) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "invalid number of symbols or OOB in aggregate glyph"); goto cleanup4; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "aggregate symbol coding (%d instances)", REFAGGNINST); if (REFAGGNINST > 1) { Jbig2Image *image; int i; if (tparams == NULL) { /* First time through, we need to initialise the */ /* various tables for Huffman or adaptive encoding */ /* as well as the text region parameters structure */ refagg_dicts = jbig2_new(ctx, Jbig2SymbolDict *, n_refagg_dicts); if (refagg_dicts == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory allocating dictionary array"); goto cleanup4; } refagg_dicts[0] = jbig2_sd_new(ctx, params->SDNUMINSYMS + params->SDNUMNEWSYMS); if (refagg_dicts[0] == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory allocating symbol dictionary"); jbig2_free(ctx->allocator, refagg_dicts); goto cleanup4; } for (i = 0; i < params->SDNUMINSYMS; i++) { refagg_dicts[0]->glyphs[i] = jbig2_image_clone(ctx, params->SDINSYMS->glyphs[i]); } tparams = jbig2_new(ctx, Jbig2TextRegionParams, 1); if (tparams == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory creating text region params"); goto cleanup4; } if (!params->SDHUFF) { /* Values from Table 17, section 6.5.8.2 (2) */ tparams->IADT = jbig2_arith_int_ctx_new(ctx); tparams->IAFS = jbig2_arith_int_ctx_new(ctx); tparams->IADS = jbig2_arith_int_ctx_new(ctx); tparams->IAIT = jbig2_arith_int_ctx_new(ctx); /* Table 31 */ for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < (int)(params->SDNUMINSYMS + params->SDNUMNEWSYMS); SBSYMCODELEN++); tparams->IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN); tparams->IARI = jbig2_arith_int_ctx_new(ctx); tparams->IARDW = jbig2_arith_int_ctx_new(ctx); tparams->IARDH = jbig2_arith_int_ctx_new(ctx); tparams->IARDX = jbig2_arith_int_ctx_new(ctx); tparams->IARDY = jbig2_arith_int_ctx_new(ctx); } else { tparams->SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F); /* Table B.6 */ tparams->SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H); /* Table B.8 */ tparams->SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K); /* Table B.11 */ tparams->SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */ tparams->SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */ tparams->SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */ tparams->SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); /* Table B.15 */ } tparams->SBHUFF = params->SDHUFF; tparams->SBREFINE = 1; tparams->SBSTRIPS = 1; tparams->SBDEFPIXEL = 0; tparams->SBCOMBOP = JBIG2_COMPOSE_OR; tparams->TRANSPOSED = 0; tparams->REFCORNER = JBIG2_CORNER_TOPLEFT; tparams->SBDSOFFSET = 0; tparams->SBRTEMPLATE = params->SDRTEMPLATE; } tparams->SBNUMINSTANCES = REFAGGNINST; image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT); if (image == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory creating symbol image"); goto cleanup4; } /* multiple symbols are handled as a text region */ jbig2_decode_text_region(ctx, segment, tparams, (const Jbig2SymbolDict * const *)refagg_dicts, n_refagg_dicts, image, data, size, GR_stats, as, ws); SDNEWSYMS->glyphs[NSYMSDECODED] = image; refagg_dicts[0]->glyphs[params->SDNUMINSYMS + NSYMSDECODED] = jbig2_image_clone(ctx, SDNEWSYMS->glyphs[NSYMSDECODED]); } else { /* 6.5.8.2.2 */ /* bool SBHUFF = params->SDHUFF; */ Jbig2RefinementRegionParams rparams; Jbig2Image *image; uint32_t ID; int32_t RDX, RDY; int BMSIZE = 0; int ninsyms = params->SDNUMINSYMS; int code1 = 0; int code2 = 0; int code3 = 0; int code4 = 0; /* 6.5.8.2.2 (2, 3, 4, 5) */ if (params->SDHUFF) { ID = jbig2_huffman_get_bits(hs, SBSYMCODELEN, &code4); RDX = jbig2_huffman_get(hs, SDHUFFRDX, &code1); RDY = jbig2_huffman_get(hs, SDHUFFRDX, &code2); BMSIZE = jbig2_huffman_get(hs, SBHUFFRSIZE, &code3); jbig2_huffman_skip(hs); } else { code1 = jbig2_arith_iaid_decode(IAID, as, (int32_t *) & ID); code2 = jbig2_arith_int_decode(IARDX, as, &RDX); code3 = jbig2_arith_int_decode(IARDY, as, &RDY); } if ((code1 < 0) || (code2 < 0) || (code3 < 0) || (code4 < 0)) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode data"); goto cleanup4; } if (ID >= ninsyms + NSYMSDECODED) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "refinement references unknown symbol %d", ID); goto cleanup4; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "symbol is a refinement of id %d with the " "refinement applied at (%d,%d)", ID, RDX, RDY); image = jbig2_image_new(ctx, SYMWIDTH, HCHEIGHT); if (image == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Out of memory creating symbol image"); goto cleanup4; } /* Table 18 */ rparams.GRTEMPLATE = params->SDRTEMPLATE; rparams.reference = (ID < ninsyms) ? params->SDINSYMS->glyphs[ID] : SDNEWSYMS->glyphs[ID - ninsyms]; /* SumatraPDF: fail on missing glyphs */ if (rparams.reference == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "missing glyph %d/%d!", ID, ninsyms); jbig2_image_release(ctx, image); goto cleanup4; } rparams.DX = RDX; rparams.DY = RDY; rparams.TPGRON = 0; memcpy(rparams.grat, params->sdrat, 4); code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, image, GR_stats); if (code < 0) goto cleanup4; SDNEWSYMS->glyphs[NSYMSDECODED] = image; /* 6.5.8.2.2 (7) */ if (params->SDHUFF) { if (BMSIZE == 0) BMSIZE = image->height * image->stride; jbig2_huffman_advance(hs, BMSIZE); } } } #ifdef OUTPUT_PBM { char name[64]; FILE *out; snprintf(name, 64, "sd.%04d.%04d.pbm", segment->number, NSYMSDECODED); out = fopen(name, "wb"); jbig2_image_write_pbm(SDNEWSYMS->glyphs[NSYMSDECODED], out); jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "writing out glyph as '%s' ...", name); fclose(out); } #endif } /* 6.5.5 (4c.iii) */ if (params->SDHUFF && !params->SDREFAGG) { SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH; } /* 6.5.5 (4c.iv) */ NSYMSDECODED = NSYMSDECODED + 1; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "decoded symbol %u of %u (%ux%u)", NSYMSDECODED, params->SDNUMNEWSYMS, SYMWIDTH, HCHEIGHT); } /* end height class decode loop */ /* 6.5.5 (4d) */ if (params->SDHUFF && !params->SDREFAGG) { /* 6.5.9 */ Jbig2Image *image; int BMSIZE = jbig2_huffman_get(hs, params->SDHUFFBMSIZE, &code); int j, x; if (code || (BMSIZE < 0)) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding size of collective bitmap!"); goto cleanup4; } /* skip any bits before the next byte boundary */ jbig2_huffman_skip(hs); image = jbig2_image_new(ctx, TOTWIDTH, HCHEIGHT); if (image == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate collective bitmap image!"); goto cleanup4; } if (BMSIZE == 0) { /* if BMSIZE == 0 bitmap is uncompressed */ const byte *src = data + jbig2_huffman_offset(hs); const int stride = (image->width >> 3) + ((image->width & 7) ? 1 : 0); byte *dst = image->data; /* SumatraPDF: prevent read access violation */ if (size - jbig2_huffman_offset(hs) < image->height * stride) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%d/%d)", image->height * stride, size - jbig2_huffman_offset(hs)); jbig2_image_release(ctx, image); goto cleanup4; } BMSIZE = image->height * stride; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "reading %dx%d uncompressed bitmap" " for %d symbols (%d bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE); for (j = 0; j < image->height; j++) { memcpy(dst, src, stride); dst += image->stride; src += stride; } } else { Jbig2GenericRegionParams rparams; /* SumatraPDF: prevent read access violation */ if (size - jbig2_huffman_offset(hs) < BMSIZE) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "not enough data for decoding (%d/%d)", BMSIZE, size - jbig2_huffman_offset(hs)); jbig2_image_release(ctx, image); goto cleanup4; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "reading %dx%d collective bitmap for %d symbols (%d bytes)", image->width, image->height, NSYMSDECODED - HCFIRSTSYM, BMSIZE); rparams.MMR = 1; code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data + jbig2_huffman_offset(hs), BMSIZE, image); if (code) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding MMR bitmap image!"); jbig2_image_release(ctx, image); goto cleanup4; } } /* advance past the data we've just read */ jbig2_huffman_advance(hs, BMSIZE); /* copy the collective bitmap into the symbol dictionary */ x = 0; for (j = HCFIRSTSYM; j < NSYMSDECODED; j++) { Jbig2Image *glyph; glyph = jbig2_image_new(ctx, SDNEWSYMWIDTHS[j], HCHEIGHT); if (glyph == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to copy the collective bitmap into symbol dictionary"); jbig2_image_release(ctx, image); goto cleanup4; } jbig2_image_compose(ctx, glyph, image, -x, 0, JBIG2_COMPOSE_REPLACE); x += SDNEWSYMWIDTHS[j]; SDNEWSYMS->glyphs[j] = glyph; } jbig2_image_release(ctx, image); } } /* end of symbol decode loop */ /* 6.5.10 */ SDEXSYMS = jbig2_sd_new(ctx, params->SDNUMEXSYMS); if (SDEXSYMS == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate symbols exported from symbols dictionary"); goto cleanup4; } else { int i = 0; int j = 0; int k; int exflag = 0; int64_t limit = params->SDNUMINSYMS + params->SDNUMNEWSYMS; int32_t exrunlength; int zerolength = 0; while (i < limit) { if (params->SDHUFF) exrunlength = jbig2_huffman_get(hs, SBHUFFRSIZE, &code); else code = jbig2_arith_int_decode(IAEX, as, &exrunlength); /* prevent infinite loop */ zerolength = exrunlength > 0 ? 0 : zerolength + 1; if (code || (exrunlength > limit - i) || (exrunlength < 0) || (zerolength > 4) || (exflag && (exrunlength > params->SDNUMEXSYMS - j))) { if (code) jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode exrunlength for exported symbols"); else if (exrunlength <= 0) jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "runlength too small in export symbol table (%d <= 0)\n", exrunlength); else jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "runlength too large in export symbol table (%d > %d - %d)\n", exrunlength, params->SDNUMEXSYMS, j); /* skip to the cleanup code and return SDEXSYMS = NULL */ jbig2_sd_release(ctx, SDEXSYMS); SDEXSYMS = NULL; break; } for (k = 0; k < exrunlength; k++) { if (exflag) { SDEXSYMS->glyphs[j++] = (i < params->SDNUMINSYMS) ? jbig2_image_clone(ctx, params->SDINSYMS->glyphs[i]) : jbig2_image_clone(ctx, SDNEWSYMS->glyphs[i - params->SDNUMINSYMS]); } i++; } exflag = !exflag; } } cleanup4: if (tparams != NULL) { if (!params->SDHUFF) { jbig2_arith_int_ctx_free(ctx, tparams->IADT); jbig2_arith_int_ctx_free(ctx, tparams->IAFS); jbig2_arith_int_ctx_free(ctx, tparams->IADS); jbig2_arith_int_ctx_free(ctx, tparams->IAIT); jbig2_arith_iaid_ctx_free(ctx, tparams->IAID); jbig2_arith_int_ctx_free(ctx, tparams->IARI); jbig2_arith_int_ctx_free(ctx, tparams->IARDW); jbig2_arith_int_ctx_free(ctx, tparams->IARDH); jbig2_arith_int_ctx_free(ctx, tparams->IARDX); jbig2_arith_int_ctx_free(ctx, tparams->IARDY); } else { jbig2_release_huffman_table(ctx, tparams->SBHUFFFS); jbig2_release_huffman_table(ctx, tparams->SBHUFFDS); jbig2_release_huffman_table(ctx, tparams->SBHUFFDT); jbig2_release_huffman_table(ctx, tparams->SBHUFFRDX); jbig2_release_huffman_table(ctx, tparams->SBHUFFRDY); jbig2_release_huffman_table(ctx, tparams->SBHUFFRDW); jbig2_release_huffman_table(ctx, tparams->SBHUFFRDH); } jbig2_free(ctx->allocator, tparams); } if (refagg_dicts != NULL) { jbig2_sd_release(ctx, refagg_dicts[0]); jbig2_free(ctx->allocator, refagg_dicts); } cleanup2: jbig2_sd_release(ctx, SDNEWSYMS); if (params->SDHUFF && !params->SDREFAGG) { jbig2_free(ctx->allocator, SDNEWSYMWIDTHS); } jbig2_release_huffman_table(ctx, SDHUFFRDX); jbig2_release_huffman_table(ctx, SBHUFFRSIZE); jbig2_huffman_free(ctx, hs); jbig2_arith_iaid_ctx_free(ctx, IAID); jbig2_arith_int_ctx_free(ctx, IARDX); jbig2_arith_int_ctx_free(ctx, IARDY); cleanup1: jbig2_word_stream_buf_free(ctx, ws); jbig2_free(ctx->allocator, as); jbig2_arith_int_ctx_free(ctx, IADH); jbig2_arith_int_ctx_free(ctx, IADW); jbig2_arith_int_ctx_free(ctx, IAEX); jbig2_arith_int_ctx_free(ctx, IAAI); return SDEXSYMS; } /* 7.4.2 */ int jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { Jbig2SymbolDictParams params; uint16_t flags; int sdat_bytes; int offset; Jbig2ArithCx *GB_stats = NULL; Jbig2ArithCx *GR_stats = NULL; int table_index = 0; const Jbig2HuffmanParams *huffman_params; if (segment->data_length < 10) goto too_short; /* 7.4.2.1.1 */ flags = jbig2_get_uint16(segment_data); /* zero params to ease cleanup later */ memset(¶ms, 0, sizeof(Jbig2SymbolDictParams)); params.SDHUFF = flags & 1; params.SDREFAGG = (flags >> 1) & 1; params.SDTEMPLATE = (flags >> 10) & 3; params.SDRTEMPLATE = (flags >> 12) & 1; if (params.SDHUFF) { switch ((flags & 0x000c) >> 2) { case 0: /* Table B.4 */ params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_D); break; case 1: /* Table B.5 */ params.SDHUFFDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_E); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom DH huffman table not found (%d)", table_index); } params.SDHUFFDH = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: default: return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table"); } if (params.SDHUFFDH == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate DH huffman table"); goto cleanup; } switch ((flags & 0x0030) >> 4) { case 0: /* Table B.2 */ params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_B); break; case 1: /* Table B.3 */ params.SDHUFFDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_C); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom DW huffman table not found (%d)", table_index); break; } params.SDHUFFDW = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: default: jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol dictionary specified invalid huffman table"); goto cleanup; /* Jump direct to cleanup to avoid 2 errors being given */ } if (params.SDHUFFDW == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate DW huffman table"); goto cleanup; } if (flags & 0x0040) { /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom BMSIZE huffman table not found (%d)", table_index); } else { params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; } } else { /* Table B.1 */ params.SDHUFFBMSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); } if (params.SDHUFFBMSIZE == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate BMSIZE huffman table"); goto cleanup; } if (flags & 0x0080) { /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom REFAGG huffman table not found (%d)", table_index); } else { params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; } } else { /* Table B.1 */ params.SDHUFFAGGINST = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); } if (params.SDHUFFAGGINST == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate REFAGG huffman table"); goto cleanup; } } /* FIXME: there are quite a few of these conditions to check */ /* maybe #ifdef CONFORMANCE and a separate routine */ if (!params.SDHUFF) { if (flags & 0x000c) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDH is not."); goto cleanup; } if (flags & 0x0030) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "SDHUFF is zero, but contrary to spec SDHUFFDW is not."); goto cleanup; } } if (flags & 0x0080) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "bitmap coding context is used (NYI) symbol data likely to be garbage!"); goto cleanup; } /* 7.4.2.1.2 */ sdat_bytes = params.SDHUFF ? 0 : params.SDTEMPLATE == 0 ? 8 : 2; memcpy(params.sdat, segment_data + 2, sdat_bytes); offset = 2 + sdat_bytes; /* 7.4.2.1.3 */ if (params.SDREFAGG && !params.SDRTEMPLATE) { if (offset + 4 > segment->data_length) goto too_short; memcpy(params.sdrat, segment_data + offset, 4); offset += 4; } if (offset + 8 > segment->data_length) goto too_short; /* 7.4.2.1.4 */ params.SDNUMEXSYMS = jbig2_get_uint32(segment_data + offset); /* 7.4.2.1.5 */ params.SDNUMNEWSYMS = jbig2_get_uint32(segment_data + offset + 4); offset += 8; jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "symbol dictionary, flags=%04x, %u exported syms, %u new syms", flags, params.SDNUMEXSYMS, params.SDNUMNEWSYMS); /* 7.4.2.2 (2) */ { int n_dicts = jbig2_sd_count_referred(ctx, segment); Jbig2SymbolDict **dicts = NULL; if (n_dicts > 0) { dicts = jbig2_sd_list_referred(ctx, segment); if (dicts == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate dicts in symbol dictionary"); goto cleanup; } params.SDINSYMS = jbig2_sd_cat(ctx, n_dicts, dicts); if (params.SDINSYMS == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate symbol array in symbol dictionary"); jbig2_free(ctx->allocator, dicts); goto cleanup; } jbig2_free(ctx->allocator, dicts); } if (params.SDINSYMS != NULL) { params.SDNUMINSYMS = params.SDINSYMS->n_symbols; } } /* 7.4.2.2 (3, 4) */ if (flags & 0x0100) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as used (NYI)"); goto cleanup; } else { int stats_size = params.SDTEMPLATE == 0 ? 65536 : params.SDTEMPLATE == 1 ? 8192 : 1024; GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GB_stats == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate GB_stats in jbig2_symbol_dictionary"); goto cleanup; } memset(GB_stats, 0, stats_size); stats_size = params.SDRTEMPLATE ? 1 << 10 : 1 << 13; GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GR_stats == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate GR_stats in jbig2_symbol_dictionary"); jbig2_free(ctx->allocator, GB_stats); goto cleanup; } memset(GR_stats, 0, stats_size); } segment->result = (void *)jbig2_decode_symbol_dict(ctx, segment, ¶ms, segment_data + offset, segment->data_length - offset, GB_stats, GR_stats); #ifdef DUMP_SYMDICT if (segment->result) jbig2_dump_symbol_dict(ctx, segment); #endif /* 7.4.2.2 (7) */ if (flags & 0x0200) { /* todo: retain GB_stats, GR_stats */ jbig2_free(ctx->allocator, GR_stats); jbig2_free(ctx->allocator, GB_stats); jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "segment marks bitmap coding context as retained (NYI)"); } else { jbig2_free(ctx->allocator, GR_stats); jbig2_free(ctx->allocator, GB_stats); } cleanup: if (params.SDHUFF) { jbig2_release_huffman_table(ctx, params.SDHUFFDH); jbig2_release_huffman_table(ctx, params.SDHUFFDW); jbig2_release_huffman_table(ctx, params.SDHUFFBMSIZE); jbig2_release_huffman_table(ctx, params.SDHUFFAGGINST); } jbig2_sd_release(ctx, params.SDINSYMS); return (segment->result != NULL) ? 0 : -1; too_short: return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); } jbig2dec-0.13/jbig2_symbol_dict.h000066400000000000000000000033211270170036400166430ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* symbol dictionary header */ /* the results of decoding a symbol dictionary */ typedef struct { uint32_t n_symbols; Jbig2Image **glyphs; } Jbig2SymbolDict; /* decode a symbol dictionary segment and store the results */ int jbig2_symbol_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data); /* get a particular glyph by index */ Jbig2Image *jbig2_sd_glyph(Jbig2SymbolDict *dict, unsigned int id); /* return a new empty symbol dict */ Jbig2SymbolDict *jbig2_sd_new(Jbig2Ctx *ctx, int n_symbols); /* release the memory associated with a symbol dict */ void jbig2_sd_release(Jbig2Ctx *ctx, Jbig2SymbolDict *dict); /* generate a new symbol dictionary by concatenating a list of existing dictionaries */ Jbig2SymbolDict *jbig2_sd_cat(Jbig2Ctx *ctx, int n_dicts, Jbig2SymbolDict **dicts); /* count the number of dictionary segments referred to by the given segment */ int jbig2_sd_count_referred(Jbig2Ctx *ctx, Jbig2Segment *segment); /* return an array of pointers to symbol dictionaries referred to by a segment */ Jbig2SymbolDict **jbig2_sd_list_referred(Jbig2Ctx *ctx, Jbig2Segment *segment); jbig2dec-0.13/jbig2_text.c000066400000000000000000001073041270170036400153200ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "os_types.h" #include #include /* memset() */ #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_arith.h" #include "jbig2_arith_int.h" #include "jbig2_arith_iaid.h" #include "jbig2_huffman.h" #include "jbig2_generic.h" #include "jbig2_symbol_dict.h" #include "jbig2_text.h" /** * jbig2_decode_text_region: decode a text region segment * * @ctx: jbig2 decoder context * @segment: jbig2 segment (header) structure * @params: parameters from the text region header * @dicts: an array of referenced symbol dictionaries * @n_dicts: the number of referenced symbol dictionaries * @image: image structure in which to store the decoded region bitmap * @data: pointer to text region data to be decoded * @size: length of text region data * * Implements the text region decoding procedure * described in section 6.4 of the JBIG2 spec. * * returns: 0 on success **/ int jbig2_decode_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2TextRegionParams *params, const Jbig2SymbolDict *const *dicts, const int n_dicts, Jbig2Image *image, const byte *data, const size_t size, Jbig2ArithCx *GR_stats, Jbig2ArithState *as, Jbig2WordStream *ws) { /* relevent bits of 6.4.4 */ uint32_t NINSTANCES; uint32_t ID; int32_t STRIPT; int32_t FIRSTS; int32_t DT; int32_t DFS; int32_t IDS; int32_t CURS; int32_t CURT; int S, T; int x, y; bool first_symbol; uint32_t index, SBNUMSYMS; Jbig2Image *IB = NULL; Jbig2HuffmanState *hs = NULL; Jbig2HuffmanTable *SBSYMCODES = NULL; int code = 0; int RI; SBNUMSYMS = 0; for (index = 0; index < n_dicts; index++) { SBNUMSYMS += dicts[index]->n_symbols; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "symbol list contains %d glyphs in %d dictionaries", SBNUMSYMS, n_dicts); if (params->SBHUFF) { Jbig2HuffmanTable *runcodes = NULL; Jbig2HuffmanParams runcodeparams; Jbig2HuffmanLine runcodelengths[35]; Jbig2HuffmanLine *symcodelengths = NULL; Jbig2HuffmanParams symcodeparams; int err, len, range, r; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "huffman coded text region"); hs = jbig2_huffman_new(ctx, ws); if (hs == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for text region"); return -1; } /* 7.4.3.1.7 - decode symbol ID Huffman table */ /* this is actually part of the segment header, but it is more convenient to handle it here */ /* parse and build the runlength code huffman table */ for (index = 0; index < 35; index++) { runcodelengths[index].PREFLEN = jbig2_huffman_get_bits(hs, 4, &code); if (code < 0) goto cleanup1; runcodelengths[index].RANGELEN = 0; runcodelengths[index].RANGELOW = index; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, " read runcode%d length %d", index, runcodelengths[index].PREFLEN); } runcodeparams.HTOOB = 0; runcodeparams.lines = runcodelengths; runcodeparams.n_lines = 35; runcodes = jbig2_build_huffman_table(ctx, &runcodeparams); if (runcodes == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error constructing symbol id runcode table!"); code = -1; goto cleanup1; } /* decode the symbol id codelengths using the runlength table */ symcodelengths = jbig2_new(ctx, Jbig2HuffmanLine, SBNUMSYMS); if (symcodelengths == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "memory allocation failure reading symbol ID huffman table!"); code = -1; goto cleanup1; } index = 0; while (index < SBNUMSYMS) { code = jbig2_huffman_get(hs, runcodes, &err); if (err != 0 || code < 0 || code >= 35) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error reading symbol ID huffman table!"); code = err ? err : -1; goto cleanup1; } if (code < 32) { len = code; range = 1; } else { if (code == 32) { if (index < 1) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "error decoding symbol id table: run length with no antecedent!"); code = -1; goto cleanup1; } len = symcodelengths[index - 1].PREFLEN; } else { len = 0; /* code == 33 or 34 */ } err = 0; if (code == 32) range = jbig2_huffman_get_bits(hs, 2, &err) + 3; else if (code == 33) range = jbig2_huffman_get_bits(hs, 3, &err) + 3; else if (code == 34) range = jbig2_huffman_get_bits(hs, 7, &err) + 11; if (err < 0) goto cleanup1; } jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, " read runcode%d at index %d (length %d range %d)", code, index, len, range); if (index + range > SBNUMSYMS) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "runlength extends %d entries beyond the end of symbol id table!", index + range - SBNUMSYMS); range = SBNUMSYMS - index; } for (r = 0; r < range; r++) { symcodelengths[index + r].PREFLEN = len; symcodelengths[index + r].RANGELEN = 0; symcodelengths[index + r].RANGELOW = index + r; } index += r; } if (index < SBNUMSYMS) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "runlength codes do not cover the available symbol set"); } symcodeparams.HTOOB = 0; symcodeparams.lines = symcodelengths; symcodeparams.n_lines = SBNUMSYMS; /* skip to byte boundary */ jbig2_huffman_skip(hs); /* finally, construct the symbol id huffman table itself */ SBSYMCODES = jbig2_build_huffman_table(ctx, &symcodeparams); cleanup1: jbig2_free(ctx->allocator, symcodelengths); jbig2_release_huffman_table(ctx, runcodes); if (SBSYMCODES == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not construct Symbol ID huffman table!"); jbig2_huffman_free(ctx, hs); return ((code != 0) ? code : -1); } } /* 6.4.5 (1) */ jbig2_image_clear(ctx, image, params->SBDEFPIXEL); /* 6.4.6 */ if (params->SBHUFF) { STRIPT = jbig2_huffman_get(hs, params->SBHUFFDT, &code); } else { code = jbig2_arith_int_decode(params->IADT, as, &STRIPT); } if (code < 0) goto cleanup2; /* 6.4.5 (2) */ STRIPT *= -(params->SBSTRIPS); FIRSTS = 0; NINSTANCES = 0; /* 6.4.5 (3) */ while (NINSTANCES < params->SBNUMINSTANCES) { /* (3b) */ if (params->SBHUFF) { DT = jbig2_huffman_get(hs, params->SBHUFFDT, &code); } else { code = jbig2_arith_int_decode(params->IADT, as, &DT); } if (code < 0) goto cleanup2; DT *= params->SBSTRIPS; STRIPT += DT; first_symbol = TRUE; /* 6.4.5 (3c) - decode symbols in strip */ for (;;) { /* (3c.i) */ if (first_symbol) { /* 6.4.7 */ if (params->SBHUFF) { DFS = jbig2_huffman_get(hs, params->SBHUFFFS, &code); } else { code = jbig2_arith_int_decode(params->IAFS, as, &DFS); } if (code < 0) goto cleanup2; FIRSTS += DFS; CURS = FIRSTS; first_symbol = FALSE; } else { if (NINSTANCES > params->SBNUMINSTANCES) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "too many NINSTANCES (%d) decoded", NINSTANCES); break; } /* (3c.ii) / 6.4.8 */ if (params->SBHUFF) { IDS = jbig2_huffman_get(hs, params->SBHUFFDS, &code); } else { code = jbig2_arith_int_decode(params->IADS, as, &IDS); } if (code) { /* decoded an OOB, reached end of strip */ break; } CURS += IDS + params->SBDSOFFSET; } /* (3c.iii) / 6.4.9 */ if (params->SBSTRIPS == 1) { CURT = 0; } else if (params->SBHUFF) { CURT = jbig2_huffman_get_bits(hs, params->LOGSBSTRIPS, &code); } else { code = jbig2_arith_int_decode(params->IAIT, as, &CURT); } if (code < 0) goto cleanup2; T = STRIPT + CURT; /* (3b.iv) / 6.4.10 - decode the symbol id */ if (params->SBHUFF) { ID = jbig2_huffman_get(hs, SBSYMCODES, &code); } else { code = jbig2_arith_iaid_decode(params->IAID, as, (int *)&ID); } if (code < 0) goto cleanup2; if (ID >= SBNUMSYMS) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "symbol id out of range! (%d/%d)", ID, SBNUMSYMS); goto cleanup2; } /* (3c.v) / 6.4.11 - look up the symbol bitmap IB */ { uint32_t id = ID; index = 0; while (id >= dicts[index]->n_symbols) id -= dicts[index++]->n_symbols; IB = jbig2_image_clone(ctx, dicts[index]->glyphs[id]); /* SumatraPDF: fail on missing glyphs */ if (!IB) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "missing glyph %d/%d!", index, id); goto cleanup2; } } if (params->SBREFINE) { if (params->SBHUFF) { RI = jbig2_huffman_get_bits(hs, 1, &code); } else { code = jbig2_arith_int_decode(params->IARI, as, &RI); } if (code < 0) goto cleanup2; } else { RI = 0; } if (RI) { Jbig2RefinementRegionParams rparams; Jbig2Image *IBO; int32_t RDW, RDH, RDX, RDY; Jbig2Image *refimage; int BMSIZE = 0; int code1 = 0; int code2 = 0; int code3 = 0; int code4 = 0; int code5 = 0; /* 6.4.11 (1, 2, 3, 4) */ if (!params->SBHUFF) { code1 = jbig2_arith_int_decode(params->IARDW, as, &RDW); code2 = jbig2_arith_int_decode(params->IARDH, as, &RDH); code3 = jbig2_arith_int_decode(params->IARDX, as, &RDX); code4 = jbig2_arith_int_decode(params->IARDY, as, &RDY); } else { RDW = jbig2_huffman_get(hs, params->SBHUFFRDW, &code1); RDH = jbig2_huffman_get(hs, params->SBHUFFRDH, &code2); RDX = jbig2_huffman_get(hs, params->SBHUFFRDX, &code3); RDY = jbig2_huffman_get(hs, params->SBHUFFRDY, &code4); BMSIZE = jbig2_huffman_get(hs, params->SBHUFFRSIZE, &code5); jbig2_huffman_skip(hs); } if ((code1 < 0) || (code2 < 0) || (code3 < 0) || (code4 < 0) || (code5 < 0)) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode data"); goto cleanup2; } /* 6.4.11 (6) */ IBO = IB; refimage = jbig2_image_new(ctx, IBO->width + RDW, IBO->height + RDH); if (refimage == NULL) { jbig2_image_release(ctx, IBO); if (params->SBHUFF) { jbig2_release_huffman_table(ctx, SBSYMCODES); } return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate reference image"); } jbig2_image_clear(ctx, refimage, 0x00); /* Table 12 */ rparams.GRTEMPLATE = params->SBRTEMPLATE; rparams.reference = IBO; rparams.DX = (RDW >> 1) + RDX; rparams.DY = (RDH >> 1) + RDY; rparams.TPGRON = 0; memcpy(rparams.grat, params->sbrat, 4); code = jbig2_decode_refinement_region(ctx, segment, &rparams, as, refimage, GR_stats); if (code < 0) { jbig2_image_release(ctx, refimage); goto cleanup2; } IB = refimage; jbig2_image_release(ctx, IBO); /* 6.4.11 (7) */ if (params->SBHUFF) { jbig2_huffman_advance(hs, BMSIZE); } } /* (3c.vi) */ if ((!params->TRANSPOSED) && (params->REFCORNER > 1)) { CURS += IB->width - 1; } else if ((params->TRANSPOSED) && !(params->REFCORNER & 1)) { CURS += IB->height - 1; } /* (3c.vii) */ S = CURS; /* (3c.viii) */ if (!params->TRANSPOSED) { switch (params->REFCORNER) { case JBIG2_CORNER_TOPLEFT: x = S; y = T; break; case JBIG2_CORNER_TOPRIGHT: x = S - IB->width + 1; y = T; break; case JBIG2_CORNER_BOTTOMLEFT: x = S; y = T - IB->height + 1; break; default: case JBIG2_CORNER_BOTTOMRIGHT: x = S - IB->width + 1; y = T - IB->height + 1; break; } } else { /* TRANSPOSED */ switch (params->REFCORNER) { case JBIG2_CORNER_TOPLEFT: x = T; y = S; break; case JBIG2_CORNER_TOPRIGHT: x = T - IB->width + 1; y = S; break; case JBIG2_CORNER_BOTTOMLEFT: x = T; y = S - IB->height + 1; break; default: case JBIG2_CORNER_BOTTOMRIGHT: x = T - IB->width + 1; y = S - IB->height + 1; break; } } /* (3c.ix) */ #ifdef JBIG2_DEBUG jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "composing glyph id %d: %dx%d @ (%d,%d) symbol %d/%d", ID, IB->width, IB->height, x, y, NINSTANCES + 1, params->SBNUMINSTANCES); #endif code = jbig2_image_compose(ctx, image, IB, x, y, params->SBCOMBOP); if (code < 0) { jbig2_image_release(ctx, IB); goto cleanup2; } /* (3c.x) */ if ((!params->TRANSPOSED) && (params->REFCORNER < 2)) { CURS += IB->width - 1; } else if ((params->TRANSPOSED) && (params->REFCORNER & 1)) { CURS += IB->height - 1; } /* (3c.xi) */ NINSTANCES++; jbig2_image_release(ctx, IB); } /* end strip */ } /* 6.4.5 (4) */ cleanup2: if (params->SBHUFF) { jbig2_release_huffman_table(ctx, SBSYMCODES); } jbig2_huffman_free(ctx, hs); return code; } /** * jbig2_text_region: read a text region segment header **/ int jbig2_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data) { int offset = 0; Jbig2RegionSegmentInfo region_info; Jbig2TextRegionParams params; Jbig2Image *image = NULL; Jbig2SymbolDict **dicts = NULL; int n_dicts = 0; uint16_t flags = 0; uint16_t huffman_flags = 0; Jbig2ArithCx *GR_stats = NULL; int code = 0; Jbig2WordStream *ws = NULL; Jbig2ArithState *as = NULL; int table_index = 0; const Jbig2HuffmanParams *huffman_params = NULL; /* 7.4.1 */ if (segment->data_length < 17) goto too_short; jbig2_get_region_segment_info(®ion_info, segment_data); offset += 17; /* 7.4.3.1.1 */ flags = jbig2_get_uint16(segment_data + offset); offset += 2; jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "text region header flags 0x%04x", flags); /* zero params to ease cleanup later */ memset(¶ms, 0, sizeof(Jbig2TextRegionParams)); params.SBHUFF = flags & 0x0001; params.SBREFINE = flags & 0x0002; params.LOGSBSTRIPS = (flags & 0x000c) >> 2; params.SBSTRIPS = 1 << params.LOGSBSTRIPS; params.REFCORNER = (Jbig2RefCorner)((flags & 0x0030) >> 4); params.TRANSPOSED = flags & 0x0040; params.SBCOMBOP = (Jbig2ComposeOp)((flags & 0x0180) >> 7); params.SBDEFPIXEL = flags & 0x0200; /* SBDSOFFSET is a signed 5 bit integer */ params.SBDSOFFSET = (flags & 0x7C00) >> 10; if (params.SBDSOFFSET > 0x0f) params.SBDSOFFSET -= 0x20; params.SBRTEMPLATE = flags & 0x8000; if (params.SBDSOFFSET) { jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "text region has SBDSOFFSET %d", params.SBDSOFFSET); } if (params.SBHUFF) { /* Huffman coding */ /* 7.4.3.1.2 */ huffman_flags = jbig2_get_uint16(segment_data + offset); offset += 2; if (huffman_flags & 0x8000) jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "reserved bit 15 of text region huffman flags is not zero"); } else { /* arithmetic coding */ /* 7.4.3.1.3 */ if ((params.SBREFINE) && !(params.SBRTEMPLATE)) { params.sbrat[0] = segment_data[offset]; params.sbrat[1] = segment_data[offset + 1]; params.sbrat[2] = segment_data[offset + 2]; params.sbrat[3] = segment_data[offset + 3]; offset += 4; } } /* 7.4.3.1.4 */ params.SBNUMINSTANCES = jbig2_get_uint32(segment_data + offset); offset += 4; if (params.SBHUFF) { /* 7.4.3.1.5 - Symbol ID Huffman table */ /* ...this is handled in the segment body decoder */ /* 7.4.3.1.6 - Other Huffman table selection */ switch (huffman_flags & 0x0003) { case 0: /* Table B.6 */ params.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_F); break; case 1: /* Table B.7 */ params.SBHUFFFS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_G); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom FS huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFFS = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: /* invalid */ default: code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid FS huffman table"); goto cleanup1; break; } if (params.SBHUFFFS == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified FS huffman table"); goto cleanup1; } switch ((huffman_flags & 0x000c) >> 2) { case 0: /* Table B.8 */ params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_H); break; case 1: /* Table B.9 */ params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_I); break; case 2: /* Table B.10 */ params.SBHUFFDS = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_J); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom DS huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFDS = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; } if (params.SBHUFFDS == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified DS huffman table"); goto cleanup1; } switch ((huffman_flags & 0x0030) >> 4) { case 0: /* Table B.11 */ params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_K); break; case 1: /* Table B.12 */ params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_L); break; case 2: /* Table B.13 */ params.SBHUFFDT = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_M); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom DT huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFDT = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; } if (params.SBHUFFDT == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified DT huffman table"); goto cleanup1; } switch ((huffman_flags & 0x00c0) >> 6) { case 0: /* Table B.14 */ params.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N); break; case 1: /* Table B.15 */ params.SBHUFFRDW = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom RDW huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFRDW = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: /* invalid */ default: code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDW huffman table"); goto cleanup1; break; } if (params.SBHUFFRDW == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified RDW huffman table"); goto cleanup1; } switch ((huffman_flags & 0x0300) >> 8) { case 0: /* Table B.14 */ params.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N); break; case 1: /* Table B.15 */ params.SBHUFFRDH = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom RDH huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFRDH = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: /* invalid */ default: code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDH huffman table"); goto cleanup1; break; } if (params.SBHUFFRDH == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified RDH huffman table"); goto cleanup1; } switch ((huffman_flags & 0x0c00) >> 10) { case 0: /* Table B.14 */ params.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N); break; case 1: /* Table B.15 */ params.SBHUFFRDX = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom RDX huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFRDX = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: /* invalid */ default: code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDX huffman table"); goto cleanup1; break; } if (params.SBHUFFRDX == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified RDX huffman table"); goto cleanup1; } switch ((huffman_flags & 0x3000) >> 12) { case 0: /* Table B.14 */ params.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_N); break; case 1: /* Table B.15 */ params.SBHUFFRDY = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_O); break; case 3: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom RDY huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFRDY = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; case 2: /* invalid */ default: code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region specified invalid RDY huffman table"); goto cleanup1; break; } if (params.SBHUFFRDY == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified RDY huffman table"); goto cleanup1; } switch ((huffman_flags & 0x4000) >> 14) { case 0: /* Table B.1 */ params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, &jbig2_huffman_params_A); break; case 1: /* Custom table from referred segment */ huffman_params = jbig2_find_table(ctx, segment, table_index); if (huffman_params == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Custom RSIZE huffman table not found (%d)", table_index); goto cleanup1; } params.SBHUFFRSIZE = jbig2_build_huffman_table(ctx, huffman_params); ++table_index; break; } if (params.SBHUFFRSIZE == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate text region specified RSIZE huffman table"); goto cleanup1; } if (huffman_flags & 0x8000) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "text region huffman flags bit 15 is set, contrary to spec"); } /* 7.4.3.1.7 */ /* For convenience this is done in the body decoder routine */ } jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "text region: %d x %d @ (%d,%d) %d symbols", region_info.width, region_info.height, region_info.x, region_info.y, params.SBNUMINSTANCES); /* 7.4.3.2 (2) - compose the list of symbol dictionaries */ n_dicts = jbig2_sd_count_referred(ctx, segment); if (n_dicts != 0) { dicts = jbig2_sd_list_referred(ctx, segment); } else { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "text region refers to no symbol dictionaries!"); goto cleanup1; } if (dicts == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unable to retrive symbol dictionaries! previous parsing error?"); goto cleanup1; } else { int index; if (dicts[0] == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to find first referenced symbol dictionary!"); goto cleanup1; } for (index = 1; index < n_dicts; index++) if (dicts[index] == NULL) { jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unable to find all referenced symbol dictionaries!"); n_dicts = index; } } /* 7.4.3.2 (3) */ { int stats_size = params.SBRTEMPLATE ? 1 << 10 : 1 << 13; GR_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size); if (GR_stats == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "could not allocate GR_stats"); goto cleanup1; } memset(GR_stats, 0, stats_size); } image = jbig2_image_new(ctx, region_info.width, region_info.height); if (image == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate text region image"); goto cleanup2; } ws = jbig2_word_stream_buf_new(ctx, segment_data + offset, segment->data_length - offset); if (ws == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate ws in text region image"); goto cleanup2; } as = jbig2_arith_new(ctx, ws); if (as == NULL) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate as in text region image"); goto cleanup2; } if (!params.SBHUFF) { int SBSYMCODELEN, index; int SBNUMSYMS = 0; for (index = 0; index < n_dicts; index++) { SBNUMSYMS += dicts[index]->n_symbols; } params.IADT = jbig2_arith_int_ctx_new(ctx); params.IAFS = jbig2_arith_int_ctx_new(ctx); params.IADS = jbig2_arith_int_ctx_new(ctx); params.IAIT = jbig2_arith_int_ctx_new(ctx); if ((params.IADT == NULL) || (params.IAFS == NULL) || (params.IADS == NULL) || (params.IAIT == NULL)) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate text region image data"); goto cleanup3; } /* Table 31 */ for (SBSYMCODELEN = 0; (1 << SBSYMCODELEN) < SBNUMSYMS; SBSYMCODELEN++) { } params.IAID = jbig2_arith_iaid_ctx_new(ctx, SBSYMCODELEN); params.IARI = jbig2_arith_int_ctx_new(ctx); params.IARDW = jbig2_arith_int_ctx_new(ctx); params.IARDH = jbig2_arith_int_ctx_new(ctx); params.IARDX = jbig2_arith_int_ctx_new(ctx); params.IARDY = jbig2_arith_int_ctx_new(ctx); if ((params.IAID == NULL) || (params.IARI == NULL) || (params.IARDW == NULL) || (params.IARDH == NULL) || (params.IARDX == NULL) || (params.IARDY == NULL)) { code = jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "couldn't allocate text region image data"); goto cleanup4; } } code = jbig2_decode_text_region(ctx, segment, ¶ms, (const Jbig2SymbolDict * const *)dicts, n_dicts, image, segment_data + offset, segment->data_length - offset, GR_stats, as, ws); if (code < 0) { jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to decode text region image data"); goto cleanup4; } if ((segment->flags & 63) == 4) { /* we have an intermediate region here. save it for later */ segment->result = jbig2_image_clone(ctx, image); } else { /* otherwise composite onto the page */ jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "composing %dx%d decoded text region onto page at (%d, %d)", region_info.width, region_info.height, region_info.x, region_info.y); jbig2_page_add_result(ctx, &ctx->pages[ctx->current_page], image, region_info.x, region_info.y, region_info.op); } cleanup4: if (!params.SBHUFF) { jbig2_arith_iaid_ctx_free(ctx, params.IAID); jbig2_arith_int_ctx_free(ctx, params.IARI); jbig2_arith_int_ctx_free(ctx, params.IARDW); jbig2_arith_int_ctx_free(ctx, params.IARDH); jbig2_arith_int_ctx_free(ctx, params.IARDX); jbig2_arith_int_ctx_free(ctx, params.IARDY); } cleanup3: if (!params.SBHUFF) { jbig2_arith_int_ctx_free(ctx, params.IADT); jbig2_arith_int_ctx_free(ctx, params.IAFS); jbig2_arith_int_ctx_free(ctx, params.IADS); jbig2_arith_int_ctx_free(ctx, params.IAIT); } jbig2_free(ctx->allocator, as); jbig2_word_stream_buf_free(ctx, ws); cleanup2: jbig2_free(ctx->allocator, GR_stats); jbig2_image_release(ctx, image); cleanup1: if (params.SBHUFF) { jbig2_release_huffman_table(ctx, params.SBHUFFFS); jbig2_release_huffman_table(ctx, params.SBHUFFDS); jbig2_release_huffman_table(ctx, params.SBHUFFDT); jbig2_release_huffman_table(ctx, params.SBHUFFRDX); jbig2_release_huffman_table(ctx, params.SBHUFFRDY); jbig2_release_huffman_table(ctx, params.SBHUFFRDW); jbig2_release_huffman_table(ctx, params.SBHUFFRDH); jbig2_release_huffman_table(ctx, params.SBHUFFRSIZE); } jbig2_free(ctx->allocator, dicts); return code; too_short: return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short"); } jbig2dec-0.13/jbig2_text.h000066400000000000000000000041621270170036400153230ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /** * Headers for Text region handling **/ typedef enum { JBIG2_CORNER_BOTTOMLEFT = 0, JBIG2_CORNER_TOPLEFT = 1, JBIG2_CORNER_BOTTOMRIGHT = 2, JBIG2_CORNER_TOPRIGHT = 3 } Jbig2RefCorner; typedef struct { bool SBHUFF; bool SBREFINE; bool SBDEFPIXEL; Jbig2ComposeOp SBCOMBOP; bool TRANSPOSED; Jbig2RefCorner REFCORNER; int SBDSOFFSET; /* int SBW; */ /* int SBH; */ uint32_t SBNUMINSTANCES; int LOGSBSTRIPS; int SBSTRIPS; /* int SBNUMSYMS; */ /* SBSYMCODES */ /* SBSYMCODELEN */ /* SBSYMS */ Jbig2HuffmanTable *SBHUFFFS; Jbig2HuffmanTable *SBHUFFDS; Jbig2HuffmanTable *SBHUFFDT; Jbig2HuffmanTable *SBHUFFRDW; Jbig2HuffmanTable *SBHUFFRDH; Jbig2HuffmanTable *SBHUFFRDX; Jbig2HuffmanTable *SBHUFFRDY; Jbig2HuffmanTable *SBHUFFRSIZE; Jbig2ArithIntCtx *IADT; Jbig2ArithIntCtx *IAFS; Jbig2ArithIntCtx *IADS; Jbig2ArithIntCtx *IAIT; Jbig2ArithIaidCtx *IAID; Jbig2ArithIntCtx *IARI; Jbig2ArithIntCtx *IARDW; Jbig2ArithIntCtx *IARDH; Jbig2ArithIntCtx *IARDX; Jbig2ArithIntCtx *IARDY; bool SBRTEMPLATE; int8_t sbrat[4]; } Jbig2TextRegionParams; int jbig2_decode_text_region(Jbig2Ctx *ctx, Jbig2Segment *segment, const Jbig2TextRegionParams *params, const Jbig2SymbolDict *const *dicts, const int n_dicts, Jbig2Image *image, const byte *data, const size_t size, Jbig2ArithCx *GR_stats, Jbig2ArithState *as, Jbig2WordStream *ws); jbig2dec-0.13/jbig2dec.1000066400000000000000000000033771270170036400146530ustar00rootroot00000000000000.TH jbig2dec 1 "2016 April 08" "Version 0.13" "jbig2dec Manual" .SH NAME jbig2dec \- File format converter specialized in JBIG2 decoding .SH SYNOPSIS .B jbig2dec .RI [ options ] .I file.jbig2 .br .B jbig2dec .RI [ options ] .I global-stream page-stream .SH DESCRIPTION The .B jbig2dec command converts JBIG2 files to png or pbm files. When passed a single .I file argument it is interpreted as a JBIG2 file stream, with either sequential or random-access organization. When passed two stream arguments, they are interpreted as the global and page-specific portions of an embedded organzation, as used in PDF. If a particular page references no global segment stream, /dev/null can be passed for the .I global-stream argument to request the embedded parser. .SH OPTIONS The options are as follows: .TP .BI -o " file" Store the decoded output in .IR file . Defaults to the input with a different extension. Set to \fI-\fR for standard output. .TP .BI -t " type" Force a particular output file format. Supported are \fIpng\fR and \fIpbm\fR. .TP .BR -d " or " --dump Print the structure of the JBIG2 file rather than explicitly decoding it. .TP .BR --hash Print a hash of the decoded document. .TP .BR -q " or " --quiet Suppress warnings and other diagnostic output. .TP .BR -v " or " --verbose Report additional information about the decoding process. Pass just \fB-v\fR for information about the file as it's being decoded. This is the same as \fB--verbose=2\fR. Pass \fB--verbose=3\fR or higher for debugging information. .TP .BR --version Show program version information. .TP .BR -h " or " --help Show usage summary. .SH AUTHOR jbig2-dev This manpage was initially written by Sebastian Rasmussen for jbig2dec and the Debian Project. jbig2dec-0.13/jbig2dec.c000066400000000000000000000340061270170036400147260ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef PACKAGE #define PACKAGE "jbig2dec" #endif #ifndef VERSION #define VERSION "unknown-version" #endif #include #include #include #include #ifdef HAVE_GETOPT_H # include #else # include "getopt.h" #endif #include "os_types.h" #include "sha1.h" #include "jbig2.h" #include "jbig2_priv.h" #include "jbig2_image.h" typedef enum { usage, dump, render } jbig2dec_mode; typedef enum { jbig2dec_format_jbig2, jbig2dec_format_pbm, jbig2dec_format_png, jbig2dec_format_none } jbig2dec_format; typedef struct { jbig2dec_mode mode; int verbose, hash; SHA1_CTX *hash_ctx; char *output_file; jbig2dec_format output_format; } jbig2dec_params_t; static int print_version(void); static int print_usage(void); /* page hashing functions */ static void hash_init(jbig2dec_params_t *params) { params->hash_ctx = (SHA1_CTX *) malloc(sizeof(SHA1_CTX)); if (params->hash_ctx == NULL) { fprintf(stderr, "unable to allocate hash state\n"); params->hash = 0; return; } else { SHA1_Init(params->hash_ctx); } } static void hash_image(jbig2dec_params_t *params, Jbig2Image *image) { unsigned int N = image->stride * image->height; SHA1_Update(params->hash_ctx, image->data, N); } static void hash_print(jbig2dec_params_t *params, FILE *out) { unsigned char md[SHA1_DIGEST_SIZE]; char digest[2 * SHA1_DIGEST_SIZE + 1]; int i; SHA1_Final(params->hash_ctx, md); for (i = 0; i < SHA1_DIGEST_SIZE; i++) { snprintf(&(digest[2 * i]), 3, "%02x", md[i]); } fprintf(out, "%s", digest); } static void hash_free(jbig2dec_params_t *params) { free(params->hash_ctx); params->hash_ctx = NULL; } static int set_output_format(jbig2dec_params_t *params, const char *format) { #ifdef HAVE_LIBPNG /* this should really by strncasecmp() TODO: we need to provide our own for portability */ if (!strncmp(format, "png", 3) || !strncmp(format, "PNG", 3)) { params->output_format = jbig2dec_format_png; return 0; } #endif /* default to pbm */ params->output_format = jbig2dec_format_pbm; return 0; } static int parse_options(int argc, char *argv[], jbig2dec_params_t *params) { static struct option long_options[] = { {"version", 0, NULL, 'V'}, {"help", 0, NULL, 'h'}, {"quiet", 0, NULL, 'q'}, {"verbose", 2, NULL, 'v'}, {"dump", 0, NULL, 'd'}, {"hash", 0, NULL, 'm'}, {"output", 1, NULL, 'o'}, {"format", 1, NULL, 't'}, {NULL, 0, NULL, 0} }; int option_idx = 1; int option; while (1) { option = getopt_long(argc, argv, "Vh?qv:do:t:", long_options, &option_idx); if (option == -1) break; switch (option) { case 0: /* unknown long option */ if (!params->verbose) fprintf(stdout, "unrecognized option: --%s\n", long_options[option_idx].name); break; case 'q': params->verbose = 0; break; case 'v': if (optarg) params->verbose = atoi(optarg); else params->verbose = 2; break; case 'h': case '?': params->mode = usage; break; case 'V': /* the GNU Coding Standards suggest --version should override all other options */ print_version(); exit(0); break; case 'd': params->mode = dump; break; case 'm': params->hash = 1; break; case 'o': params->output_file = strdup(optarg); break; case 't': set_output_format(params, optarg); break; default: if (!params->verbose) fprintf(stdout, "unrecognized option: -%c\n", option); break; } } return (optind); } static int print_version(void) { fprintf(stdout, "%s %s\n", PACKAGE, VERSION); return 0; } static int print_usage(void) { fprintf(stderr, "Usage: jbig2dec [options] \n" " or jbig2dec [options] \n" "\n" " When invoked with a single file, it attempts to parse it as\n" " a normal jbig2 file. Invoked with two files, it treats the\n" " first as the global segments, and the second as the segment\n" " stream for a particular page. This is useful for examining\n" " embedded streams.\n" "\n" " available options:\n" " -h --help this usage summary\n" " -q --quiet suppress diagnostic output\n" " -v --verbose set the verbosity level\n" " -d --dump print the structure of the jbig2 file\n" " rather than explicitly decoding\n" " --version program name and version information\n" " --hash print a hash of the decoded document\n" " -o send decoded output to \n" " Defaults to the the input with a different\n" " extension. Pass '-' for stdout.\n" " -t force a particular output file format\n" #ifdef HAVE_LIBPNG " supported options are 'png' and 'pbm'\n" #else " the only supported option is 'pbm'\n" #endif "\n"); return 1; } static int error_callback(void *error_callback_data, const char *buf, Jbig2Severity severity, int32_t seg_idx) { const jbig2dec_params_t *params = (jbig2dec_params_t *) error_callback_data; char *type; char segment[22]; switch (severity) { case JBIG2_SEVERITY_DEBUG: if (params->verbose < 3) return 0; type = "DEBUG"; break;; case JBIG2_SEVERITY_INFO: if (params->verbose < 2) return 0; type = "info"; break;; case JBIG2_SEVERITY_WARNING: if (params->verbose < 1) return 0; type = "WARNING"; break;; case JBIG2_SEVERITY_FATAL: type = "FATAL ERROR"; break;; default: type = "unknown message"; break;; } if (seg_idx == -1) segment[0] = '\0'; else snprintf(segment, sizeof(segment), "(segment 0x%02x)", seg_idx); fprintf(stderr, "jbig2dec %s %s %s\n", type, buf, segment); return 0; } static char * make_output_filename(const char *input_filename, const char *extension) { char *output_filename; const char *c, *e; int len; if (extension == NULL) { fprintf(stderr, "make_output_filename called with no extension!\n"); exit(1); } if (input_filename == NULL) c = "out"; else { /* strip any leading path */ c = strrchr(input_filename, '/'); /* *nix */ if (c == NULL) c = strrchr(input_filename, '\\'); /* win32/dos */ if (c != NULL) c++; /* skip the path separator */ else c = input_filename; /* no leading path */ } /* make sure we haven't just stripped the last character */ if (*c == '\0') c = "out"; /* strip the extension */ len = strlen(c); e = strrchr(c, '.'); if (e != NULL) len -= strlen(e); /* allocate enough space for the base + ext */ output_filename = (char *)malloc(len + strlen(extension) + 1); if (output_filename == NULL) { fprintf(stderr, "couldn't allocate memory for output_filename\n"); exit(1); } strncpy(output_filename, c, len); strncpy(output_filename + len, extension, strlen(extension)); *(output_filename + len + strlen(extension)) = '\0'; /* return the new string */ return (output_filename); } static int write_page_image(jbig2dec_params_t *params, Jbig2Image *image) { if (!strncmp(params->output_file, "-", 2)) { switch (params->output_format) { #ifdef HAVE_LIBPNG case jbig2dec_format_png: jbig2_image_write_png(image, stdout); break; #endif case jbig2dec_format_pbm: jbig2_image_write_pbm(image, stdout); break; default: fprintf(stderr, "unsupported output format.\n"); return 1; } } else { if (params->verbose > 1) fprintf(stderr, "saving decoded page as '%s'\n", params->output_file); switch (params->output_format) { #ifdef HAVE_LIBPNG case jbig2dec_format_png: jbig2_image_write_png_file(image, params->output_file); break; #endif case jbig2dec_format_pbm: jbig2_image_write_pbm_file(image, params->output_file); break; default: fprintf(stderr, "unsupported output format.\n"); return 1; } } return 0; } static int write_document_hash(jbig2dec_params_t *params) { FILE *out; if (!strncmp(params->output_file, "-", 2)) { out = stderr; } else { out = stdout; } fprintf(out, "Hash of decoded document: "); hash_print(params, out); fprintf(out, "\n"); return 0; } int main(int argc, char **argv) { FILE *f = NULL, *f_page = NULL; Jbig2Ctx *ctx; uint8_t buf[4096]; jbig2dec_params_t params; int filearg; /* set defaults */ params.mode = render; params.verbose = 1; params.hash = 0; params.output_file = NULL; params.output_format = jbig2dec_format_none; filearg = parse_options(argc, argv, ¶ms); if (params.hash) hash_init(¶ms); switch (params.mode) { case usage: print_usage(); exit(0); break; case dump: fprintf(stderr, "Sorry, segment dump not yet implemented\n"); break; case render: if ((argc - filearg) == 1) /* only one argument--open as a jbig2 file */ { char *fn = argv[filearg]; f = fopen(fn, "rb"); if (f == NULL) { fprintf(stderr, "error opening %s\n", fn); return 1; } } else if ((argc - filearg) == 2) /* two arguments open as separate global and page streams */ { char *fn = argv[filearg]; char *fn_page = argv[filearg + 1]; f = fopen(fn, "rb"); if (f == NULL) { fprintf(stderr, "error opening %s\n", fn); return 1; } f_page = fopen(fn_page, "rb"); if (f_page == NULL) { fclose(f); fprintf(stderr, "error opening %s\n", fn_page); return 1; } } else /* any other number of arguments */ return print_usage(); ctx = jbig2_ctx_new(NULL, (Jbig2Options)(f_page != NULL ? JBIG2_OPTIONS_EMBEDDED : 0), NULL, error_callback, ¶ms); /* pull the whole file/global stream into memory */ for (;;) { int n_bytes = fread(buf, 1, sizeof(buf), f); if (n_bytes <= 0) break; if (jbig2_data_in(ctx, buf, n_bytes)) break; } fclose(f); /* if there's a local page stream read that in its entirety */ if (f_page != NULL) { Jbig2GlobalCtx *global_ctx = jbig2_make_global_ctx(ctx); ctx = jbig2_ctx_new(NULL, JBIG2_OPTIONS_EMBEDDED, global_ctx, error_callback, ¶ms); for (;;) { int n_bytes = fread(buf, 1, sizeof(buf), f_page); if (n_bytes <= 0) break; if (jbig2_data_in(ctx, buf, n_bytes)) break; } fclose(f_page); jbig2_global_ctx_free(global_ctx); } /* retrieve and output the returned pages */ { Jbig2Image *image; /* work around broken CVision embedded streams */ if (f_page != NULL) jbig2_complete_page(ctx); if (params.output_file == NULL) { #ifdef HAVE_LIBPNG params.output_file = make_output_filename(argv[filearg], ".png"); params.output_format = jbig2dec_format_png; #else params.output_file = make_output_filename(argv[filearg], ".pbm"); params.output_format = jbig2dec_format_pbm; #endif } else { int len = strlen(params.output_file); if ((len >= 3) && (params.output_format == jbig2dec_format_none)) /* try to set the output type by the given extension */ set_output_format(¶ms, params.output_file + len - 3); } /* retrieve and write out all the completed pages */ while ((image = jbig2_page_out(ctx)) != NULL) { write_page_image(¶ms, image); if (params.hash) hash_image(¶ms, image); jbig2_release_page(ctx, image); } if (params.hash) write_document_hash(¶ms); } jbig2_ctx_free(ctx); } /* end params.mode switch */ if (params.output_file) free(params.output_file); if (params.hash) hash_free(¶ms); /* fin */ return 0; } jbig2dec-0.13/memcmp.c000066400000000000000000000025041270170036400145310ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* replacement for broken memcmp() */ /* * compares two byte strings 'a' and 'b', both assumed to be 'len' bytes long * returns zero if the two strings are identical, otherwise returns -1 or 1 * depending on the relative magnitude of the first differing elements, * considered as unsigned chars */ int memcmp(const void *b1, const void *b2, size_t len) { unsigned char *a, *b; size_t i; a = (unsigned char *)b1; b = (unsigned char *)b2; for (i = 0; i < len; i++) { if (*a != *b) { /* strings differ */ return (*a < *b) ? -1 : 1; } a++; b++; } /* strings match */ return 0; } jbig2dec-0.13/memento.c000066400000000000000000001165711270170036400147310ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* Inspired by Fortify by Simon P Bullen. */ /* Set the following if you're only looking for leaks, not memory overwrites * to speed the operation */ /* #define MEMENTO_LEAKONLY */ #ifndef MEMENTO_STACKTRACE_METHOD #ifdef __GNUC__ #define MEMENTO_STACKTRACE_METHOD 1 #endif #endif /* Don't keep blocks around if they'd mean losing more than a quarter of * the freelist. */ #define MEMENTO_FREELIST_MAX_SINGLE_BLOCK (MEMENTO_FREELIST_MAX/4) #define COMPILING_MEMENTO_C #ifdef MEMENTO_GS_HACKS /* For GS we include malloc_.h. Anyone else would just include memento.h */ #include "malloc_.h" #ifdef __MACH__ #include #else #ifndef memset void *memset(void *, int, size_t); #endif #endif int atexit(void (*)(void)); #else #include "memento.h" #include #include #endif #if defined(__linux__) #define MEMENTO_HAS_FORK #elif defined(__APPLE__) && defined(__MACH__) #define MEMENTO_HAS_FORK #endif /* Define the underlying allocators, just in case */ void *MEMENTO_UNDERLYING_MALLOC(size_t); void MEMENTO_UNDERLYING_FREE(void *); void *MEMENTO_UNDERLYING_REALLOC(void *, size_t); void *MEMENTO_UNDERLYING_CALLOC(size_t, size_t); /* And some other standard functions we use. We don't include the header * files, just in case they pull in unexpected others. */ int atoi(const char *); char *getenv(const char *); /* How far to search for pointers in each block when calculating nestings */ /* mupdf needs at least 34000ish (sizeof(fz_shade))/ */ #define MEMENTO_PTRSEARCH 65536 #ifndef MEMENTO_MAXPATTERN #define MEMENTO_MAXPATTERN 0 #endif #ifdef MEMENTO #ifdef MEMENTO_GS_HACKS #include "valgrind.h" #else #ifdef HAVE_VALGRIND #include "valgrind/memcheck.h" #else #define VALGRIND_MAKE_MEM_NOACCESS(p,s) do { } while (0==1) #define VALGRIND_MAKE_MEM_UNDEFINED(p,s) do { } while (0==1) #define VALGRIND_MAKE_MEM_DEFINED(p,s) do { } while (0==1) #endif #endif enum { Memento_PreSize = 16, Memento_PostSize = 16 }; enum { Memento_Flag_OldBlock = 1, Memento_Flag_HasParent = 2, Memento_Flag_BreakOnFree = 4, Memento_Flag_BreakOnRealloc = 8 }; /* When we list leaked blocks at the end of execution, we search for pointers * between blocks in order to be able to give a nice nested view. * Unfortunately, if you have are running your own allocator (such as * ghostscripts chunk allocator) you can often find that the header of the * block always contains pointers to next or previous blocks. This tends to * mean the nesting displayed is "uninteresting" at best :) * * As a hack to get around this, we have a define MEMENTO_SKIP_SEARCH that * indicates how many bytes to skip over at the start of the chunk. * This may cause us to miss true nestings, but such is life... */ #ifndef MEMENTO_SEARCH_SKIP #ifdef MEMENTO_GS_HACKS #define MEMENTO_SEARCH_SKIP (2*sizeof(void *)) #else #define MEMENTO_SEARCH_SKIP 0 #endif #endif typedef struct Memento_BlkHeader Memento_BlkHeader; struct Memento_BlkHeader { size_t rawsize; int sequence; int lastCheckedOK; int flags; Memento_BlkHeader *next; Memento_BlkHeader *parent; /* Only used while printing out nested list */ const char *label; /* Entries for nesting display calculations */ Memento_BlkHeader *child; Memento_BlkHeader *sibling; char preblk[Memento_PreSize]; }; /* In future this could (should) be a smarter data structure, like, say, * splay trees. For now, we use a list. */ typedef struct Memento_Blocks { Memento_BlkHeader *head; Memento_BlkHeader **tail; } Memento_Blocks; /* And our global structure */ static struct { int inited; Memento_Blocks used; Memento_Blocks free; size_t freeListSize; int sequence; int paranoia; int paranoidAt; int countdown; int lastChecked; int breakAt; int failAt; int failing; int nextFailAt; int squeezeAt; int squeezing; int segv; int pattern; int nextPattern; int patternBit; size_t maxMemory; size_t alloc; size_t peakAlloc; size_t totalAlloc; size_t numMallocs; size_t numFrees; size_t numReallocs; } globals; #define MEMENTO_EXTRASIZE (sizeof(Memento_BlkHeader) + Memento_PostSize) /* Round up size S to the next multiple of N (where N is a power of 2) */ #define MEMENTO_ROUNDUP(S,N) ((S + N-1)&~(N-1)) #define MEMBLK_SIZE(s) MEMENTO_ROUNDUP(s + MEMENTO_EXTRASIZE, MEMENTO_MAXALIGN) #define MEMBLK_FROMBLK(B) (&((Memento_BlkHeader*)(void *)(B))[-1]) #define MEMBLK_TOBLK(B) ((void*)(&((Memento_BlkHeader*)(void*)(B))[1])) #define MEMBLK_POSTPTR(B) \ (&((char *)(void *)(B))[(B)->rawsize + sizeof(Memento_BlkHeader)]) void Memento_breakpoint(void) { /* A handy externally visible function for breakpointing */ #if 0 /* Enable this to force automatic breakpointing */ #ifdef DEBUG #ifdef _MSC_VER __asm int 3; #endif #endif #endif } static void Memento_addBlockHead(Memento_Blocks *blks, Memento_BlkHeader *b, int type) { if (blks->tail == &blks->head) { /* Adding into an empty list, means the tail changes too */ blks->tail = &b->next; } b->next = blks->head; blks->head = b; #ifndef MEMENTO_LEAKONLY memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); #endif VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); if (type == 0) { /* malloc */ VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); } else if (type == 1) { /* free */ VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); } VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); } static void Memento_addBlockTail(Memento_Blocks *blks, Memento_BlkHeader *b, int type) { VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(Memento_BlkHeader *)); *blks->tail = b; blks->tail = &b->next; b->next = NULL; VALGRIND_MAKE_MEM_NOACCESS(blks->tail, sizeof(Memento_BlkHeader *)); #ifndef MEMENTO_LEAKONLY memset(b->preblk, MEMENTO_PREFILL, Memento_PreSize); memset(MEMBLK_POSTPTR(b), MEMENTO_POSTFILL, Memento_PostSize); #endif VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(b), Memento_PostSize); if (type == 0) { /* malloc */ VALGRIND_MAKE_MEM_UNDEFINED(MEMBLK_TOBLK(b), b->rawsize); } else if (type == 1) { /* free */ VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_TOBLK(b), b->rawsize); } VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader)); } typedef struct BlkCheckData { int found; int preCorrupt; int postCorrupt; int freeCorrupt; int index; } BlkCheckData; static int Memento_Internal_checkAllocedBlock(Memento_BlkHeader *b, void *arg) { #ifndef MEMENTO_LEAKONLY int i; char *p; int corrupt = 0; BlkCheckData *data = (BlkCheckData *) arg; p = b->preblk; i = Memento_PreSize; do { corrupt |= (*p++ ^ (char)MEMENTO_PREFILL); } while (--i); if (corrupt) { data->preCorrupt = 1; } p = MEMBLK_POSTPTR(b); i = Memento_PreSize; do { corrupt |= (*p++ ^ (char)MEMENTO_POSTFILL); } while (--i); if (corrupt) { data->postCorrupt = 1; } if ((data->freeCorrupt | data->preCorrupt | data->postCorrupt) == 0) { b->lastCheckedOK = globals.sequence; } data->found |= 1; #endif return 0; } static int Memento_Internal_checkFreedBlock(Memento_BlkHeader *b, void *arg) { #ifndef MEMENTO_LEAKONLY int i; char *p; BlkCheckData *data = (BlkCheckData *) arg; p = MEMBLK_TOBLK(b); i = b->rawsize; /* Attempt to speed this up by checking an (aligned) int at a time */ do { if (((size_t) p) & 1) { if (*p++ != (char)MEMENTO_FREEFILL) break; i--; if (i == 0) break; } if ((i >= 2) && (((size_t) p) & 2)) { if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL << 8))) goto mismatch; p += 2; i -= 2; if (i == 0) break; } i -= 4; while (i >= 0) { if (*(int *)p != (MEMENTO_FREEFILL | (MEMENTO_FREEFILL << 8) | (MEMENTO_FREEFILL << 16) | (MEMENTO_FREEFILL << 24))) goto mismatch; p += 4; i -= 4; } i += 4; if ((i >= 2) && (((size_t) p) & 2)) { if (*(short *)p != (short)(MEMENTO_FREEFILL | (MEMENTO_FREEFILL << 8))) goto mismatch; p += 2; i -= 2; } mismatch: while (i) { if (*p++ != (char)MEMENTO_FREEFILL) break; i--; } } while (0); if (i) { data->freeCorrupt = 1; data->index = b->rawsize - i; } return Memento_Internal_checkAllocedBlock(b, arg); #else return 0; #endif } static void Memento_removeBlock(Memento_Blocks *blks, Memento_BlkHeader *b) { Memento_BlkHeader *head = blks->head; Memento_BlkHeader *prev = NULL; while ((head) && (head != b)) { VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); prev = head; head = head->next; VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev)); } if (head == NULL) { /* FAIL! Will have been reported to user earlier, so just exit. */ return; } VALGRIND_MAKE_MEM_DEFINED(blks->tail, sizeof(*blks->tail)); if (*blks->tail == head) { /* Removing the tail of the list */ if (prev == NULL) { /* Which is also the head */ blks->tail = &blks->head; } else { /* Which isn't the head */ blks->tail = &prev->next; } } if (prev == NULL) { /* Removing from the head of the list */ VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); blks->head = head->next; VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head)); } else { /* Removing from not-the-head */ VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); VALGRIND_MAKE_MEM_DEFINED(prev, sizeof(*prev)); prev->next = head->next; VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(*head)); VALGRIND_MAKE_MEM_NOACCESS(prev, sizeof(*prev)); } } static int Memento_Internal_makeSpace(size_t space) { /* If too big, it can never go on the freelist */ if (space > MEMENTO_FREELIST_MAX_SINGLE_BLOCK) return 0; /* Pretend we added it on. */ globals.freeListSize += space; /* Ditch blocks until it fits within our limit */ while (globals.freeListSize > MEMENTO_FREELIST_MAX) { Memento_BlkHeader *head = globals.free.head; VALGRIND_MAKE_MEM_DEFINED(head, sizeof(*head)); globals.free.head = head->next; globals.freeListSize -= MEMBLK_SIZE(head->rawsize); MEMENTO_UNDERLYING_FREE(head); } /* Make sure we haven't just completely emptied the free list */ /* (This should never happen, but belt and braces... */ if (globals.free.head == NULL) globals.free.tail = &globals.free.head; return 1; } static int Memento_appBlocks(Memento_Blocks *blks, int (*app)(Memento_BlkHeader *, void *), void *arg) { Memento_BlkHeader *head = blks->head; Memento_BlkHeader *next; int result; while (head) { VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), head->rawsize + Memento_PostSize); result = app(head, arg); next = head->next; VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); if (result) return result; head = next; } return 0; } static int Memento_appBlock(Memento_Blocks *blks, int (*app)(Memento_BlkHeader *, void *), void *arg, Memento_BlkHeader *b) { Memento_BlkHeader *head = blks->head; Memento_BlkHeader *next; int result; while (head && head != b) { VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); next = head->next; VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); head = next; } if (head == b) { VALGRIND_MAKE_MEM_DEFINED(head, sizeof(Memento_BlkHeader)); VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(head), head->rawsize + Memento_PostSize); result = app(head, arg); VALGRIND_MAKE_MEM_NOACCESS(MEMBLK_POSTPTR(head), Memento_PostSize); VALGRIND_MAKE_MEM_NOACCESS(head, sizeof(Memento_BlkHeader)); return result; } return 0; } static void showBlock(Memento_BlkHeader *b, int space) { fprintf(stderr, "0x%p:(size=%d,num=%d)", MEMBLK_TOBLK(b), (int)b->rawsize, b->sequence); if (b->label) fprintf(stderr, "%c(%s)", space, b->label); } static void blockDisplay(Memento_BlkHeader *b, int n) { n++; while (n > 0) { int i = n; if (i > 32) i = 32; n -= i; fprintf(stderr, "%s", &" "[32 - i]); } showBlock(b, '\t'); fprintf(stderr, "\n"); } static int Memento_listBlock(Memento_BlkHeader *b, void *arg) { int *counts = (int *)arg; blockDisplay(b, 0); counts[0]++; counts[1] += b->rawsize; return 0; } static void doNestedDisplay(Memento_BlkHeader *b, int depth) { blockDisplay(b, depth); for (b = b->child; b; b = b->sibling) doNestedDisplay(b, depth + 1); } static int ptrcmp(const void *a_, const void *b_) { const char **a = (const char **)a_; const char **b = (const char **)b_; return (int)(*a - *b); } static int Memento_listBlocksNested(void) { int count, size, i; Memento_BlkHeader *b; void **blocks, *minptr, *maxptr; long mask; /* Count the blocks */ count = 0; size = 0; for (b = globals.used.head; b; b = b->next) { size += b->rawsize; count++; } /* Make our block list */ blocks = MEMENTO_UNDERLYING_MALLOC(sizeof(void *) * count); if (blocks == NULL) return 1; /* Populate our block list */ b = globals.used.head; minptr = maxptr = MEMBLK_TOBLK(b); mask = (long)minptr; for (i = 0; b; b = b->next, i++) { void *p = MEMBLK_TOBLK(b); mask &= (long)p; if (p < minptr) minptr = p; if (p > maxptr) maxptr = p; blocks[i] = p; b->flags &= ~Memento_Flag_HasParent; b->child = NULL; b->sibling = NULL; b->parent = NULL; } qsort(blocks, count, sizeof(void *), ptrcmp); /* Now, calculate tree */ for (b = globals.used.head; b; b = b->next) { char *p = MEMBLK_TOBLK(b); int end = (b->rawsize < MEMENTO_PTRSEARCH ? b->rawsize : MEMENTO_PTRSEARCH); for (i = MEMENTO_SEARCH_SKIP; i < end; i += sizeof(void *)) { void *q = *(void **)(&p[i]); void **r; /* Do trivial checks on pointer */ if ((mask & (int)q) != mask || q < minptr || q > maxptr) continue; /* Search for pointer */ r = bsearch(&q, blocks, count, sizeof(void *), ptrcmp); if (r) { /* Found child */ Memento_BlkHeader *child = MEMBLK_FROMBLK(*r); Memento_BlkHeader *parent; /* We're assuming tree structure, not graph - ignore second * and subsequent pointers. */ if (child->parent != NULL) continue; if (child->flags & Memento_Flag_HasParent) continue; /* We're also assuming acyclicness here. If this is one of * our parents, ignore it. */ parent = b->parent; while (parent != NULL && parent != child) parent = parent->parent; if (parent == child) continue; child->sibling = b->child; b->child = child; child->parent = b; child->flags |= Memento_Flag_HasParent; } } } /* Now display with nesting */ for (b = globals.used.head; b; b = b->next) { if ((b->flags & Memento_Flag_HasParent) == 0) doNestedDisplay(b, 0); } fprintf(stderr, " Total number of blocks = %d\n", count); fprintf(stderr, " Total size of blocks = %d\n", size); MEMENTO_UNDERLYING_FREE(blocks); return 0; } void Memento_listBlocks(void) { fprintf(stderr, "Allocated blocks:\n"); if (Memento_listBlocksNested()) { int counts[2]; counts[0] = 0; counts[1] = 0; Memento_appBlocks(&globals.used, Memento_listBlock, &counts[0]); fprintf(stderr, " Total number of blocks = %d\n", counts[0]); fprintf(stderr, " Total size of blocks = %d\n", counts[1]); } } static int Memento_listNewBlock(Memento_BlkHeader *b, void *arg) { if (b->flags & Memento_Flag_OldBlock) return 0; b->flags |= Memento_Flag_OldBlock; return Memento_listBlock(b, arg); } void Memento_listNewBlocks(void) { int counts[2]; counts[0] = 0; counts[1] = 0; fprintf(stderr, "Blocks allocated and still extant since last list:\n"); Memento_appBlocks(&globals.used, Memento_listNewBlock, &counts[0]); fprintf(stderr, " Total number of blocks = %d\n", counts[0]); fprintf(stderr, " Total size of blocks = %d\n", counts[1]); } static void Memento_endStats(void) { fprintf(stderr, "Total memory malloced = %u bytes\n", (unsigned int)globals.totalAlloc); fprintf(stderr, "Peak memory malloced = %u bytes\n", (unsigned int)globals.peakAlloc); fprintf(stderr, "%u mallocs, %u frees, %u reallocs\n", (unsigned int)globals.numMallocs, (unsigned int)globals.numFrees, (unsigned int)globals.numReallocs); fprintf(stderr, "Average allocation size %u bytes\n", (unsigned int) (globals.numMallocs != 0 ? globals.totalAlloc / globals.numMallocs : 0)); } void Memento_stats(void) { fprintf(stderr, "Current memory malloced = %u bytes\n", (unsigned int)globals.alloc); Memento_endStats(); } static void Memento_fin(void) { Memento_checkAllMemory(); Memento_endStats(); if (globals.used.head != NULL) { Memento_listBlocks(); Memento_breakpoint(); } if (globals.segv) { fprintf(stderr, "Memory dumped on SEGV while squeezing @ %d\n", globals.failAt); } else if (globals.squeezing) { if (globals.pattern == 0) fprintf(stderr, "Memory squeezing @ %d complete\n", globals.squeezeAt); else fprintf(stderr, "Memory squeezing @ %d (%d) complete\n", globals.squeezeAt, globals.pattern); } if (globals.failing) { fprintf(stderr, "MEMENTO_FAILAT=%d\n", globals.failAt); fprintf(stderr, "MEMENTO_PATTERN=%d\n", globals.pattern); } if (globals.nextFailAt != 0) { fprintf(stderr, "MEMENTO_NEXTFAILAT=%d\n", globals.nextFailAt); fprintf(stderr, "MEMENTO_NEXTPATTERN=%d\n", globals.nextPattern); } } static void Memento_inited(void) { /* A good place for a breakpoint */ } static void Memento_init(void) { char *env; memset(&globals, 0, sizeof(globals)); globals.inited = 1; globals.used.head = NULL; globals.used.tail = &globals.used.head; globals.free.head = NULL; globals.free.tail = &globals.free.head; globals.sequence = 0; globals.countdown = 1024; env = getenv("MEMENTO_FAILAT"); globals.failAt = (env ? atoi(env) : 0); env = getenv("MEMENTO_PARANOIA"); globals.paranoia = (env ? atoi(env) : 0); if (globals.paranoia == 0) globals.paranoia = 1024; env = getenv("MEMENTO_PARANOIDAT"); globals.paranoidAt = (env ? atoi(env) : 0); env = getenv("MEMENTO_SQUEEZEAT"); globals.squeezeAt = (env ? atoi(env) : 0); env = getenv("MEMENTO_PATTERN"); globals.pattern = (env ? atoi(env) : 0); env = getenv("MEMENTO_MAXMEMORY"); globals.maxMemory = (env ? atoi(env) : 0); atexit(Memento_fin); Memento_inited(); } #ifdef MEMENTO_HAS_FORK #include #include #ifdef MEMENTO_STACKTRACE_METHOD #if MEMENTO_STACKTRACE_METHOD == 1 #include #endif #endif /* FIXME: Find some portable way of getting this */ /* MacOSX has 10240, Ubuntu seems to have 256 */ #define OPEN_MAX 10240 /* stashed_map[j] = i means that filedescriptor i-1 was duplicated to j */ int stashed_map[OPEN_MAX]; extern size_t backtrace(void **, int); extern void backtrace_symbols_fd(void **, size_t, int); static void Memento_signal(void) { fprintf(stderr, "SEGV after Memory squeezing @ %d\n", globals.squeezeAt); #ifdef MEMENTO_STACKTRACE_METHOD #if MEMENTO_STACKTRACE_METHOD == 1 { void *array[100]; size_t size; size = backtrace(array, 100); fprintf(stderr, "------------------------------------------------------------------------\n"); fprintf(stderr, "Backtrace:\n"); backtrace_symbols_fd(array, size, 2); fprintf(stderr, "------------------------------------------------------------------------\n"); } #endif #endif exit(1); } static int squeeze(void) { pid_t pid; int i, status; if (globals.patternBit < 0) return 1; if (globals.squeezing && globals.patternBit >= MEMENTO_MAXPATTERN) return 1; if (globals.patternBit == 0) globals.squeezeAt = globals.sequence; if (!globals.squeezing) { fprintf(stderr, "Memory squeezing @ %d\n", globals.squeezeAt); } else fprintf(stderr, "Memory squeezing @ %d (%x,%x)\n", globals.squeezeAt, globals.pattern, globals.patternBit); /* When we fork below, the child is going to snaffle all our file pointers * and potentially corrupt them. Let's make copies of all of them before * we fork, so we can restore them when we restart. */ for (i = 0; i < OPEN_MAX; i++) { if (stashed_map[i] == 0) { int j = dup(i); stashed_map[j] = i + 1; } } pid = fork(); if (pid == 0) { /* Child */ signal(SIGSEGV, Memento_signal); /* In the child, we always fail the next allocation. */ if (globals.patternBit == 0) { globals.patternBit = 1; } else globals.patternBit <<= 1; globals.squeezing = 1; return 1; } /* In the parent if we hit another allocation, pass it (and record the * fact we passed it in the pattern. */ globals.pattern |= globals.patternBit; globals.patternBit <<= 1; /* Wait for pid to finish */ waitpid(pid, &status, 0); if (status != 0) { fprintf(stderr, "Child status=%d\n", status); } /* Put the files back */ for (i = 0; i < OPEN_MAX; i++) { if (stashed_map[i] != 0) { dup2(i, stashed_map[i] - 1); close(i); stashed_map[i] = 0; } } return 0; } #else #include static void Memento_signal(void) { globals.segv = 1; /* If we just return from this function the SEGV will be unhandled, and * we'll launch into whatever JIT debugging system the OS provides. At * least output something useful first. If MEMENTO_NOJIT is set, then * just exit to avoid the JIT (and get the usual atexit handling). */ if (getenv("MEMENTO_NOJIT")) exit(1); else Memento_fin(); } int squeeze(void) { fprintf(stderr, "Memento memory squeezing disabled as no fork!\n"); return 0; } #endif static void Memento_startFailing(void) { if (!globals.failing) { fprintf(stderr, "Starting to fail...\n"); fflush(stderr); globals.failing = 1; globals.failAt = globals.sequence; globals.nextFailAt = globals.sequence + 1; globals.pattern = 0; globals.patternBit = 0; signal(SIGSEGV, Memento_signal); signal(SIGABRT, Memento_signal); Memento_breakpoint(); } } static void Memento_event(void) { globals.sequence++; if ((globals.sequence >= globals.paranoidAt) && (globals.paranoidAt != 0)) { globals.paranoia = 1; globals.countdown = 1; } if (--globals.countdown == 0) { Memento_checkAllMemory(); globals.countdown = globals.paranoia; } if (globals.sequence == globals.breakAt) { fprintf(stderr, "Breaking at event %d\n", globals.breakAt); Memento_breakpoint(); } } int Memento_breakAt(int event) { globals.breakAt = event; return event; } void * Memento_label(void *ptr, const char *label) { Memento_BlkHeader *block; if (ptr == NULL) return NULL; block = MEMBLK_FROMBLK(ptr); block->label = label; return ptr; } int Memento_failThisEvent(void) { int failThisOne; if (!globals.inited) Memento_init(); Memento_event(); if ((globals.sequence >= globals.failAt) && (globals.failAt != 0)) Memento_startFailing(); if ((globals.sequence >= globals.squeezeAt) && (globals.squeezeAt != 0)) { return squeeze(); } if (!globals.failing) return 0; failThisOne = ((globals.patternBit & globals.pattern) == 0); /* If we are failing, and we've reached the end of the pattern and we've * still got bits available in the pattern word, and we haven't already * set a nextPattern, then extend the pattern. */ if (globals.failing && ((~(globals.patternBit - 1) & globals.pattern) == 0) && (globals.patternBit != 0) && globals.nextPattern == 0) { /* We'll fail this one, and set the 'next' one to pass it. */ globals.nextFailAt = globals.failAt; globals.nextPattern = globals.pattern | globals.patternBit; } globals.patternBit = (globals.patternBit ? globals.patternBit << 1 : 1); return failThisOne; } void * Memento_malloc(size_t s) { Memento_BlkHeader *memblk; size_t smem = MEMBLK_SIZE(s); if (Memento_failThisEvent()) return NULL; if (s == 0) return NULL; globals.numMallocs++; if (globals.maxMemory != 0 && globals.alloc + s > globals.maxMemory) return NULL; memblk = MEMENTO_UNDERLYING_MALLOC(smem); if (memblk == NULL) return NULL; globals.alloc += s; globals.totalAlloc += s; if (globals.peakAlloc < globals.alloc) globals.peakAlloc = globals.alloc; #ifndef MEMENTO_LEAKONLY memset(MEMBLK_TOBLK(memblk), MEMENTO_ALLOCFILL, s); #endif memblk->rawsize = s; memblk->sequence = globals.sequence; memblk->lastCheckedOK = memblk->sequence; memblk->flags = 0; memblk->label = 0; memblk->child = NULL; memblk->sibling = NULL; Memento_addBlockHead(&globals.used, memblk, 0); return MEMBLK_TOBLK(memblk); } void * Memento_calloc(size_t n, size_t s) { void *block = Memento_malloc(n * s); if (block) memset(block, 0, n * s); return block; } static int checkBlock(Memento_BlkHeader *memblk, const char *action) { #ifndef MEMENTO_LEAKONLY BlkCheckData data; memset(&data, 0, sizeof(data)); Memento_appBlock(&globals.used, Memento_Internal_checkAllocedBlock, &data, memblk); if (!data.found) { /* Failure! */ fprintf(stderr, "Attempt to %s block ", action); showBlock(memblk, 32); Memento_breakpoint(); return 1; } else if (data.preCorrupt || data.postCorrupt) { fprintf(stderr, "Block "); showBlock(memblk, ' '); fprintf(stderr, " found to be corrupted on %s!\n", action); if (data.preCorrupt) { fprintf(stderr, "Preguard corrupted\n"); } if (data.postCorrupt) { fprintf(stderr, "Postguard corrupted\n"); } fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, globals.sequence); Memento_breakpoint(); return 1; } #endif return 0; } void Memento_free(void *blk) { Memento_BlkHeader *memblk; if (!globals.inited) Memento_init(); Memento_event(); if (blk == NULL) return; memblk = MEMBLK_FROMBLK(blk); VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); if (checkBlock(memblk, "free")) return; if (memblk->flags & Memento_Flag_BreakOnFree) Memento_breakpoint(); VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); globals.alloc -= memblk->rawsize; globals.numFrees++; Memento_removeBlock(&globals.used, memblk); VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); if (Memento_Internal_makeSpace(MEMBLK_SIZE(memblk->rawsize))) { VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(*memblk)); VALGRIND_MAKE_MEM_DEFINED(MEMBLK_TOBLK(memblk), memblk->rawsize + Memento_PostSize); #ifndef MEMENTO_LEAKONLY memset(MEMBLK_TOBLK(memblk), MEMENTO_FREEFILL, memblk->rawsize); #endif Memento_addBlockTail(&globals.free, memblk, 1); } else { MEMENTO_UNDERLYING_FREE(memblk); } } void * Memento_realloc(void *blk, size_t newsize) { Memento_BlkHeader *memblk, *newmemblk; size_t newsizemem; int flags; if (blk == NULL) return Memento_malloc(newsize); if (newsize == 0) { Memento_free(blk); return NULL; } if (Memento_failThisEvent()) return NULL; memblk = MEMBLK_FROMBLK(blk); if (checkBlock(memblk, "realloc")) return NULL; if (memblk->flags & Memento_Flag_BreakOnRealloc) Memento_breakpoint(); if (globals.maxMemory != 0 && globals.alloc - memblk->rawsize + newsize > globals.maxMemory) return NULL; newsizemem = MEMBLK_SIZE(newsize); Memento_removeBlock(&globals.used, memblk); flags = memblk->flags; newmemblk = MEMENTO_UNDERLYING_REALLOC(memblk, newsizemem); if (newmemblk == NULL) { Memento_addBlockHead(&globals.used, memblk, 2); return NULL; } globals.numReallocs++; globals.totalAlloc += newsize; globals.alloc -= newmemblk->rawsize; globals.alloc += newsize; if (globals.peakAlloc < globals.alloc) globals.peakAlloc = globals.alloc; newmemblk->flags = flags; if (newmemblk->rawsize < newsize) { char *newbytes = ((char *)MEMBLK_TOBLK(newmemblk)) + newmemblk->rawsize; #ifndef MEMENTO_LEAKONLY memset(newbytes, MEMENTO_ALLOCFILL, newsize - newmemblk->rawsize); #endif VALGRIND_MAKE_MEM_UNDEFINED(newbytes, newsize - newmemblk->rawsize); } newmemblk->rawsize = newsize; #ifndef MEMENTO_LEAKONLY memset(newmemblk->preblk, MEMENTO_PREFILL, Memento_PreSize); memset(MEMBLK_POSTPTR(newmemblk), MEMENTO_POSTFILL, Memento_PostSize); #endif Memento_addBlockHead(&globals.used, newmemblk, 2); return MEMBLK_TOBLK(newmemblk); } int Memento_checkBlock(void *blk) { Memento_BlkHeader *memblk; if (blk == NULL) return 0; memblk = MEMBLK_FROMBLK(blk); return checkBlock(memblk, "check"); } static int Memento_Internal_checkAllAlloced(Memento_BlkHeader *memblk, void *arg) { BlkCheckData *data = (BlkCheckData *) arg; Memento_Internal_checkAllocedBlock(memblk, data); if (data->preCorrupt || data->postCorrupt) { if ((data->found & 2) == 0) { fprintf(stderr, "Allocated blocks:\n"); data->found |= 2; } fprintf(stderr, " Block "); showBlock(memblk, ' '); if (data->preCorrupt) { fprintf(stderr, " Preguard "); } if (data->postCorrupt) { fprintf(stderr, "%s Postguard ", (data->preCorrupt ? "&" : "")); } fprintf(stderr, "corrupted.\n " "Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, globals.sequence); data->preCorrupt = 0; data->postCorrupt = 0; data->freeCorrupt = 0; } else memblk->lastCheckedOK = globals.sequence; return 0; } static int Memento_Internal_checkAllFreed(Memento_BlkHeader *memblk, void *arg) { BlkCheckData *data = (BlkCheckData *) arg; Memento_Internal_checkFreedBlock(memblk, data); if (data->preCorrupt || data->postCorrupt || data->freeCorrupt) { if ((data->found & 4) == 0) { fprintf(stderr, "Freed blocks:\n"); data->found |= 4; } fprintf(stderr, " "); showBlock(memblk, ' '); if (data->freeCorrupt) { fprintf(stderr, " index %d (address 0x%p) onwards", data->index, &((char *)MEMBLK_TOBLK(memblk))[data->index]); if (data->preCorrupt) { fprintf(stderr, "+ preguard"); } if (data->postCorrupt) { fprintf(stderr, "+ postguard"); } } else { if (data->preCorrupt) { fprintf(stderr, " preguard"); } if (data->postCorrupt) { fprintf(stderr, "%s Postguard", (data->preCorrupt ? "+" : "")); } } fprintf(stderr, " corrupted.\n" " Block last checked OK at allocation %d. Now %d.\n", memblk->lastCheckedOK, globals.sequence); data->preCorrupt = 0; data->postCorrupt = 0; data->freeCorrupt = 0; } else memblk->lastCheckedOK = globals.sequence; return 0; } int Memento_checkAllMemory(void) { #ifndef MEMENTO_LEAKONLY BlkCheckData data; memset(&data, 0, sizeof(data)); Memento_appBlocks(&globals.used, Memento_Internal_checkAllAlloced, &data); Memento_appBlocks(&globals.free, Memento_Internal_checkAllFreed, &data); if (data.found & 6) { Memento_breakpoint(); return 1; } #endif return 0; } int Memento_setParanoia(int i) { globals.paranoia = i; globals.countdown = globals.paranoia; return i; } int Memento_paranoidAt(int i) { globals.paranoidAt = i; return i; } int Memento_getBlockNum(void *b) { Memento_BlkHeader *memblk; if (b == NULL) return 0; memblk = MEMBLK_FROMBLK(b); return (memblk->sequence); } int Memento_check(void) { int result; fprintf(stderr, "Checking memory\n"); result = Memento_checkAllMemory(); fprintf(stderr, "Memory checked!\n"); return result; } typedef struct findBlkData { void *addr; Memento_BlkHeader *blk; int flags; } findBlkData; static int Memento_containsAddr(Memento_BlkHeader *b, void *arg) { findBlkData *data = (findBlkData *) arg; char *blkend = &((char *)MEMBLK_TOBLK(b))[b->rawsize]; if ((MEMBLK_TOBLK(b) <= data->addr) && ((void *)blkend > data->addr)) { data->blk = b; data->flags = 1; return 1; } if (((void *)b <= data->addr) && (MEMBLK_TOBLK(b) > data->addr)) { data->blk = b; data->flags = 2; return 1; } if (((void *)blkend <= data->addr) && ((void *)(blkend + Memento_PostSize) > data->addr)) { data->blk = b; data->flags = 3; return 1; } return 0; } int Memento_find(void *a) { findBlkData data; data.addr = a; data.blk = NULL; data.flags = 0; Memento_appBlocks(&globals.used, Memento_containsAddr, &data); if (data.blk != NULL) { fprintf(stderr, "Address 0x%p is in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, "\n"); return data.blk->sequence; } data.blk = NULL; data.flags = 0; Memento_appBlocks(&globals.free, Memento_containsAddr, &data); if (data.blk != NULL) { fprintf(stderr, "Address 0x%p is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, "\n"); return data.blk->sequence; } return 0; } void Memento_breakOnFree(void *a) { findBlkData data; data.addr = a; data.blk = NULL; data.flags = 0; Memento_appBlocks(&globals.used, Memento_containsAddr, &data); if (data.blk != NULL) { fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, ") is freed\n"); data.blk->flags |= Memento_Flag_BreakOnFree; return; } data.blk = NULL; data.flags = 0; Memento_appBlocks(&globals.free, Memento_containsAddr, &data); if (data.blk != NULL) { fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, "\n"); return; } fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a); } void Memento_breakOnRealloc(void *a) { findBlkData data; data.addr = a; data.blk = NULL; data.flags = 0; Memento_appBlocks(&globals.used, Memento_containsAddr, &data); if (data.blk != NULL) { fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, ") is freed (or realloced)\n"); data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc; return; } data.blk = NULL; data.flags = 0; Memento_appBlocks(&globals.free, Memento_containsAddr, &data); if (data.blk != NULL) { fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ", data.addr, (data.flags == 1 ? "" : (data.flags == 2 ? "preguard of " : "postguard of "))); showBlock(data.blk, ' '); fprintf(stderr, "\n"); return; } fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a); } int Memento_failAt(int i) { globals.failAt = i; if ((globals.sequence > globals.failAt) && (globals.failing != 0)) Memento_startFailing(); return i; } size_t Memento_setMax(size_t max) { globals.maxMemory = max; return max; } #else /* Just in case anyone has left some debugging code in... */ void (Memento_breakpoint)(void) { } int (Memento_checkBlock)(void *b) { return 0; } int (Memento_checkAllMemory)(void) { return 0; } int (Memento_check)(void) { return 0; } int (Memento_setParanoia)(int i) { return 0; } int (Memento_paranoidAt)(int i) { return 0; } int (Memento_breakAt)(int i) { return 0; } int (Memento_getBlockNum)(void *i) { return 0; } int (Memento_find)(void *a) { return 0; } int (Memento_failAt)(int i) { return 0; } void (Memento_breakOnFree)(void *a) { } void (Memento_breakOnRealloc)(void *a) { } #undef Memento_malloc #undef Memento_free #undef Memento_realloc #undef Memento_calloc void * Memento_malloc(size_t size) { return MEMENTO_UNDERLYING_MALLOC(size); } void Memento_free(void *b) { MEMENTO_UNDERLYING_FREE(b); } void * Memento_realloc(void *b, size_t s) { return MEMENTO_UNDERLYING_REALLOC(b, s); } void * Memento_calloc(size_t n, size_t s) { return MEMENTO_UNDERLYING_CALLOC(n, s); } void (Memento_listBlocks)(void) { } void (Memento_listNewBlocks)(void) { } size_t(Memento_setMax)(size_t max) { return 0; } void (Memento_stats)(void) { } void *(Memento_label)(void *ptr, const char *label) { return ptr; } #endif jbig2dec-0.13/memento.h000066400000000000000000000222661270170036400147330ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* Memento: A library to aid debugging of memory leaks/heap corruption. * * Usage: * First, build your project with MEMENTO defined, and include this * header file wherever you use malloc, realloc or free. * This header file will use macros to point malloc, realloc and free to * point to Memento_malloc, Memento_realloc, Memento_free. * * Run your program, and all mallocs/frees/reallocs should be redirected * through here. When the program exits, you will get a list of all the * leaked blocks, together with some helpful statistics. You can get the * same list of allocated blocks at any point during program execution by * calling Memento_listBlocks(); * * Every call to malloc/free/realloc counts as an 'allocation event'. * On each event Memento increments a counter. Every block is tagged with * the current counter on allocation. Every so often during program * execution, the heap is checked for consistency. By default this happens * every 1024 events. This can be changed at runtime by using * Memento_setParanoia(int level). 0 turns off such checking, 1 sets * checking to happen on every event, any other number n sets checking to * happen once every n events. * * Memento keeps blocks around for a while after they have been freed, and * checks them as part of these heap checks to see if they have been * written to (or are freed twice etc). * * A given heap block can be checked for consistency (it's 'pre' and * 'post' guard blocks are checked to see if they have been written to) * by calling Memento_checkBlock(void *blockAddress); * * A check of all the memory can be triggered by calling Memento_check(); * (or Memento_checkAllMemory(); if you'd like it to be quieter). * * A good place to breakpoint is Memento_breakpoint, as this will then * trigger your debugger if an error is detected. This is done * automatically for debug windows builds. * * If a block is found to be corrupt, information will be printed to the * console, including the address of the block, the size of the block, * the type of corruption, the number of the block and the event on which * it last passed a check for correctness. * * If you rerun, and call Memento_paranoidAt(int event); with this number * the the code will wait until it reaches that event and then start * checking the heap after every allocation event. Assuming it is a * deterministic failure, you should then find out where in your program * the error is occurring (between event x-1 and event x). * * Then you can rerun the program again, and call * Memento_breakAt(int event); and the program will call * Memento_Breakpoint() when event x is reached, enabling you to step * through. * * Memento_find(address) will tell you what block (if any) the given * address is in. * * An example: * Suppose we have a gs invocation that crashes with memory corruption. * * Build with -DMEMENTO. * * In your debugger put breakpoints on Memento_inited and * Memento_Breakpoint. * * Run the program. It will stop in Memento_inited. * * Execute Memento_setParanoia(1); (In VS use Ctrl-Alt-Q). (Note #1) * * Continue execution. * * It will detect the memory corruption on the next allocation event * after it happens, and stop in Memento_breakpoint. The console should * show something like: * * Freed blocks: * 0x172e610(size=288,num=1415) index 256 (0x172e710) onwards corrupted * Block last checked OK at allocation 1457. Now 1458. * * * This means that the block became corrupted between allocation 1457 * and 1458 - so if we rerun and stop the program at 1457, we can then * step through, possibly with a data breakpoint at 0x172e710 and see * when it occurs. * * So restart the program from the beginning. When we hit Memento_inited * execute Memento_breakAt(1457); (and maybe Memento_setParanoia(1), or * Memento_setParanoidAt(1457)) * * Continue execution until we hit Memento_breakpoint. * * Now you can step through and watch the memory corruption happen. * * Note #1: Using Memento_setParanoia(1) can cause your program to run * very slowly. You may instead choose to use Memento_setParanoia(100) * (or some other figure). This will only exhaustively check memory on * every 100th allocation event. This trades speed for the size of the * average allocation event range in which detection of memory corruption * occurs. You may (for example) choose to run once checking every 100 * allocations and discover that the corruption happens between events * X and X+100. You can then rerun using Memento_paranoidAt(X), and * it'll only start exhaustively checking when it reaches X. * * More than one memory allocator? * * If you have more than one memory allocator in the system (like for * instance the ghostscript chunk allocator, that builds on top of the * standard malloc and returns chunks itself), then there are some things * to note: * * * If the secondary allocator gets its underlying blocks from calling * malloc, then those will be checked by Memento, but 'subblocks' that * are returned to the secondary allocator will not. There is currently * no way to fix this other than trying to bypass the secondary * allocator. One way I have found to do this with the chunk allocator * is to tweak its idea of a 'large block' so that it puts every * allocation in its own chunk. Clearly this negates the point of having * a secondary allocator, and is therefore not recommended for general * use. * * * Again, if the secondary allocator gets its underlying blocks from * calling malloc (and hence Memento) leak detection should still work * (but whole blocks will be detected rather than subblocks). * * * If on every allocation attempt the secondary allocator calls into * Memento_failThisEvent(), and fails the allocation if it returns true * then more useful features can be used; firstly memory squeezing will * work, and secondly, Memento will have a "finer grained" paranoia * available to it. */ #ifndef MEMENTO_H #include #define MEMENTO_H #ifndef MEMENTO_UNDERLYING_MALLOC #define MEMENTO_UNDERLYING_MALLOC malloc #endif #ifndef MEMENTO_UNDERLYING_FREE #define MEMENTO_UNDERLYING_FREE free #endif #ifndef MEMENTO_UNDERLYING_REALLOC #define MEMENTO_UNDERLYING_REALLOC realloc #endif #ifndef MEMENTO_UNDERLYING_CALLOC #define MEMENTO_UNDERLYING_CALLOC calloc #endif #ifndef MEMENTO_MAXALIGN #define MEMENTO_MAXALIGN (sizeof(int)) #endif #define MEMENTO_PREFILL 0xa6 #define MEMENTO_POSTFILL 0xa7 #define MEMENTO_ALLOCFILL 0xa8 #define MEMENTO_FREEFILL 0xa9 #define MEMENTO_FREELIST_MAX 0x2000000 int Memento_checkBlock(void *); int Memento_checkAllMemory(void); int Memento_check(void); int Memento_setParanoia(int); int Memento_paranoidAt(int); int Memento_breakAt(int); void Memento_breakOnFree(void *a); void Memento_breakOnRealloc(void *a); int Memento_getBlockNum(void *); int Memento_find(void *a); void Memento_breakpoint(void); int Memento_failAt(int); int Memento_failThisEvent(void); void Memento_listBlocks(void); void Memento_listNewBlocks(void); size_t Memento_setMax(size_t); void Memento_stats(void); void *Memento_label(void *, const char *); void *Memento_malloc(size_t s); void *Memento_realloc(void *, size_t s); void Memento_free(void *); void *Memento_calloc(size_t, size_t); #ifdef MEMENTO #ifndef COMPILING_MEMENTO_C #define malloc Memento_malloc #define free Memento_free #define realloc Memento_realloc #define calloc Memento_calloc #endif #else #define Memento_malloc MEMENTO_UNDERLYING_MALLOC #define Memento_free MEMENTO_UNDERLYING_FREE #define Memento_realloc MEMENTO_UNDERLYING_REALLOC #define Memento_calloc MEMENTO_UNDERLYING_CALLOC #define Memento_checkBlock(A) 0 #define Memento_checkAllMemory() 0 #define Memento_check() 0 #define Memento_setParanoia(A) 0 #define Memento_paranoidAt(A) 0 #define Memento_breakAt(A) 0 #define Memento_breakOnFree(A) 0 #define Memento_breakOnRealloc(A) 0 #define Memento_getBlockNum(A) 0 #define Memento_find(A) 0 #define Memento_breakpoint() do {} while (0) #define Memento_failAt(A) 0 #define Memento_failThisEvent() 0 #define Memento_listBlocks() do {} while (0) #define Memento_listNewBlocks() do {} while (0) #define Memento_setMax(A) 0 #define Memento_stats() do {} while (0) #define Memento_label(A,B) (A) #endif /* MEMENTO */ #endif /* MEMENTO_H */ jbig2dec-0.13/msvc.mak000066400000000000000000000066111270170036400145540ustar00rootroot00000000000000# makefile for jbig2dec # under Microsoft Visual C++ # # To compile zlib.dll: # Get zlib >= 1.2.7, unzip and rename to zlib, # cd zlib, then nmake -f win32\Makefile.msc # To compile libpng.lib: # Get libpng >= 1.6.0, unzip then rename to libpng, # cd libpng, nmake -f scripts\makefile.vcwin32 !ifndef LIBPNGDIR LIBPNGDIR=../libpng !endif !ifndef ZLIBDIR ZLIBDIR=../zlib !endif # define iff you're linking to libpng !if exist("$(ZLIBDIR)") && exist("$(LIBPNGDIR)") && exist ("$(LIBPNGDIR)/pnglibconf.h") LIBPNG_CFLAGS=-DHAVE_LIBPNG -I$(LIBPNGDIR) -I$(ZLIBDIR) LIBPNG_LDFLAGS=$(LIBPNGDIR)/libpng.lib $(ZLIBDIR)/zlib.lib /link /NODEFAULTLIB:LIBCMT JBIG2_IMAGE_PNG_OBJ=jbig2_image_png$(OBJ) !else LIBPNG_CFLAGS= LIBPNG_LDFLAGS= JBIG2_IMAGE_PNG_OBJ= !endif EXE=.exe OBJ=.obj NUL= CFLAGS=-nologo -W4 -Zi -DHAVE_STRING_H=1 -D_CRT_SECURE_NO_WARNINGS $(LIBPNG_CFLAGS) CC=cl FE=-Fe # no libpng # OBJS=getopt$(OBJ) getopt1$(OBJ) jbig2$(OBJ) jbig2_arith$(OBJ) \ jbig2_arith_iaid$(OBJ) jbig2_arith_int$(OBJ) jbig2_huffman$(OBJ) \ jbig2_generic$(OBJ) jbig2_refinement$(OBJ) jbig2_halftone$(OBJ)\ jbig2_image$(OBJ) jbig2_image_pbm$(OBJ) $(JBIG2_IMAGE_PNG_OBJ) \ jbig2_segment$(OBJ) jbig2_symbol_dict$(OBJ) jbig2_text$(OBJ) \ jbig2_mmr$(OBJ) jbig2_page$(OBJ) jbig2_metadata$(OBJ) \ jbig2dec$(OBJ) sha1$(OBJ) HDRS=getopt.h jbig2.h jbig2_arith.h jbig2_arith_iaid.h jbig2_arith_int.h \ jbig2_generic.h jbig2_huffman.h jbig2_hufftab.h jbig2_image.h \ jbig2_mmr.h jbig2_priv.h jbig2_symbol_dict.h jbig2_metadata.h \ config_win32.h sha1.h all: jbig2dec$(EXE) jbig2dec$(EXE): $(OBJS) $(CC) $(CFLAGS) $(FE)jbig2dec$(EXE) $(OBJS) $(LIBPNG_LDFLAGS) getopt$(OBJ): getopt.c getopt.h $(CC) $(CFLAGS) -c getopt.c getopt1$(OBJ): getopt1.c getopt.h $(CC) $(CFLAGS) -c getopt1.c jbig2$(OBJ): jbig2.c $(HDRS) $(CC) $(CFLAGS) -c jbig2.c jbig2_arith$(OBJ): jbig2_arith.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_arith.c jbig2_arith_iaid$(OBJ): jbig2_arith_iaid.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_arith_iaid.c jbig2_arith_int$(OBJ): jbig2_arith_int.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_arith_int.c jbig2_generic$(OBJ): jbig2_generic.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_generic.c jbig2_refinement$(OBJ): jbig2_refinement.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_refinement.c jbig2_huffman$(OBJ): jbig2_huffman.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_huffman.c jbig2_image$(OBJ): jbig2_image.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_image.c jbig2_image_pbm$(OBJ): jbig2_image_pbm.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_image_pbm.c jbig2_image_png$(OBJ): jbig2_image_png.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_image_png.c jbig2_halftone$(OBJ): jbig2_halftone.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_halftone.c jbig2_mmr$(OBJ): jbig2_mmr.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_mmr.c jbig2_page$(OBJ): jbig2_page.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_page.c jbig2_segment$(OBJ): jbig2_segment.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_segment.c jbig2_symbol_dict$(OBJ): jbig2_symbol_dict.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_symbol_dict.c jbig2_text$(OBJ): jbig2_text.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_text.c jbig2_metadata$(OBJ): jbig2_metadata.c $(HDRS) $(CC) $(CFLAGS) -c jbig2_metadata.c jbig2dec$(OBJ): jbig2dec.c $(HDRS) $(CC) $(CFLAGS) -c jbig2dec.c sha1$(OBJ): sha1.c $(HDRS) $(CC) $(CFLAGS) -c sha1.c clean: -del $(OBJS) -del jbig2dec$(EXE) -del jbig2dec.ilk -del jbig2dec.pdb -del pbm2png$(EXE) -del pbm2png.ilk -del pbm2png.pdb -del vc70.pdb -del vc60.pdb -del vc50.pdb jbig2dec-0.13/os_types.h000066400000000000000000000041211270170036400151220ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ /* indirection layer for build and platform-specific definitions in general, this header should ensure that the stdint types are available, and that any optional compile flags are defined if the build system doesn't pass them directly. */ #ifndef _JBIG2_OS_TYPES_H #define _JBIG2_OS_TYPES_H #if defined(__CYGWIN__) && !defined(HAVE_STDINT_H) # include # if defined(OLD_CYGWIN_SYS_TYPES) /* * Old versions of Cygwin have no stdint.h but define "MS types". Some of * them conflict with a standard type emulation provided by config_types.h * so we do a fixup here. */ typedef u_int8_t uint8_t; typedef u_int16_t uint16_t; typedef u_int32_t uint32_t; #endif #elif defined(HAVE_CONFIG_H) # include "config_types.h" #elif defined(_WIN32) || defined(__WIN32__) # include "config_win32.h" #elif defined (STD_INT_USE_SYS_TYPES_H) # include #elif defined (STD_INT_USE_INTTYPES_H) # include #elif defined (STD_INT_USE_SYS_INTTYPES_H) # include #elif defined (STD_INT_USE_SYS_INT_TYPES_H) # include #elif !defined(HAVE_STDINT_H) typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; #endif #if defined(HAVE_STDINT_H) || defined(__MACOS__) # include #elif defined(__VMS) || defined(__osf__) # include #endif #ifdef __hpux #include #endif #endif /* _JBIG2_OS_TYPES_H */ jbig2dec-0.13/pbm2png.c000066400000000000000000000031561270170036400146240ustar00rootroot00000000000000/* Copyright (C) 2001-2012 Artifex Software, Inc. All Rights Reserved. This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of the license contained in the file LICENSE in this distribution. Refer to licensing information at http://www.artifex.com or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. */ /* jbig2dec */ #ifdef HAVE_CONFIG_H #include "config.h" #include "config_types.h" #elif _WIN32 #include "config_win32.h" #endif #ifdef HAVE_STDINT_H #include #endif #include #include #include #include "jbig2.h" #include "jbig2_image.h" int main(int argc, char *argv[]) { Jbig2Ctx *ctx; Jbig2Image *image; int error; /* we need a context for the allocators */ ctx = jbig2_ctx_new(NULL, 0, NULL, NULL, NULL); if (argc != 3) { fprintf(stderr, "usage: %s \n\n", argv[0]); return 1; } image = jbig2_image_read_pbm_file(ctx, argv[1]); if (image == NULL) { fprintf(stderr, "error reading pbm file '%s'\n", argv[1]); return 1; } else { fprintf(stderr, "converting %dx%d image to png format\n", image->width, image->height); } error = jbig2_image_write_png_file(image, argv[2]); if (error) { fprintf(stderr, "error writing png file '%s' error %d\n", argv[2], error); } return (error); } jbig2dec-0.13/sha1.c000066400000000000000000000271131270170036400141120ustar00rootroot00000000000000/* SHA-1 in C By Steve Reid 100% Public Domain ----------------- Modified 7/98 By James H. Brown Still 100% Public Domain Corrected a problem which generated improper hash values on 16 bit machines Routine SHA1Update changed from void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) to void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned long len) The 'len' parameter was declared an int which works fine on 32 bit machines. However, on 16 bit machines an int is too small for the shifts being done against it. This caused the hash function to generate incorrect values if len was greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). Since the file IO in main() reads 16K at a time, any file 8K or larger would be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million "a"s). I also changed the declaration of variables i & j in SHA1Update to unsigned long from unsigned int for the same reason. These changes should make no difference to any 32 bit implementations since an int and a long are the same size in those environments. -- I also corrected a few compiler warnings generated by Borland C. 1. Added #include for exit() prototype 2. Removed unused variable 'j' in SHA1Final 3. Changed exit(0) to return(0) at end of main. ALL changes I made can be located by searching for comments containing 'JHB' ----------------- Modified 8/98 By Steve Reid Still 100% public domain 1- Removed #include and used return() instead of exit() 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) 3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net ----------------- Modified 4/01 By Saul Kravitz Still 100% PD Modified to run on Compaq Alpha hardware. ----------------- Modified 07/2002 By Ralph Giles Still 100% public domain modified for use with stdint types, autoconf code cleanup, removed attribution comments switched SHA1Final() argument order for consistency use SHA1_ prefix for public api move public api to sha1.h */ /* Test Vectors (from FIPS PUB 180-1) "abc" A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 A million repetitions of "a" 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F */ /* #define SHA1HANDSOFF */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "os_types.h" #include "sha1.h" void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ /* I got the idea of expanding during the round function from SSLeay */ /* FIXME: can we do this in an endian-proof way? */ #ifdef WORDS_BIGENDIAN #define blk0(i) block->l[i] #else #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ |(rol(block->l[i],8)&0x00FF00FF)) #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); #ifdef VERBOSE /* SAK */ void SHAPrintContext(SHA1_CTX *context, char *msg) { printf("%s (%d,%d) %x %x %x %x %x\n", msg, context->count[0], context->count[1], context->state[0], context->state[1], context->state[2], context->state[3], context->state[4]); } #endif /* VERBOSE */ /* Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) { uint32_t a, b, c, d, e; typedef union { uint8_t c[64]; uint32_t l[16]; } CHAR64LONG16; CHAR64LONG16 *block; #ifdef SHA1HANDSOFF static uint8_t workspace[64]; block = (CHAR64LONG16 *) workspace; memcpy(block, buffer, 64); #else block = (CHAR64LONG16 *) buffer; #endif /* Copy context->state[] to working vars */ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; /* 4 rounds of 20 operations each. Loop unrolled. */ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); /* Add the working vars back into context.state[] */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; /* Wipe variables */ a = b = c = d = e = 0; } /* SHA1Init - Initialize new context */ void SHA1_Init(SHA1_CTX *context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; context->state[4] = 0xC3D2E1F0; context->count[0] = context->count[1] = 0; } /* Run your data through this. */ void SHA1_Update(SHA1_CTX *context, const uint8_t *data, const size_t len) { size_t i, j; #ifdef VERBOSE SHAPrintContext(context, "before"); #endif j = (context->count[0] >> 3) & 63; if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64 - j)); SHA1_Transform(context->state, context->buffer); for (; i + 63 < len; i += 64) { SHA1_Transform(context->state, data + i); } j = 0; } else i = 0; memcpy(&context->buffer[j], &data[i], len - i); #ifdef VERBOSE SHAPrintContext(context, "after "); #endif } /* Add padding and return the message digest. */ void SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE]) { uint32_t i; uint8_t finalcount[8]; for (i = 0; i < 8; i++) { finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ } SHA1_Update(context, (uint8_t *) "\200", 1); while ((context->count[0] & 504) != 448) { SHA1_Update(context, (uint8_t *) "\0", 1); } SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ for (i = 0; i < SHA1_DIGEST_SIZE; i++) { digest[i] = (uint8_t) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } /* Wipe variables */ i = 0; memset(context->buffer, 0, 64); memset(context->state, 0, 20); memset(context->count, 0, 8); memset(finalcount, 0, 8); /* SWR */ #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ SHA1_Transform(context->state, context->buffer); #endif } /*************************************************************/ #if 0 int main(int argc, char **argv) { int i, j; SHA1_CTX context; unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384]; FILE *file; if (argc > 2) { puts("Public domain SHA-1 implementation - by Steve Reid "); puts("Modified for 16 bit environments 7/98 - by James H. Brown "); /* JHB */ puts("Produces the SHA-1 hash of a file, or stdin if no file is specified."); return (0); } if (argc < 2) { file = stdin; } else { if (!(file = fopen(argv[1], "rb"))) { fputs("Unable to open file.", stderr); return (-1); } } SHA1_Init(&context); while (!feof(file)) { /* note: what if ferror(file) */ i = fread(buffer, 1, 16384, file); SHA1_Update(&context, buffer, i); } SHA1_Final(&context, digest); fclose(file); for (i = 0; i < SHA1_DIGEST_SIZE / 4; i++) { for (j = 0; j < 4; j++) { printf("%02X", digest[i * 4 + j]); } putchar(' '); } putchar('\n'); return (0); /* JHB */ } #endif /* self test */ #ifdef TEST static char *test_data[] = { "abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "A million repetitions of 'a'" }; static char *test_results[] = { "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F" }; void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output) { int i, j; char *c = output; for (i = 0; i < SHA1_DIGEST_SIZE / 4; i++) { for (j = 0; j < 4; j++) { sprintf(c, "%02X", digest[i * 4 + j]); c += 2; } sprintf(c, " "); c += 1; } *(c - 1) = '\0'; } int main(int argc, char **argv) { int k; SHA1_CTX context; uint8_t digest[20]; char output[80]; fprintf(stdout, "verifying SHA-1 implementation... "); for (k = 0; k < 2; k++) { SHA1_Init(&context); SHA1_Update(&context, (uint8_t *) test_data[k], strlen(test_data[k])); SHA1_Final(&context, digest); digest_to_hex(digest, output); if (strcmp(output, test_results[k])) { fprintf(stdout, "FAIL\n"); fprintf(stderr, "* hash of \"%s\" incorrect:\n", test_data[k]); fprintf(stderr, "\t%s returned\n", output); fprintf(stderr, "\t%s is correct\n", test_results[k]); return (1); } } /* million 'a' vector we feed separately */ SHA1_Init(&context); for (k = 0; k < 1000000; k++) SHA1_Update(&context, (uint8_t *) "a", 1); SHA1_Final(&context, digest); digest_to_hex(digest, output); if (strcmp(output, test_results[2])) { fprintf(stdout, "FAIL\n"); fprintf(stderr, "* hash of \"%s\" incorrect:\n", test_data[2]); fprintf(stderr, "\t%s returned\n", output); fprintf(stderr, "\t%s is correct\n", test_results[2]); return (1); } /* success */ fprintf(stdout, "ok\n"); return (0); } #endif /* TEST */ jbig2dec-0.13/sha1.h000066400000000000000000000010741270170036400141150ustar00rootroot00000000000000/* public api for steve reid's public domain SHA-1 implementation */ /* this file is in the public domain */ #ifndef __SHA1_H #define __SHA1_H #ifdef __cplusplus extern "C" { #endif typedef struct { uint32_t state[5]; uint32_t count[2]; uint8_t buffer[64]; } SHA1_CTX; #define SHA1_DIGEST_SIZE 20 void SHA1_Init(SHA1_CTX *context); void SHA1_Update(SHA1_CTX *context, const uint8_t *data, const size_t len); void SHA1_Final(SHA1_CTX *context, uint8_t digest[SHA1_DIGEST_SIZE]); #ifdef __cplusplus } #endif #endif /* __SHA1_H */ jbig2dec-0.13/snprintf.c000066400000000000000000000074271270170036400151270ustar00rootroot00000000000000/* * Revision 12: http://theos.com/~deraadt/snprintf.c * * Copyright (c) 1997 Theo de Raadt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef __VMS #include #else #include #endif #include #include #include #include #if __STDC__ #include #include #else #include #endif #include #include #include #ifndef roundup #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif #ifdef __sgi #define size_t ssize_t #endif static int pgsize; static char *curobj; static int caught; static sigjmp_buf bail; #define EXTRABYTES 2 /* XXX: why 2? you don't want to know */ static char * msetup(str, n) char *str; size_t n; { char *e; if (n == 0) return NULL; if (pgsize == 0) pgsize = getpagesize(); curobj = (char *)malloc(n + EXTRABYTES + pgsize * 2); if (curobj == NULL) return NULL; e = curobj + n + EXTRABYTES; e = (char *)roundup((unsigned long)e, pgsize); if (mprotect(e, pgsize, PROT_NONE) == -1) { free(curobj); curobj = NULL; return NULL; } e = e - n - EXTRABYTES; *e = '\0'; return (e); } static void mcatch(int a) { siglongjmp(bail, 1); } static void mcleanup(str, n, p) char *str; size_t n; char *p; { strncpy(str, p, n - 1); str[n - 1] = '\0'; if (mprotect((caddr_t)(p + n + EXTRABYTES), pgsize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) mprotect((caddr_t)(p + n + EXTRABYTES), pgsize, PROT_READ | PROT_WRITE); free(curobj); } int #if __STDC__ vsnprintf(char *str, size_t n, char const *fmt, va_list ap) #else vsnprintf(str, n, fmt, ap) char *str; size_t n; char *fmt; char *ap; #endif { struct sigaction osa, nsa; char *p; int ret = n + 1; /* if we bail, indicated we overflowed */ memset(&nsa, 0, sizeof nsa); nsa.sa_handler = mcatch; sigemptyset(&nsa.sa_mask); p = msetup(str, n); if (p == NULL) { *str = '\0'; return 0; } if (sigsetjmp(bail, 1) == 0) { if (sigaction(SIGSEGV, &nsa, &osa) == -1) { mcleanup(str, n, p); return (0); } ret = vsprintf(p, fmt, ap); } mcleanup(str, n, p); (void)sigaction(SIGSEGV, &osa, NULL); return (ret); } int #if __STDC__ snprintf(char *str, size_t n, char const *fmt, ...) #else snprintf(str, n, fmt, va_alist) char *str; size_t n; char *fmt; va_dcl #endif { va_list ap; #if __STDC__ va_start(ap, fmt); #else va_start(ap); #endif return (vsnprintf(str, n, fmt, ap)); va_end(ap); } jbig2dec-0.13/test_jbig2dec.py000077500000000000000000000146741270170036400162070ustar00rootroot00000000000000#! /usr/bin/env python # this is the testtest script for jbig2dec import os, re import sys, time class SelfTest: 'generic class for self tests' def __init__(self): self.result = 'unrun' self.msg = '' def shortDescription(self): 'returns a short name for the test' return "generic self test" def runTest(self): 'call this to execute the test' pass def fail(self, msg=None): self.result = 'FAIL' self.msg = msg def failIf(self, check, msg=None): if check: self.fail(msg) def assertEqual(self, a, b, msg=None): if a != b: self.fail(msg) class SelfTestSuite: 'generic class for running a collection of SelfTest instances' def __init__(self, stream=sys.stderr): self.stream = stream self.tests = [] self.fails = [] self.xfails = [] self.errors = [] def addTest(self, test): self.tests.append(test) def run(self): starttime = time.time() for test in self.tests: self.stream.write("%s ... " % test.shortDescription()) test.result = 'ok' test.runTest() if test.result != 'ok': self.fails.append(test) self.stream.write("%s\n" % test.result) stoptime = time.time() self.stream.write('-'*72 + '\n') self.stream.write('ran %d tests in %.3f seconds\n\n' % (len(self.tests), stoptime - starttime)) if len(self.fails): self.stream.write('FAILED %d of %d tests\n' % (len(self.fails),len(self.tests))) else: self.stream.write('PASSED all %d tests\n' % len(self.tests)) class KnownFileHash(SelfTest): 'self test to check for correct decode of known test files' # hashes of known test inputs known_042_DECODED = "ebfdf6e2fc5ff3ee2271c2fa19de0e52712046e8" # we do not have correct hashes for these known_amb_DECODED = "ff32ffff0776ff66ff254129ff28ffffffff6bff" # these are known test files in the form # (filename, sha-1(file), sha-1(decoded document) known_hashes = ( ('../ubc/042_1.jb2', "673e1ee5c55ab241b171e476ba1168a42733ddaa", known_042_DECODED), ('../ubc/042_2.jb2', "9aa2804e2d220952035c16fb3c907547884067c5", known_042_DECODED), ('../ubc/042_3.jb2', "9663a5f35727f13e61a0a2f0a64207b1f79e7d67", known_042_DECODED), ('../ubc/042_4.jb2', "014df658c8b99b600c2ceac3f1d53c7cc2b4917c", known_042_DECODED), ('../ubc/042_5.jb2', "264720a6ccbbf72aa6a2cfb6343f43b8e6f2da4b", known_042_DECODED), ('../ubc/042_6.jb2', "96f7dc9df4a1b305f9ac082dd136f85ef5b108fe", known_042_DECODED), ('../ubc/042_7.jb2', "5526371ba9dc2b8743f20ae3e05a7e60b3dcba76", known_042_DECODED), ('../ubc/042_8.jb2', "4bf0c87dfaf40d67c36f2a083579eeda26d54641", known_042_DECODED), ('../ubc/042_9.jb2', "53e630e7fe2fe6e1d6164758e15fc93382e07f55", known_042_DECODED), ('../ubc/042_10.jb2', "5ca1364367e25cb8f642e9dc677a94d5cfed0c8b", known_042_DECODED), ('../ubc/042_11.jb2', "bc194caf022bc5345fc41259e05cea3c08245216", known_042_DECODED), ('../ubc/042_12.jb2', "f354df8eb4849bc707f088739e322d1fe3a14ef3", known_042_DECODED), ('../ubc/042_13.jb2', "7d428bd542f58591b254d9827f554b0552c950a7", known_042_DECODED), ('../ubc/042_14.jb2', "c40fe3a02acb6359baf9b40fc9c49bc0800be589", known_042_DECODED), ('../ubc/042_15.jb2', "a9e39fc1ecb178aec9f05039514d75ea3246246c", known_042_DECODED), ('../ubc/042_16.jb2', "4008bbca43670f3c90eaee26516293ba95baaf3d", known_042_DECODED), ('../ubc/042_17.jb2', "0ff95637b64c57d659a41c582da03e25321551fb", known_042_DECODED), ('../ubc/042_18.jb2', "87381d044f00c4329200e44decbe91bebfa31595", known_042_DECODED), ('../ubc/042_19.jb2', "387d95a140b456d4742622c788cf5b51cebbf438", known_042_DECODED), ('../ubc/042_20.jb2', "85c19e9ec42b8ddd6b860a1bebea1c67610e7a59", known_042_DECODED), ('../ubc/042_21.jb2', "ab535c7d7a61a7b9dc53d546e7419ca78ac7f447", known_042_DECODED), ('../ubc/042_22.jb2', "a9e2b365be63716dbde74b0661c3c6efd2a6844d", known_042_DECODED), ('../ubc/042_23.jb2', "8ffa40a05e93e10982b38a2233a8da58c1b5c343", known_042_DECODED), ('../ubc/042_24.jb2', "2553fe65111c58f6412de51d8cdc71651e778ccf", known_042_DECODED), ('../ubc/042_25.jb2', "52de4a3b86252d896a8d783ba71dd0699333dd69", known_042_DECODED), ('../ubc/amb_1.jb2', "d6d6d1c981dc37a09108c1e3ed990aa5b345fa6a", known_amb_DECODED), ('../ubc/amb_2.jb2', "9af6616a89eb03f8934de72626e301a716366c3c", known_amb_DECODED), ('../str-p39', "1a303e33d3ea57eb7e19a676a1b2f28baa29b045", "ff373f070f5f405b732c53ffffff087eff22ff5b") ) def __init__(self, file, file_hash, decode_hash): SelfTest.__init__(self) self.file = file self.file_hash = file_hash self.decode_hash = decode_hash def shortDescription(self): return "Checking '%s' for correct decoded document hash" % self.file def runTest(self): '''jbig2dec should return proper document hashes for known files''' # invoke jbig2dec on our file instance = os.popen('./jbig2dec -q -o /dev/null --hash ' + self.file) lines = instance.readlines() exit_code = instance.close() self.failIf(exit_code, 'jbig2dec should exit normally') # test here for correct hash hash_pattern = re.compile('[0-9a-f]{%d}' % len(decode_hash)) for line in lines: m = hash_pattern.search(line.lower()) if m: self.assertEqual(self.decode_hash, m.group(), 'hash of known decoded document must be correct') return self.fail('document hash was not found in the output') suite = SelfTestSuite() for filename, file_hash, decode_hash in KnownFileHash.known_hashes: # only add tests for files we can find if not os.access(filename, os.R_OK): continue # todo: verify our file matches its encoded document hash suite.addTest(KnownFileHash(filename, file_hash, decode_hash)) # run the defined tests if we're called as a script if __name__ == "__main__": result = suite.run() sys.exit(not result)