diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..4362b49 --- /dev/null +++ b/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 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. + + This 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 this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..a488611 --- /dev/null +++ b/NEWS @@ -0,0 +1,119 @@ +v1.1 +~~~~ + +Bugfixes: + - Add git version in --version (Marc-André Lureau) + - Fix list of new symbols in index page (Marc-André Lureau) + - Fix unused declarations (Marc-André Lureau) + - Match the former autotools build (Jan Alexander Steffens) + - Specify gcab compoment in PACKAGE_BUGREPORT (Marc-André Lureau) + +v1.0 +==== + +Notes: + - This fixes the security bug known as CVE-2018-5345 + +Translations: + - Add Friulian translation (Fabio Tomat) + - Updated Brazilian Portuguese translation (Rafael Fontenelle) + - Updated Danish translation (Ask Hjorth Larsen, Joe Hansen) + - Updated German translation (Mario Blättermann) + - Updated Polish translation (Piotr Drąg) + - Updated Russian translation (Stas Solovey) + - Updated Slovenian translation (Matej Urbančič) + - Updated Spanish translation (Daniel Mustieles) + - Updated Swedish translation (Anders Jonsson) + +New Features: + - Add a helper executable to create massive compressed archives (Richard Hughes) + - Add a special binary to use just for fuzzing (Richard Hughes) + - Add gcab_cabinet_get_size() (Richard Hughes) + - Add gcab_file_new_with_bytes() (Richard Hughes) + - Add gcab_file_set_attributes() (Richard Hughes) + - Add gcab_file_set_date() (Richard Hughes) + - Add gcab_folder_get_comptype() (Richard Hughes) + - Add gcab_folder_get_file_by_name() (Richard Hughes) + - Add some self tests to test libgcab (Richard Hughes) + - Switch to the Meson buildsystem (Richard Hughes) + +Bugfixes: + - Always check the return value when writing to the stream (Richard Hughes) + - Do not crash when ncbytes is larger than the buffer size (Richard Hughes) + - Do not encode timezone in generated files (Chris Lamb) + - Do not return translated errors from libraries (Richard Hughes) + - Explicitly enable C99 support (Philip Withnall) + - Fix a few 'Dereference of null pointer' warnings (Richard Hughes) + - Fix a large memory leak when parsing LZX cab files (Richard Hughes) + - Fix a theoretical crash when building the table entries (Richard Hughes) + - Fix buffer overrun when generating Huffman codes (Richard Hughes) + - Fix dependency on generated .h file (Philip Chimento) + - Fix invalid return annotation (Marc-André Lureau) + - Fix the calculation of the checksum on big endian machines (Richard Hughes) + - Fix -Wimplicit-fallthrough= (Marc-André Lureau) + - Replace all the custom typedefd unsigned types with working versions (Richard Hughes) + - Return detailed errors from gcab_cabinet_get_signature() (Richard Hughes) + - Use g_autoptr() to fix countless memory leaks when parsing corrupt files (Richard Hughes) + - Use g_autoptr() to fix several memory leaks on error in the library (Richard Hughes) + - Use G_DECLARE_FINAL_TYPE to remove lots of C boilerplate (Richard Hughes) + - Use glib-mkenum's prefixes to avoid sed (Emmanuele Bassi) + +v0.7 +==== + +- learn to rewind if needed during extraction #763377 +- fix extraction of files without cdata #763376 +- do not abort with a critical warning if a file has an incorrect + checksum +- set utf8 flag automatically #754091 +- fix wrong modification date #753040 +- build warning fixes +- translation updates + +v0.6 +==== + +- fix for the AFL-detected crashes +- add file information getters (get_attributes(), get_date(), get_size()) +- gcab learned --list-details to list files with those informations +- fix the file date when creating cab +- build-sys fixes + +v0.5 +==== + +- fix path traversal: do not escape from output directory +- add gcab_cabinet_get_signature() +- translations updates +- build warning fixes + +v0.4 +==== + +- add missing call to g_type_init() for older GLib +- translations updates +- build warning fixes + +v0.3 +==== + +- add LZX decompression, thanks to Wine project! +- gcab learned the ubiquitous --version +- overwrite files on extract + +v0.2 +==== + +- add support for extraction of MSZIP cabinets +- add 100% gtk-doc API documentation +- make check doesn't require cabextract anymore +- fix a few memleaks and misc bugs + +v0.1 +==== + +This is the first release of gcab, a tool and library mainly made to +create Cabinet files, using GObject/GIO API, providing GIR bindings. +- creation supports plain and basic MSZIP compression +- can open and list files from cabinet, no extraction +- provided API/ABI stable diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e1764c --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +GCab +==== + +A GObject library to create cabinet files + +Fuzzing +------- + + CC=afl-gcc meson --default-library=static ../ + AFL_HARDEN=1 ninja + afl-fuzz -m 300 -i ../tests/fuzzing/ -o findings ./src/gcab-fuzz @@ diff --git a/RELEASE b/RELEASE new file mode 100644 index 0000000..64ff42a --- /dev/null +++ b/RELEASE @@ -0,0 +1,43 @@ +GCab Release Notes + +1. Write NEWS entries for GCab in the same format as usual. + +git shortlog v1.0.. | grep -i -v trivial | grep -v Merge > NEWS.new + +-------------------------------------------------------------------------------- +v1.1 +~~~~ + +Notes: + +New Features: + +Bugfixes: +-------------------------------------------------------------------------------- + +4. Commit changes: + +# MAKE SURE THESE ARE CORRECT +export release_version="1.1" +export release_tag="v1.1" + +git commit -a -m "Release ${release_version}" +git tag -s -f -m "Release ${release_version}" "${release_tag}" + +git push --tags +git push + +5. run 'ninja dist' + +6. Upload tarball: + +scp meson-dist/*.tar.xz rhughes@master.gnome.org: +ssh rhughes@master.gnome.org +ftpadmin install gcab-*.tar.xz + +7. Do post release version bump in meson.build + +8. Commit trivial changes: + +git commit -a -m "trivial: post release version bump" +git push diff --git a/contrib/gcab.spec.in b/contrib/gcab.spec.in new file mode 100644 index 0000000..bc943fe --- /dev/null +++ b/contrib/gcab.spec.in @@ -0,0 +1,81 @@ +Name: gcab +Version: #VERSION# +Release: 0.#BUILD#%{?alphatag}%{?dist} +Summary: Cabinet file library and tool + +License: LGPLv2+ +#VCS: git:git://git.gnome.org/gcab +URL: http://ftp.gnome.org/pub/GNOME/sources/gcab +Source0: http://ftp.gnome.org/pub/GNOME/sources/gcab/%{version}/%{name}-%{version}.tar.xz + +BuildRequires: gettext +BuildRequires: gtk-doc +BuildRequires: vala-tools +BuildRequires: glib2-devel +BuildRequires: gobject-introspection-devel +BuildRequires: zlib-devel +BuildRequires: meson + +Requires: libgcab1%{?_isa} = %{version}-%{release} + +%description +gcab is a tool to manipulate Cabinet archive. + +%package -n libgcab1 +Summary: Library to create Cabinet archives + +%description -n libgcab1 +libgcab is a library to manipulate Cabinet archive using GIO/GObject. + +%package -n libgcab1-devel +Summary: Development files to create Cabinet archives +Requires: libgcab1%{?_isa} = %{version}-%{release} +Requires: glib2-devel +Requires: pkgconfig + +%description -n libgcab1-devel +libgcab is a library to manipulate Cabinet archive. + +Libraries, includes, etc. to compile with the gcab library. + +%prep +%setup -q + +%build +%meson +%meson_build + +%check +%meson_test + +%install +%meson_install + +%find_lang %{name} + +%post -n libgcab1 -p /sbin/ldconfig +%postun -n libgcab1 -p /sbin/ldconfig + +%files +%doc COPYING NEWS +%{_bindir}/gcab +%{_mandir}/man1/gcab.1* + +%files -n libgcab1 -f %{name}.lang +%doc COPYING NEWS +%{_libdir}/girepository-1.0/GCab-1.0.typelib +%{_libdir}/libgcab-1.0.so.* + +%files -n libgcab1-devel +%{_datadir}/gir-1.0/GCab-1.0.gir +%{_datadir}/gtk-doc/html/gcab/* +%{_datadir}/vala/vapi/libgcab-1.0.vapi +%{_datadir}/vala/vapi/libgcab-1.0.deps +%{_includedir}/libgcab-1.0/* +%{_libdir}/libgcab-1.0.so +%{_libdir}/pkgconfig/libgcab-1.0.pc + +%changelog +* #LONGDATE# Richard Hughes #VERSION#-0.#BUILD##ALPHATAG# +- Update from GIT + diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 0000000..034926c --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = reference + +-include $(top_srcdir)/git.mk diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 0000000..ead14c4 --- /dev/null +++ b/docs/meson.build @@ -0,0 +1 @@ +subdir('reference') diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am new file mode 100644 index 0000000..9d54a02 --- /dev/null +++ b/docs/reference/Makefile.am @@ -0,0 +1,44 @@ +NULL = +AUTOMAKE_OPTIONS = 1.6 + +DOC_MODULE = gcab +DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.sgml +DOC_SOURCE_DIR = $(top_srcdir)/libgcab + +SCANGOBJ_OPTIONS = +SCAN_OPTIONS = --rebuild-types +MKDB_OPTIONS = --xml-mode --output-format=xml +MKTMPL_OPTIONS = +MKHTML_OPTIONS = +FIXXREF_OPTIONS = + +# Used for dependencies. The docs will be rebuilt if any of these change. +HFILE_GLOB = $(top_srcdir)/libgcab/*.h +CFILE_GLOB = $(top_srcdir)/libgcab/*.c +EXTRA_HFILES = +IGNORE_HFILES = \ + cabinet.h \ + decomp.h \ + gcab-priv.h \ + $(NULL) + +GTKDOC_CFLAGS = +GTKDOC_LIBS = $(top_builddir)/libgcab-1.0.la + +include $(top_srcdir)/gtk-doc.make + +DISTCLEANFILES = $(DOC_MODULE).types + +if ENABLE_GTK_DOC +doccheck: $(GTKDOC_CHECK) + $(AM_V_GEN)ln -s $< $@ + +MOSTLYCLEANFILES = doccheck + +TESTS_ENVIRONMENT = \ + DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \ + SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir) +TESTS = doccheck +endif + +-include $(top_srcdir)/git.mk diff --git a/docs/reference/gcab-docs.sgml b/docs/reference/gcab-docs.sgml new file mode 100644 index 0000000..9464366 --- /dev/null +++ b/docs/reference/gcab-docs.sgml @@ -0,0 +1,41 @@ + + +]> + + + GCab Reference Manual + + + + Cabinet API + + + + + + + Index + + + + Index of deprecated symbols + + + + Index of new symbols in 0.5 + + + + Index of new symbols in 0.6 + + + + Index of new symbols in 1.0 + + + + + diff --git a/docs/reference/gcab-sections.txt b/docs/reference/gcab-sections.txt new file mode 100644 index 0000000..42ec864 --- /dev/null +++ b/docs/reference/gcab-sections.txt @@ -0,0 +1,82 @@ +
+gcab-cabinet +GCabCabinet +gcab_cabinet_new +gcab_cabinet_load +gcab_cabinet_extract +gcab_cabinet_extract_simple +gcab_cabinet_get_folders +gcab_cabinet_add_folder +gcab_cabinet_write +gcab_cabinet_write_simple +gcab_cabinet_get_signature +gcab_cabinet_get_size +GCAB_ERROR +GCabError + +GCAB_CABINET +GCAB_CABINET_CLASS +GCAB_CABINET_GET_CLASS +GCAB_IS_CABINET +GCAB_IS_CABINET_CLASS +GCAB_TYPE_CABINET +gcab_cabinet_get_type + +GCabCabinetClass +gcab_error_quark +
+ +
+gcab-file +GCabFileAttribute +GCabFileCallback +GCabFile +gcab_file_get_attributes +gcab_file_get_date +gcab_file_set_date +gcab_file_get_extract_name +gcab_file_get_file +gcab_file_get_name +gcab_file_get_size +gcab_file_get_bytes +gcab_file_new_with_file +gcab_file_new_with_bytes +gcab_file_set_extract_name +gcab_file_set_attributes + +GCAB_FILE +GCAB_FILE_CLASS +GCAB_FILE_GET_CLASS +GCAB_IS_FILE +GCAB_IS_FILE_CLASS +GCAB_TYPE_FILE +gcab_file_get_type +GCAB_TYPE_FILE_ATTRIBUTE +gcab_file_attribute_get_type + +GCabFileClass +
+ +
+gcab-folder +GCabCompression +GCabFolder +gcab_folder_new +gcab_folder_add_file +gcab_folder_get_files +gcab_folder_get_nfiles +gcab_folder_get_comptype +gcab_folder_get_file_by_name + +GCAB_FOLDER +GCAB_FOLDER_CLASS +GCAB_FOLDER_GET_CLASS +GCAB_IS_FOLDER +GCAB_IS_FOLDER_CLASS +GCAB_TYPE_FOLDER +gcab_folder_get_type +GCAB_TYPE_COMPRESSION +gcab_compression_get_type + +GCabFolderClass +
diff --git a/docs/reference/meson.build b/docs/reference/meson.build new file mode 100644 index 0000000..879e9eb --- /dev/null +++ b/docs/reference/meson.build @@ -0,0 +1,9 @@ +gnome.gtkdoc( + 'gcab', + src_dir : [ + join_paths(meson.source_root(), 'libgcab'), + join_paths(meson.build_root(), 'libgcab'), + ], + main_sgml : 'gcab-docs.sgml', + install : true +) diff --git a/gcab.doap b/gcab.doap new file mode 100644 index 0000000..831ef4a --- /dev/null +++ b/gcab.doap @@ -0,0 +1,19 @@ + + + Cabinet file library and tool + A GObject library to create cabinet files + + + + + + Marc-André Lureau + + malureau + + + diff --git a/libgcab/cabinet.c b/libgcab/cabinet.c new file mode 100644 index 0000000..53d58bb --- /dev/null +++ b/libgcab/cabinet.c @@ -0,0 +1,682 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include "gcab-priv.h" + +static voidpf +zalloc (voidpf opaque, uInt items, uInt size) +{ + return g_malloc (items *size); +} +static void +zfree (voidpf opaque, voidpf address) +{ + g_free (address); +} + +static gboolean +cdata_set (cdata_t *cd, int type, guint8 *data, size_t size) +{ + if (type > GCAB_COMPRESSION_MSZIP) { + g_critical ("unsupported compression method %d", type); + return FALSE; + } + + cd->nubytes = size; + + if (type == 0) { + memcpy (cd->in, data, size); + cd->ncbytes = size; + } + + if (type == GCAB_COMPRESSION_MSZIP) { + z_stream stream = { 0, }; + + stream.zalloc = zalloc; + stream.zfree = zfree; + if (deflateInit2 (&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) + return FALSE; + stream.next_in = data; + stream.avail_in = size; + stream.next_out = cd->in + 2; + stream.avail_out = sizeof (cd->in) - 2; + /* insert the signature */ + cd->in[0] = 'C'; + cd->in[1] = 'K'; + deflate (&stream, Z_FINISH); + deflateEnd (&stream); + cd->ncbytes = stream.total_out + 2; + } + + return TRUE; +} + +static char * +_data_input_stream_read_until (GDataInputStream *stream, + const gchar *stop_chars, + gsize stop_len, + GCancellable *cancellable, + GError **error) +{ + GBufferedInputStream *bstream; + gchar *result; + + bstream = G_BUFFERED_INPUT_STREAM (stream); + + result = g_data_input_stream_read_upto (stream, stop_chars, stop_len, + NULL, cancellable, error); + + /* If we're not at end of stream then we have a stop_char to consume. */ + if (result != NULL && g_buffered_input_stream_get_available (bstream) > 0) + { + gsize res; + gchar b; + + res = g_input_stream_read (G_INPUT_STREAM (stream), &b, 1, NULL, NULL); + g_assert (res == 1); + } + + return result; +} + +#define R1(val) G_STMT_START{ \ + val = g_data_input_stream_read_byte (in, cancellable, error); \ + if (error && *error) \ + goto end; \ +}G_STMT_END +#define R2(val) G_STMT_START{ \ + val = g_data_input_stream_read_uint16 (in, cancellable, error); \ + if (error && *error) \ + goto end; \ +}G_STMT_END +#define R4(val) G_STMT_START{ \ + val = g_data_input_stream_read_uint32 (in, cancellable, error); \ + if (error && *error) \ + goto end; \ +}G_STMT_END +#define RS(val) G_STMT_START{ \ + val = _data_input_stream_read_until (in, "\0", 1, \ + cancellable, error); \ + if (error && *error) \ + goto end; \ + if (!val) { \ + g_set_error(error, GCAB_ERROR, GCAB_ERROR_FORMAT, \ + "Invalid contents"); \ + goto end; \ + } \ +}G_STMT_END +#define RN(buff, size) G_STMT_START{ \ + if (size) { \ + gint _val = g_input_stream_read (G_INPUT_STREAM (in), buff, size, cancellable, error); \ + if (error && *error) \ + goto end; \ + if (_val >= 0 && _val < size) { \ + g_set_error(error, GCAB_ERROR, GCAB_ERROR_FORMAT, \ + "Expected %d bytes, got %d", size, _val); \ + goto end; \ + } \ + if (_val == -1) { \ + g_set_error(error, GCAB_ERROR, GCAB_ERROR_FORMAT, \ + "Invalid contents"); \ + goto end; \ + } \ + } \ +}G_STMT_END + +static void +hexdump (guchar *p, gsize s) +{ + gsize i; + + for (i = 0; i < s; i++) { + if (i != 0) { + if (i % 16 == 0) + g_printerr ("\n"); + else if (i % 8 == 0) + g_printerr (" "); + else + g_printerr (" "); + } + + if (i % 16 == 0) + g_printerr ("%.8x ", (guint)i); + + g_printerr ("%.2x", (guint)p[i]); + } + + g_printerr ("\n"); +} + +#define P1(p, field) \ + g_debug ("%15s: %.2x", #field, (guint)p->field) +#define P2(p, field) \ + g_debug ("%15s: %.4x", #field, (guint)p->field) +#define P4(p, field) \ + g_debug ("%15s: %.8x", #field, (guint)p->field) +#define PS(p, field) \ + g_debug ("%15s: %s", #field, p->field) +#define PN(p, field, size) \ + g_debug ("%15s:", #field), hexdump (p->field, size) +#define PND(p, field, size) \ + g_debug ("%15s:", #field), hexdump (field, size) + +#define W1(val) \ + g_data_output_stream_put_byte (out, val, cancellable, error) +#define W2(val) \ + g_data_output_stream_put_uint16 (out, val, cancellable, error) +#define W4(val) \ + g_data_output_stream_put_uint32 (out, val, cancellable, error) +#define WS(val) \ + g_data_output_stream_put_string (out, val, cancellable, error) + +G_GNUC_INTERNAL gboolean +cheader_write (cheader_t *ch, GDataOutputStream *out, + GCancellable *cancellable, GError **error) +{ + GOutputStream *stream = g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (out)); + + if (!W1 ('M') || !W1 ('S') || !W1 ('C') || !W1 ('F') || + !W4 (ch->res1) || + !W4 (ch->size) || + !W4 (ch->res2) || + !W4 (ch->offsetfiles) || + !W4 (ch->res3) || + !W1 (ch->versionMIN = 3) || + !W1 (ch->versionMAJ = 1) || + !W2 (ch->nfolders) || + !W2 (ch->nfiles) || + !W2 (ch->flags) || + !W2 (ch->setID) || + !W2 (ch->cabID)) + return FALSE; + + if (ch->flags & CABINET_HEADER_RESERVE) { + if (!W2 (ch->res_header) || + !W1 (ch->res_folder) || + !W1 (ch->res_data)) + return FALSE; + if (g_output_stream_write (stream, ch->reserved, ch->res_header, + cancellable, error) == -1) + return FALSE; + } + + return TRUE; +} + +G_GNUC_INTERNAL gboolean +cheader_read (cheader_t *ch, GDataInputStream *in, + GCancellable *cancellable, GError **error) +{ + gboolean success = FALSE; + guint8 sig[4]; + + R1 (sig[0]); + R1 (sig[1]); + R1 (sig[2]); + R1 (sig[3]); + if (memcmp (sig, "MSCF", 4)) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "The input is not of cabinet format"); + goto end; + } + + memset (ch, 0, sizeof (cheader_t)); + R4 (ch->res1); + R4 (ch->size); + R4 (ch->res2); + R4 (ch->offsetfiles); + R4 (ch->res3); + R1 (ch->versionMIN); + R1 (ch->versionMAJ); + R2 (ch->nfolders); + R2 (ch->nfiles); + R2 (ch->flags); + R2 (ch->setID); + R2 (ch->cabID); + + if (ch->flags & CABINET_HEADER_RESERVE) { + R2 (ch->res_header); + R1 (ch->res_folder); + R1 (ch->res_data); + ch->reserved = g_malloc (ch->res_header); + RN (ch->reserved, ch->res_header); + } + + if (ch->flags & CABINET_HEADER_PREV) { + RS (ch->cab_prev); + RS (ch->disk_prev); + } + + if (ch->flags & CABINET_HEADER_NEXT) { + RS (ch->cab_next); + RS (ch->disk_next); + } + + if (g_getenv ("GCAB_DEBUG")) { + g_debug ("CFHEADER"); + P4 (ch, res1); + P4 (ch, size); + P4 (ch, res2); + P4 (ch, offsetfiles); + P4 (ch, res3); + P1 (ch, versionMIN); + P1 (ch, versionMAJ); + P2 (ch, nfolders); + P2 (ch, nfiles); + P2 (ch, flags); + P2 (ch, setID); + P2 (ch, cabID); + if (ch->flags & CABINET_HEADER_RESERVE) { + P2 (ch, res_header); + P1 (ch, res_folder); + P1 (ch, res_data); + if (ch->res_header) + PN (ch, reserved, ch->res_header); + } + if (ch->flags & CABINET_HEADER_PREV) { + PS (ch, cab_prev); + PS (ch, disk_prev); + } + if (ch->flags & CABINET_HEADER_NEXT) { + PS (ch, cab_next); + PS (ch, disk_next); + } + + } + + success = TRUE; + +end: + return success; +} + +void +cheader_free (cheader_t *ch) +{ + if (ch == NULL) + return; + g_free (ch->reserved); + g_free (ch->cab_prev); + g_free (ch->disk_prev); + g_free (ch->cab_next); + g_free (ch->disk_next); + g_free (ch); +} + +G_GNUC_INTERNAL gboolean +cfolder_write (cfolder_t *cf, GDataOutputStream *out, + GCancellable *cancellable, GError **error) +{ + if ((!W4 (cf->offsetdata)) || + (!W2 (cf->ndatab)) || + (!W2 (cf->typecomp))) + return FALSE; + + return TRUE; +} + +G_GNUC_INTERNAL gboolean +cfolder_read (cfolder_t *cf, guint8 res_size, GDataInputStream *in, + GCancellable *cancellable, GError **error) +{ + gboolean success = FALSE; + + R4 (cf->offsetdata); + R2 (cf->ndatab); + R2 (cf->typecomp); + cf->reserved = g_malloc (res_size); + RN (cf->reserved, res_size); + + if (g_getenv ("GCAB_DEBUG")) { + g_debug ("CFOLDER"); + P4 (cf, offsetdata); + P2 (cf, ndatab); + P2 (cf, typecomp); + if (res_size) + PN (cf, reserved, res_size); + } + + success = TRUE; + +end: + return success; +} + +void +cfolder_free (cfolder_t *cf) +{ + if (cf == NULL) + return; + g_free (cf->reserved); + g_free (cf); +} + +G_GNUC_INTERNAL gboolean +cfile_write (cfile_t *cf, GDataOutputStream *out, + GCancellable *cancellable, GError **error) +{ + if ((!W4 (cf->usize)) || + (!W4 (cf->uoffset)) || + (!W2 (cf->index)) || + (!W2 (cf->date)) || + (!W2 (cf->time)) || + (!W2 (cf->fattr)) || + (!WS (cf->name) || !W1 (0))) + return FALSE; + + return TRUE; +} + + +G_GNUC_INTERNAL gboolean +cfile_read (cfile_t *cf, GDataInputStream *in, + GCancellable *cancellable, GError **error) +{ + gboolean success = FALSE; + + R4 (cf->usize); + R4 (cf->uoffset); + R2 (cf->index); + R2 (cf->date); + R2 (cf->time); + R2 (cf->fattr); + RS (cf->name); + + if (g_getenv ("GCAB_DEBUG")) { + g_debug ("CFILE"); + P4 (cf, usize); + P4 (cf, uoffset); + P2 (cf, index); + P2 (cf, date); + P2 (cf, time); + P2 (cf, fattr); + PS (cf, name); + } + + success = TRUE; + +end: + return success; +} + +void +cfile_free (cfile_t *cf) +{ + if (cf == NULL) + return; + g_free (cf->name); + g_free (cf); +} + +static guint32 +compute_checksum (guint8 *in, guint16 ncbytes, guint32 seed) +{ + int no_ulongs; + guint32 csum=0; + guint32 temp; + + no_ulongs = ncbytes / 4; + csum = seed; + + while (no_ulongs-- > 0) { + temp = ((guint32) (*in++)); + temp |= (((guint32) (*in++)) << 8); + temp |= (((guint32) (*in++)) << 16); + temp |= (((guint32) (*in++)) << 24); + + csum ^= temp; + } + + temp = 0; + switch (ncbytes % 4) { + case 3: temp |= (((guint32) (*in++)) << 16); + /* fall-thru */ + case 2: temp |= (((guint32) (*in++)) << 8); + /* fall-thru */ + case 1: temp |= ((guint32) (*in++)); + /* fall-thru */ + default: break; + } + + csum ^= temp; + + return csum; +} + +G_GNUC_INTERNAL gboolean +cdata_write (cdata_t *cd, GDataOutputStream *out, int type, + guint8 *data, size_t size, gsize *bytes_written, + GCancellable *cancellable, GError **error) +{ + if (!cdata_set(cd, type, data, size)) + return FALSE; + + guint32 datacsum = compute_checksum(cd->in, cd->ncbytes, 0); + guint8 sizecsum[4]; + guint16 nbytes_le; + + nbytes_le = GUINT16_TO_LE (cd->ncbytes); + memcpy (&sizecsum[0], &nbytes_le, 2); + nbytes_le = GUINT16_TO_LE (cd->nubytes); + memcpy (&sizecsum[2], &nbytes_le, 2); + cd->checksum = compute_checksum (sizecsum, sizeof(sizecsum), datacsum); + GOutputStream *stream = g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (out)); + + *bytes_written = 0; + + if ((!W4 (cd->checksum)) || + (!W2 (cd->ncbytes)) || + (!W2 (cd->nubytes)) || + (g_output_stream_write (stream, cd->in, cd->ncbytes, cancellable, error) == -1)) + return FALSE; + + *bytes_written = 4 + 2 + 2 + cd->ncbytes; + + return TRUE; +} + +G_GNUC_INTERNAL void +cdata_free (cdata_t *cd) +{ + z_stream *z = &cd->z; + + if (cd->decomp.comptype == GCAB_COMPRESSION_LZX) { + LZXfdi_clear (&cd->decomp); + } + + if (cd->decomp.comptype == GCAB_COMPRESSION_MSZIP) { + if (z->opaque) { + inflateEnd (z); + z->opaque = NULL; + } + } + g_free (cd->reserved); + g_free (cd); +} + +static gint +_enforce_checksum (void) +{ + static gint enforce = -1; + if (enforce == -1) + enforce = g_getenv ("GCAB_SKIP_CHECKSUM") == NULL ? 1 : 0; + return enforce; +} + +G_GNUC_INTERNAL gboolean +cdata_read (cdata_t *cd, guint8 res_data, gint comptype, + GDataInputStream *in, GCancellable *cancellable, GError **error) + +{ + gboolean success = FALSE; + int ret, zret = Z_OK; + gint compression = comptype & GCAB_COMPRESSION_MASK; + gsize buf_sz; + guint8 *buf = NULL; + guint32 datacsum; + guint32 checksum_tmp; + guint8 sizecsum[4]; + guint16 nbytes_le; + + /* decompress directly into ->out for no decompression */ + switch (compression) { + case GCAB_COMPRESSION_NONE: + buf = cd->out; + buf_sz = sizeof(cd->out); + break; + case GCAB_COMPRESSION_MSZIP: + case GCAB_COMPRESSION_LZX: + buf = cd->in; + buf_sz = sizeof(cd->in); + break; + default: + g_set_error (error, GCAB_ERROR, GCAB_ERROR_NOT_SUPPORTED, + "unsupported compression method %d", compression); + break; + } + if (buf == NULL) + return FALSE; + + R4 (cd->checksum); + R2 (cd->ncbytes); + if (cd->ncbytes > buf_sz) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_INVALID_DATA, + "tried to decompress %" G_GUINT16_FORMAT " bytes " + "into buffer of size %" G_GSIZE_FORMAT, + cd->ncbytes, buf_sz); + return FALSE; + } + R2 (cd->nubytes); + if (cd->nubytes > CAB_BLOCKMAX) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_INVALID_DATA, + "CDATA block of %" G_GUINT16_FORMAT " bytes " + "was bigger than maximum size %i", + cd->nubytes, CAB_BLOCKMAX); + return FALSE; + } + RN (cd->reserved, res_data); + RN (buf, cd->ncbytes); + + datacsum = compute_checksum(buf, cd->ncbytes, 0); + nbytes_le = GUINT16_TO_LE (cd->ncbytes); + memcpy (&sizecsum[0], &nbytes_le, 2); + nbytes_le = GUINT16_TO_LE (cd->nubytes); + memcpy (&sizecsum[2], &nbytes_le, 2); + checksum_tmp = compute_checksum (sizecsum, sizeof(sizecsum), datacsum); + if (cd->checksum != checksum_tmp) { + if (_enforce_checksum ()) { + g_set_error_literal (error, GCAB_ERROR, GCAB_ERROR_INVALID_DATA, + "incorrect checksum detected"); + return FALSE; + } + if (g_getenv ("GCAB_DEBUG")) + g_debug ("CDATA checksum 0x%08x", (guint) checksum_tmp); + } + + if (g_getenv ("GCAB_DEBUG")) { + g_debug ("CDATA"); + P4 (cd, checksum); + P2 (cd, ncbytes); + P2 (cd, nubytes); + if (res_data) + PN (cd, reserved, res_data); + PND (cd, buf, 64); + } + + if (compression == GCAB_COMPRESSION_LZX) { + if (cd->fdi.alloc == NULL) { + cd->fdi.alloc = g_malloc; + cd->fdi.free = g_free; + cd->decomp.fdi = &cd->fdi; + cd->decomp.inbuf = cd->in; + cd->decomp.outbuf = cd->out; + cd->decomp.comptype = compression; + + ret = LZXfdi_init((comptype >> 8) & 0x1f, &cd->decomp); + if (ret < 0) + goto end; + } + + ret = LZXfdi_decomp (cd->ncbytes, cd->nubytes, &cd->decomp); + if (ret < 0) + goto end; + } + + if (compression == GCAB_COMPRESSION_MSZIP) { + if (cd->in[0] != 'C' || cd->in[1] != 'K') + goto end; + + cd->decomp.comptype = compression; + z_stream *z = &cd->z; + + z->avail_in = cd->ncbytes - 2; + z->next_in = cd->in + 2; + z->avail_out = cd->nubytes; + z->next_out = cd->out; + z->total_out = 0; + + if (!z->opaque) { + z->zalloc = zalloc; + z->zfree = zfree; + z->opaque = cd; + + zret = inflateInit2 (z, -MAX_WBITS); + if (zret != Z_OK) + goto end; + } + + while (1) { + zret = inflate (z, Z_BLOCK); + if (zret == Z_STREAM_END) + break; + if (zret != Z_OK) + goto end; + } + + g_warn_if_fail (z->avail_in == 0); + g_warn_if_fail (z->avail_out == 0); + if (z->avail_in != 0 || z->avail_out != 0) + goto end; + + zret = inflateReset (z); + if (zret != Z_OK) + goto end; + + zret = inflateSetDictionary (z, cd->out, cd->nubytes); + if (zret != Z_OK) + goto end; + } + + success = TRUE; + +end: + if (zret != Z_OK) + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED, + "zlib failed: %s", zError (zret)); + + if (error != NULL && *error == NULL && !success) + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED, + "Invalid cabinet chunk"); + + return success; +} diff --git a/libgcab/cabinet.h b/libgcab/cabinet.h new file mode 100644 index 0000000..850ac65 --- /dev/null +++ b/libgcab/cabinet.h @@ -0,0 +1,164 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef CABINET_H +#define CABINET_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gcab-folder.h" +#include "decomp.h" + +/* based on the spec + http://msdn.microsoft.com/en-us/library/bb417343.aspx */ + +#define DATABLOCKSIZE 32768 + +#define CFO_START 0x24 /* folder offset */ +#define CFI_START 0x2C /* file offset */ + +typedef struct +{ + guint32 res1; + guint32 size; + guint32 res2; + guint32 offsetfiles; + guint32 res3; + guint8 versionMIN; + guint8 versionMAJ; + guint16 nfolders; + guint16 nfiles; + guint16 flags; + guint16 setID; + guint16 cabID; + guint16 res_header; + guint8 res_folder; + guint8 res_data; + guint8 *reserved; + gchar *cab_prev; + gchar *disk_prev; + gchar *cab_next; + gchar *disk_next; +} cheader_t; + +typedef enum { + CABINET_HEADER_PREV = 0x0001, + CABINET_HEADER_NEXT = 0x0002, + CABINET_HEADER_RESERVE = 0x0004, +} CabinetHeaderFlags; + +typedef struct +{ + guint32 offsetdata; + guint16 ndatab; + guint16 typecomp; + guint8 *reserved; +} cfolder_t; + +typedef struct +{ + guint32 usize; + guint32 uoffset; + guint16 index; + guint16 date; + guint16 time; + guint16 fattr; + gchar *name; +} cfile_t; + +typedef struct +{ + guint32 checksum; + guint16 ncbytes; + guint16 nubytes; + guint8 *reserved; + guint8 in[CAB_INPUTMAX+2]; + guint8 out[CAB_BLOCKMAX]; + /* using zlib */ + z_stream z; + /* using wine decomp.h */ + FDI_Int fdi; + fdi_decomp_state decomp; +} cdata_t; + +gboolean cheader_write (cheader_t *ch, + GDataOutputStream *out, + GCancellable *cancellable, + GError **error); +gboolean cheader_read (cheader_t *ch, + GDataInputStream *in, + GCancellable *cancellable, + GError **error); +void cheader_free (cheader_t *ch); + +gboolean cfolder_write (cfolder_t *cf, + GDataOutputStream *out, + GCancellable *cancellable, + GError **error); +gboolean cfolder_read (cfolder_t *cf, + guint8 res_folder, + GDataInputStream *in, + GCancellable *cancellable, + GError **error); +void cfolder_free (cfolder_t *cf); + +gboolean cfile_write (cfile_t *cf, + GDataOutputStream *out, + GCancellable *cancellable, + GError **error); +gboolean cfile_read (cfile_t *cf, + GDataInputStream *in, + GCancellable *cancellable, + GError **error); +void cfile_free (cfile_t *cf); + +gboolean cdata_write (cdata_t *cd, + GDataOutputStream *out, + int type, + guint8 *data, + size_t size, + gsize *bytes_written, + GCancellable *cancellable, + GError **error); +gboolean cdata_read (cdata_t *cd, + guint8 res_data, + gint comptype, + GDataInputStream *in, + GCancellable *cancellable, + GError **error); +void cdata_free (cdata_t *cd); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(cfolder_t, cfolder_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(cfile_t, cfile_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(cheader_t, cheader_free) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(cdata_t, cdata_free) + +#endif /* CABINET_H */ diff --git a/libgcab/decomp.c b/libgcab/decomp.c new file mode 100644 index 0000000..64d97f8 --- /dev/null +++ b/libgcab/decomp.c @@ -0,0 +1,1168 @@ +/* + * Adapted from Wine fdi.c: File Decompression Interface + * + * Copyright 2000-2002 Stuart Caie + * Copyright 2002 Patrik Stridvall + * Copyright 2003 Greg Turner + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include +#include "decomp.h" + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/* Tables for deflate from PKZIP's appnote.txt. */ + +#define THOSE_ZIP_CONSTS \ +static const cab_UBYTE Zipborder[] = /* Order of the bit length code lengths */ \ +{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; \ +static const cab_UWORD Zipcplens[] = /* Copy lengths for literal codes 257..285 */ \ +{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, \ + 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; \ +static const cab_UWORD Zipcplext[] = /* Extra bits for literal codes 257..285 */ \ +{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, \ + 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ \ +static const cab_UWORD Zipcpdist[] = /* Copy offsets for distance codes 0..29 */ \ +{ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, \ +513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; \ +static const cab_UWORD Zipcpdext[] = /* Extra bits for distance codes */ \ +{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, \ +10, 11, 11, 12, 12, 13, 13}; \ +/* And'ing with Zipmask[n] masks the lower n bits */ \ +static const cab_UWORD Zipmask[17] = { \ + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, \ + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff \ +} + +THOSE_ZIP_CONSTS; + +#define CAB(x) (decomp_state->x) +#define ZIP(x) (decomp_state->methods.zip.x) +#define LZX(x) (decomp_state->methods.lzx.x) + +#define ZIPNEEDBITS(n) {while(k<(n)){cab_LONG c=*(ZIP(inpos)++);\ + b|=((cab_ULONG)c)<>=(n);k-=(n);} + +/******************************************************** + * Ziphuft_free (internal) + */ +static void fdi_Ziphuft_free(FDI_Int *fdi, struct Ziphuft *t) +{ + register struct Ziphuft *p, *q; + + /* Go through linked list, freeing from the allocated (t[-1]) address. */ + p = t; + while (p != NULL) + { + q = (--p)->v.t; + fdi->free(p); + p = q; + } +} + +/********************************************************* + * fdi_Ziphuft_build (internal) + */ +static cab_LONG fdi_Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, const cab_UWORD *d, const cab_UWORD *e, +struct Ziphuft **t, cab_LONG *m, fdi_decomp_state *decomp_state) +{ + cab_ULONG a; /* counter for codes of length k */ + cab_ULONG el; /* length of EOB code (value 256) */ + cab_ULONG f; /* i repeats in table every f entries */ + cab_LONG g; /* maximum code length */ + cab_LONG h; /* table level */ + register cab_ULONG i; /* counter, current code */ + register cab_ULONG j; /* counter */ + register cab_LONG k; /* number of bits in current code */ + cab_LONG *l; /* stack of bits per table */ + register cab_ULONG *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */ + register struct Ziphuft *q; /* points to current table */ + struct Ziphuft r; /* table entry for structure assignment */ + register cab_LONG w; /* bits before this table == (l * h) */ + cab_ULONG *xp; /* pointer into x */ + cab_LONG y; /* number of dummy codes added */ + cab_ULONG z; /* number of entries in current table */ + + l = ZIP(lx)+1; + + /* Generate counts for each bit length */ + el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */ + + for(i = 0; i < ZIPBMAX+1; ++i) + ZIP(c)[i] = 0; + p = b; i = n; + do + { + ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */ + } while (--i); + if (ZIP(c)[0] == n) /* null input--all zero length codes */ + { + *t = NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; j <= ZIPBMAX; j++) + if (ZIP(c)[j]) + break; + k = j; /* minimum code length */ + if ((cab_ULONG)*m < j) + *m = j; + for (i = ZIPBMAX; i; i--) + if (ZIP(c)[i]) + break; + g = i; /* maximum code length */ + if ((cab_ULONG)*m > i) + *m = i; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= ZIP(c)[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= ZIP(c)[i]) < 0) + return 2; + ZIP(c)[i] += y; + + /* Generate starting offsets LONGo the value table for each length */ + ZIP(x)[1] = j = 0; + p = ZIP(c) + 1; xp = ZIP(x) + 2; + while (--i) + { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do{ + if ((j = *p++) != 0) + ZIP(v)[ZIP(x)[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + ZIP(x)[0] = i = 0; /* first Huffman code is zero */ + p = ZIP(v); /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = l[-1] = 0; /* no bits decoded yet */ + ZIP(u)[0] = NULL; /* just to keep compilers happy */ + q = NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = ZIP(c)[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l[h]) + { + w += l[h++]; /* add bits already decoded */ + + /* compute minimum size table less than or equal to *m bits */ + if ((z = g - w) > (cab_ULONG)*m) /* upper limit */ + z = *m; + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = ZIP(c) + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if (*++xp > ZIPBMAX) + return 2; /* corrupt */ + if ((f <<= 1) <= *xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + if ((cab_ULONG)w + j > el && (cab_ULONG)w < el) + j = el - w; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + l[h] = j; /* set table size in stack */ + + /* allocate and link in new table */ + if (!(q = CAB(fdi)->alloc((z + 1)*sizeof(struct Ziphuft)))) + { + if(h) + fdi_Ziphuft_free(CAB(fdi), ZIP(u)[0]); + return 3; /* not enough memory */ + } + *t = q + 1; /* link to list for Ziphuft_free() */ + *(t = &(q->v.t)) = NULL; + ZIP(u)[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + ZIP(x)[h] = i; /* save pattern for backing up */ + r.b = (cab_UBYTE)l[h-1]; /* bits to dump before this table */ + r.e = (cab_UBYTE)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> (w - l[h-1]); + ZIP(u)[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (cab_UBYTE)(k - w); + if (p >= ZIP(v) + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = *p++; /* simple code is just the value */ + } + else + { + r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* no tables */ + if (h < 0) + return 2; /* corrupt */ + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != ZIP(x)[h]) + w -= l[--h]; /* don't need to update q */ + } + } + + /* return actual size of base table */ + *m = l[0]; + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/********************************************************* + * fdi_Zipinflate_codes (internal) + */ +static cab_LONG fdi_Zipinflate_codes(const struct Ziphuft *tl, const struct Ziphuft *td, + cab_LONG bl, cab_LONG bd, fdi_decomp_state *decomp_state) +{ + register cab_ULONG e; /* table entry flag/number of extra bits */ + cab_ULONG n, d; /* length and index for copy */ + cab_ULONG w; /* current window position */ + const struct Ziphuft *t; /* pointer to table entry */ + cab_ULONG ml, md; /* masks for bl and bd bits */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = ZIP(bb); /* initialize bit buffer */ + k = ZIP(bk); + w = ZIP(window_posn); /* initialize window position */ + + /* inflate the coded data */ + ml = Zipmask[bl]; /* precompute masks for speed */ + md = Zipmask[bd]; + + for(;;) + { + ZIPNEEDBITS((cab_ULONG)bl) + if((e = (t = tl + (b & ml))->e) > 16) + do + { + if (e == 99) + return 1; + ZIPDUMPBITS(t->b) + e -= 16; + ZIPNEEDBITS(e) + } while ((e = (t = t->v.t + (b & Zipmask[e]))->e) > 16); + ZIPDUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + CAB(outbuf)[w++] = (cab_UBYTE)t->v.n; + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if(e == 15) + break; + + /* get length of block to copy */ + ZIPNEEDBITS(e) + n = t->v.n + (b & Zipmask[e]); + ZIPDUMPBITS(e); + + /* decode distance of block to copy */ + ZIPNEEDBITS((cab_ULONG)bd) + if ((e = (t = td + (b & md))->e) > 16) + do { + if (e == 99) + return 1; + ZIPDUMPBITS(t->b) + e -= 16; + ZIPNEEDBITS(e) + } while ((e = (t = t->v.t + (b & Zipmask[e]))->e) > 16); + ZIPDUMPBITS(t->b) + ZIPNEEDBITS(e) + d = w - t->v.n - (b & Zipmask[e]); + ZIPDUMPBITS(e) + do + { + d &= ZIPWSIZE - 1; + e = ZIPWSIZE - max(d, w); + e = min(e, n); + n -= e; + do + { + CAB(outbuf)[w++] = CAB(outbuf)[d++]; + } while (--e); + } while (n); + } + } + + /* restore the globals from the locals */ + ZIP(window_posn) = w; /* restore global window pointer */ + ZIP(bb) = b; /* restore global bit buffer */ + ZIP(bk) = k; + + /* done */ + return 0; +} + +/*********************************************************** + * Zipinflate_stored (internal) + */ +static cab_LONG fdi_Zipinflate_stored(fdi_decomp_state *decomp_state) +/* "decompress" an inflated type 0 (stored) block. */ +{ + cab_ULONG n; /* number of bytes in block */ + cab_ULONG w; /* current window position */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = ZIP(bb); /* initialize bit buffer */ + k = ZIP(bk); + w = ZIP(window_posn); /* initialize window position */ + + /* go to byte boundary */ + n = k & 7; + ZIPDUMPBITS(n); + + /* get the length and its complement */ + ZIPNEEDBITS(16) + n = (b & 0xffff); + ZIPDUMPBITS(16) + ZIPNEEDBITS(16) + if (n != ((~b) & 0xffff)) + return 1; /* error in compressed data */ + ZIPDUMPBITS(16) + + /* read and output the compressed data */ + while(n--) + { + ZIPNEEDBITS(8) + CAB(outbuf)[w++] = (cab_UBYTE)b; + ZIPDUMPBITS(8) + } + + /* restore the globals from the locals */ + ZIP(window_posn) = w; /* restore global window pointer */ + ZIP(bb) = b; /* restore global bit buffer */ + ZIP(bk) = k; + return 0; +} + +/****************************************************** + * fdi_Zipinflate_fixed (internal) + */ +static cab_LONG fdi_Zipinflate_fixed(fdi_decomp_state *decomp_state) +{ + struct Ziphuft *fixed_tl; + struct Ziphuft *fixed_td; + cab_LONG fixed_bl, fixed_bd; + cab_LONG i; /* temporary variable */ + cab_ULONG *l; + + l = ZIP(ll); + + /* literal table */ + for(i = 0; i < 144; i++) + l[i] = 8; + for(; i < 256; i++) + l[i] = 9; + for(; i < 280; i++) + l[i] = 7; + for(; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + fixed_bl = 7; + if((i = fdi_Ziphuft_build(l, 288, 257, Zipcplens, Zipcplext, &fixed_tl, &fixed_bl, decomp_state))) + return i; + + /* distance table */ + for(i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + fixed_bd = 5; + if((i = fdi_Ziphuft_build(l, 30, 0, Zipcpdist, Zipcpdext, &fixed_td, &fixed_bd, decomp_state)) > 1) + { + fdi_Ziphuft_free(CAB(fdi), fixed_tl); + return i; + } + + /* decompress until an end-of-block code */ + i = fdi_Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state); + + fdi_Ziphuft_free(CAB(fdi), fixed_td); + fdi_Ziphuft_free(CAB(fdi), fixed_tl); + return i; +} + +/************************************************************** + * fdi_Zipinflate_dynamic (internal) + */ +static cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state) + /* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + cab_LONG i; /* temporary variables */ + cab_ULONG j; + cab_ULONG *ll; + cab_ULONG l; /* last length */ + cab_ULONG m; /* mask for bit lengths table */ + cab_ULONG n; /* number of lengths to get */ + struct Ziphuft *tl; /* literal/length code table */ + struct Ziphuft *td; /* distance code table */ + cab_LONG bl; /* lookup bits for tl */ + cab_LONG bd; /* lookup bits for td */ + cab_ULONG nb; /* number of bit length codes */ + cab_ULONG nl; /* number of literal/length codes */ + cab_ULONG nd; /* number of distance codes */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = ZIP(bb); + k = ZIP(bk); + ll = ZIP(ll); + + /* read in table lengths */ + ZIPNEEDBITS(5) + nl = 257 + (b & 0x1f); /* number of literal/length codes */ + ZIPDUMPBITS(5) + ZIPNEEDBITS(5) + nd = 1 + (b & 0x1f); /* number of distance codes */ + ZIPDUMPBITS(5) + ZIPNEEDBITS(4) + nb = 4 + (b & 0xf); /* number of bit length codes */ + ZIPDUMPBITS(4) + if(nl > 288 || nd > 32) + return 1; /* bad lengths */ + + /* read in bit-length-code lengths */ + for(j = 0; j < nb; j++) + { + ZIPNEEDBITS(3) + ll[Zipborder[j]] = b & 7; + ZIPDUMPBITS(3) + } + for(; j < 19; j++) + ll[Zipborder[j]] = 0; + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if((i = fdi_Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0) + { + if(i == 1) + fdi_Ziphuft_free(CAB(fdi), tl); + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = Zipmask[bl]; + i = l = 0; + while((cab_ULONG)i < n) + { + ZIPNEEDBITS((cab_ULONG)bl) + j = (td = tl + (b & m))->b; + ZIPDUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + ZIPNEEDBITS(2) + j = 3 + (b & 3); + ZIPDUMPBITS(2) + if((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + ZIPNEEDBITS(3) + j = 3 + (b & 7); + ZIPDUMPBITS(3) + if ((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + ZIPNEEDBITS(7) + j = 11 + (b & 0x7f); + ZIPDUMPBITS(7) + if ((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + + /* free decoding table for trees */ + fdi_Ziphuft_free(CAB(fdi), tl); + + /* restore the global bit buffer */ + ZIP(bb) = b; + ZIP(bk) = k; + + /* build the decoding tables for literal/length and distance codes */ + bl = ZIPLBITS; + if((i = fdi_Ziphuft_build(ll, nl, 257, Zipcplens, Zipcplext, &tl, &bl, decomp_state)) != 0) + { + if(i == 1) + fdi_Ziphuft_free(CAB(fdi), tl); + return i; /* incomplete code set */ + } + bd = ZIPDBITS; + fdi_Ziphuft_build(ll + nl, nd, 0, Zipcpdist, Zipcpdext, &td, &bd, decomp_state); + + /* decompress until an end-of-block code */ + if(fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state)) + return 1; + + /* free the decoding tables, return */ + fdi_Ziphuft_free(CAB(fdi), tl); + fdi_Ziphuft_free(CAB(fdi), td); + return 0; +} + +/***************************************************** + * fdi_Zipinflate_block (internal) + */ +static cab_LONG fdi_Zipinflate_block(cab_LONG *e, fdi_decomp_state *decomp_state) /* e == last block flag */ +{ /* decompress an inflated block */ + cab_ULONG t; /* block type */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = ZIP(bb); + k = ZIP(bk); + + /* read in last block bit */ + ZIPNEEDBITS(1) + *e = (cab_LONG)b & 1; + ZIPDUMPBITS(1) + + /* read in block type */ + ZIPNEEDBITS(2) + t = b & 3; + ZIPDUMPBITS(2) + + /* restore the global bit buffer */ + ZIP(bb) = b; + ZIP(bk) = k; + + /* inflate that block type */ + if(t == 2) + return fdi_Zipinflate_dynamic(decomp_state); + if(t == 0) + return fdi_Zipinflate_stored(decomp_state); + if(t == 1) + return fdi_Zipinflate_fixed(decomp_state); + /* bad block type */ + return 2; +} + +/**************************************************** + * ZIPfdi_decomp(internal) + */ +int ZIPfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) +{ + cab_LONG e; /* last block flag */ + + ZIP(inpos) = CAB(inbuf); + ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0; + if(outlen > ZIPWSIZE) + return -1; + + /* CK = Chris Kirmse, official Microsoft purloiner */ + if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B) + return -1; + ZIP(inpos) += 2; + + do { + if(fdi_Zipinflate_block(&e, decomp_state)) + return -1; + } while(!e); + + /* return success */ + return 1; +} + +/************************************************************************* + * make_decode_table (internal) + * + * This function was coded by David Tritscher. It builds a fast huffman + * decoding table out of just a canonical huffman code lengths table. + * + * PARAMS + * nsyms: total number of symbols in this huffman tree. + * nbits: any symbols with a code length of nbits or less can be decoded + * in one lookup of the table. + * length: A table to get code lengths from [0 to syms-1] + * table: The table to fill up with decoded symbols and pointers. + * + * RETURNS + * OK: 0 + * error: 1 + */ +static int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, + const cab_UBYTE *length, cab_UWORD *table) { + register cab_UWORD sym; + register cab_ULONG leaf; + register cab_UBYTE bit_num = 1; + cab_ULONG fill; + cab_ULONG pos = 0; /* the current position in the decode table */ + cab_ULONG table_mask = 1 << nbits; + cab_ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */ + cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */ + + /* fill entries for codes short enough for a direct mapping */ + while (bit_num <= nbits) { + for (sym = 0; sym < nsyms; sym++) { + if (length[sym] == bit_num) { + leaf = pos; + + if((pos += bit_mask) > table_mask) return 1; /* table overrun */ + + /* fill all possible lookups of this symbol with the symbol itself */ + fill = bit_mask; + while (fill-- > 0) table[leaf++] = sym; + } + } + bit_mask >>= 1; + bit_num++; + } + + /* if there are any codes longer than nbits */ + if (pos != table_mask) { + /* clear the remainder of the table */ + for (sym = pos; sym < table_mask; sym++) table[sym] = 0; + + /* give ourselves room for codes to grow by up to 16 more bits */ + pos <<= 16; + table_mask <<= 16; + bit_mask = 1 << 15; + + while (bit_num <= 16) { + for (sym = 0; sym < nsyms; sym++) { + if (length[sym] == bit_num) { + leaf = pos >> 16; + for (fill = 0; fill < bit_num - nbits; fill++) { + /* if this path hasn't been taken yet, 'allocate' two entries */ + if (table[leaf] == 0) { + table[(next_symbol << 1)] = 0; + table[(next_symbol << 1) + 1] = 0; + table[leaf] = next_symbol++; + } + /* follow the path and select either left or right for next bit */ + leaf = table[leaf] << 1; + if ((pos >> (15-fill)) & 1) leaf++; + } + table[leaf] = sym; + + if ((pos += bit_mask) > table_mask) return 1; /* table overflow */ + } + } + bit_mask >>= 1; + bit_num++; + } + } + + /* full table? */ + if (pos == table_mask) return 0; + + /* either erroneous table, or all elements are 0 - let's find out. */ + for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1; + return 0; +} + +/************************************************************ + * fdi_lzx_read_lens (internal) + */ +static int fdi_lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb, + fdi_decomp_state *decomp_state) { + cab_ULONG i,j, x,y; + int z; + + register cab_ULONG bitbuf = lb->bb; + register int bitsleft = lb->bl; + cab_UBYTE *inpos = lb->ip; + cab_UWORD *hufftbl; + + for (x = 0; x < 20; x++) { + READ_BITS(y, 4); + LENTABLE(PRETREE)[x] = y; + } + BUILD_TABLE(PRETREE); + + for (x = first; x < last; ) { + READ_HUFFSYM(PRETREE, z); + if (z == 17) { + READ_BITS(y, 4); y += 4; + while (y--) lens[x++] = 0; + } + else if (z == 18) { + READ_BITS(y, 5); y += 20; + while (y--) lens[x++] = 0; + } + else if (z == 19) { + READ_BITS(y, 1); y += 4; + READ_HUFFSYM(PRETREE, z); + z = lens[x] - z; if (z < 0) z += 17; + while (y--) lens[x++] = z; + } + else { + z = lens[x] - z; if (z < 0) z += 17; + lens[x++] = z; + } + } + + lb->bb = bitbuf; + lb->bl = bitsleft; + lb->ip = inpos; + return 0; +} + +/************************************************************ + * LZXfdi_init (internal) + */ +int LZXfdi_init(int window, fdi_decomp_state *decomp_state) { + static const cab_UBYTE bits[] = + { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, + 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17}; + static const cab_ULONG base[] = + { 0, 1, 2, 3, 4, 6, 8, 12, + 16, 24, 32, 48, 64, 96, 128, 192, + 256, 384, 512, 768, 1024, 1536, 2048, 3072, + 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, + 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, + 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936, + 1835008, 1966080, 2097152}; + cab_ULONG wndsize = 1 << window; + int posn_slots; + + /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ + /* if a previously allocated window is big enough, keep it */ + if (window < 15 || window > 21) return DECR_DATAFORMAT; + if (LZX(actual_size) < wndsize) { + if (LZX(window)) CAB(fdi)->free(LZX(window)); + LZX(window) = NULL; + } + if (!LZX(window)) { + if (!(LZX(window) = CAB(fdi)->alloc(wndsize))) return DECR_NOMEMORY; + LZX(actual_size) = wndsize; + } + LZX(window_size) = wndsize; + + /* initialize static tables */ + memcpy(CAB(extra_bits), bits, sizeof(bits)); + memcpy(CAB(lzx_position_base), base, sizeof(base)); + + /* calculate required position slots */ + if (window == 20) posn_slots = 42; + else if (window == 21) posn_slots = 50; + else posn_slots = window << 1; + + /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */ + + LZX(R0) = LZX(R1) = LZX(R2) = 1; + LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3); + LZX(header_read) = 0; + LZX(frames_read) = 0; + LZX(block_remaining) = 0; + LZX(block_type) = LZX_BLOCKTYPE_INVALID; + LZX(intel_curpos) = 0; + LZX(intel_started) = 0; + LZX(window_posn) = 0; + + /* initialize tables to 0 (because deltas will be applied to them) */ + memset(LZX(MAINTREE_len), 0, sizeof(LZX(MAINTREE_len))); + memset(LZX(LENGTH_len), 0, sizeof(LZX(LENGTH_len))); + + return DECR_OK; +} + +void LZXfdi_clear(fdi_decomp_state *decomp_state) { + cab_UBYTE *window = LZX(window); + CAB(fdi)->free(window); +} + +/******************************************************* + * LZXfdi_decomp(internal) + */ +int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) { + cab_UBYTE *inpos = CAB(inbuf); + const cab_UBYTE *endinp = inpos + inlen; + cab_UBYTE *window = LZX(window); + cab_UBYTE *runsrc, *rundest; + cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */ + + cab_ULONG window_posn = LZX(window_posn); + cab_ULONG window_size = LZX(window_size); + cab_ULONG R0 = LZX(R0); + cab_ULONG R1 = LZX(R1); + cab_ULONG R2 = LZX(R2); + + register cab_ULONG bitbuf; + register int bitsleft; + cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */ + struct lzx_bits lb; /* used in READ_LENGTHS macro */ + + int togo = outlen, this_run, main_element, aligned_bits; + int match_length, copy_length, length_footer, extra, verbatim_bits; + + INIT_BITSTREAM; + + /* read header if necessary */ + if (!LZX(header_read)) { + i = j = 0; + READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); } + LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */ + LZX(header_read) = 1; + } + + /* main decoding loop */ + while (togo > 0) { + /* last block finished, new block expected */ + if (LZX(block_remaining) == 0) { + if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) { + if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */ + INIT_BITSTREAM; + } + + READ_BITS(LZX(block_type), 3); + READ_BITS(i, 16); + READ_BITS(j, 8); + LZX(block_remaining) = LZX(block_length) = (i << 8) | j; + + switch (LZX(block_type)) { + case LZX_BLOCKTYPE_ALIGNED: + for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; } + BUILD_TABLE(ALIGNED); + /* rest of aligned header is same as verbatim */ + /* fall-thru */ + + case LZX_BLOCKTYPE_VERBATIM: + READ_LENGTHS(MAINTREE, 0, 256, fdi_lzx_read_lens); + READ_LENGTHS(MAINTREE, 256, LZX(main_elements), fdi_lzx_read_lens); + BUILD_TABLE(MAINTREE); + if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1; + + READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, fdi_lzx_read_lens); + BUILD_TABLE(LENGTH); + break; + + case LZX_BLOCKTYPE_UNCOMPRESSED: + LZX(intel_started) = 1; /* because we can't assume otherwise */ + ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */ + if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */ + R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + break; + + default: + return DECR_ILLEGALDATA; + } + } + + /* buffer exhaustion check */ + if (inpos > endinp) { + /* it's possible to have a file where the next run is less than + * 16 bits in size. In this case, the READ_HUFFSYM() macro used + * in building the tables will exhaust the buffer, so we should + * allow for this, but not allow those accidentally read bits to + * be used (so we check that there are at least 16 bits + * remaining - in this boundary case they aren't really part of + * the compressed data) + */ + if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA; + } + + while ((this_run = LZX(block_remaining)) > 0 && togo > 0) { + if (this_run > togo) this_run = togo; + togo -= this_run; + LZX(block_remaining) -= this_run; + + /* apply 2^x-1 mask */ + window_posn &= window_size - 1; + /* runs can't straddle the window wraparound */ + if ((window_posn + this_run) > window_size) + return DECR_DATAFORMAT; + + switch (LZX(block_type)) { + + case LZX_BLOCKTYPE_VERBATIM: + while (this_run > 0) { + READ_HUFFSYM(MAINTREE, main_element); + + if (main_element < LZX_NUM_CHARS) { + /* literal: 0 to LZX_NUM_CHARS-1 */ + window[window_posn++] = main_element; + this_run--; + } + else { + /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ + main_element -= LZX_NUM_CHARS; + + match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; + if (match_length == LZX_NUM_PRIMARY_LENGTHS) { + READ_HUFFSYM(LENGTH, length_footer); + match_length += length_footer; + } + match_length += LZX_MIN_MATCH; + + match_offset = main_element >> 3; + + if (match_offset > 2) { + /* not repeated offset */ + if (match_offset != 3) { + extra = CAB(extra_bits)[match_offset]; + READ_BITS(verbatim_bits, extra); + match_offset = CAB(lzx_position_base)[match_offset] + - 2 + verbatim_bits; + } + else { + match_offset = 1; + } + + /* update repeated offset LRU queue */ + R2 = R1; R1 = R0; R0 = match_offset; + } + else if (match_offset == 0) { + match_offset = R0; + } + else if (match_offset == 1) { + match_offset = R1; + R1 = R0; R0 = match_offset; + } + else /* match_offset == 2 */ { + match_offset = R2; + R2 = R0; R0 = match_offset; + } + + rundest = window + window_posn; + this_run -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + memcpy(rundest, runsrc, match_length); + rundest += match_length; + runsrc += match_length; + } + } + break; + + case LZX_BLOCKTYPE_ALIGNED: + while (this_run > 0) { + READ_HUFFSYM(MAINTREE, main_element); + + if (main_element < LZX_NUM_CHARS) { + /* literal: 0 to LZX_NUM_CHARS-1 */ + window[window_posn++] = main_element; + this_run--; + } + else { + /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ + main_element -= LZX_NUM_CHARS; + + match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; + if (match_length == LZX_NUM_PRIMARY_LENGTHS) { + READ_HUFFSYM(LENGTH, length_footer); + match_length += length_footer; + } + match_length += LZX_MIN_MATCH; + + match_offset = main_element >> 3; + + if (match_offset > 2) { + /* not repeated offset */ + extra = CAB(extra_bits)[match_offset]; + match_offset = CAB(lzx_position_base)[match_offset] - 2; + if (extra > 3) { + /* verbatim and aligned bits */ + extra -= 3; + READ_BITS(verbatim_bits, extra); + match_offset += (verbatim_bits << 3); + READ_HUFFSYM(ALIGNED, aligned_bits); + match_offset += aligned_bits; + } + else if (extra == 3) { + /* aligned bits only */ + READ_HUFFSYM(ALIGNED, aligned_bits); + match_offset += aligned_bits; + } + else if (extra > 0) { /* extra==1, extra==2 */ + /* verbatim bits only */ + READ_BITS(verbatim_bits, extra); + match_offset += verbatim_bits; + } + else /* extra == 0 */ { + /* ??? */ + match_offset = 1; + } + + /* update repeated offset LRU queue */ + R2 = R1; R1 = R0; R0 = match_offset; + } + else if (match_offset == 0) { + match_offset = R0; + } + else if (match_offset == 1) { + match_offset = R1; + R1 = R0; R0 = match_offset; + } + else /* match_offset == 2 */ { + match_offset = R2; + R2 = R0; R0 = match_offset; + } + + rundest = window + window_posn; + this_run -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + memcpy(rundest, runsrc, match_length); + rundest += match_length; + runsrc += match_length; + } + } + break; + + case LZX_BLOCKTYPE_UNCOMPRESSED: + if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA; + memcpy(window + window_posn, inpos, (size_t) this_run); + inpos += this_run; window_posn += this_run; + break; + + default: + return DECR_ILLEGALDATA; /* might as well */ + } + + } + } + + if (togo != 0) return DECR_ILLEGALDATA; + memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - + outlen, (size_t) outlen); + + LZX(window_posn) = window_posn; + LZX(R0) = R0; + LZX(R1) = R1; + LZX(R2) = R2; + + /* intel E8 decoding */ + if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) { + if (outlen <= 6 || !LZX(intel_started)) { + LZX(intel_curpos) += outlen; + } + else { + cab_UBYTE *data = CAB(outbuf); + cab_UBYTE *dataend = data + outlen - 10; + cab_LONG curpos = LZX(intel_curpos); + cab_LONG filesize = LZX(intel_filesize); + cab_LONG abs_off, rel_off; + + LZX(intel_curpos) = curpos + outlen; + + while (data < dataend) { + if (*data++ != 0xE8) { curpos++; continue; } + abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); + if ((abs_off >= -curpos) && (abs_off < filesize)) { + rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; + data[0] = (cab_UBYTE) rel_off; + data[1] = (cab_UBYTE) (rel_off >> 8); + data[2] = (cab_UBYTE) (rel_off >> 16); + data[3] = (cab_UBYTE) (rel_off >> 24); + } + data += 4; + curpos += 5; + } + } + } + return DECR_OK; +} diff --git a/libgcab/decomp.h b/libgcab/decomp.h new file mode 100644 index 0000000..041d60e --- /dev/null +++ b/libgcab/decomp.h @@ -0,0 +1,252 @@ +/* + * Adapted from Wine fdi.c: File Decompression Interface + * + * Copyright 2000-2002 Stuart Caie + * Copyright 2002 Patrik Stridvall + * Copyright 2003 Greg Turner + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef MSZIP_H_ +# define MSZIP_H_ + +#include + +#define DECR_ILLEGALDATA -1 +#define DECR_DATAFORMAT -2 +#define DECR_NOMEMORY -3 +#define DECR_OK 1 + +/* Bitstream reading macros (LZX / intel little-endian byte order) + * + * INIT_BITSTREAM should be used first to set up the system + * READ_BITS(var,n) takes N bits from the buffer and puts them in var + * + * ENSURE_BITS(n) ensures there are at least N bits in the bit buffer. + * it can guarantee up to 17 bits (i.e. it can read in + * 16 new bits when there is down to 1 bit in the buffer, + * and it can read 32 bits when there are 0 bits in the + * buffer). + * PEEK_BITS(n) extracts (without removing) N bits from the bit buffer + * REMOVE_BITS(n) removes N bits from the bit buffer + * + * These bit access routines work by using the area beyond the MSB and the + * LSB as a free source of zeroes. This avoids having to mask any bits. + * So we have to know the bit width of the bitbuffer variable. + */ + +#define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0) + +/* Quantum reads bytes in normal order; LZX is little-endian order */ +#define ENSURE_BITS(n) \ + while (bitsleft < (n)) { \ + bitbuf |= ((inpos[1]<<8)|inpos[0]) << (CAB_ULONG_BITS-16 - bitsleft); \ + bitsleft += 16; inpos+=2; \ + } + +#define PEEK_BITS(n) (bitbuf >> (CAB_ULONG_BITS - (n))) +#define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n))) + +#define READ_BITS(v,n) do { \ + if (n) { \ + ENSURE_BITS(n); \ + (v) = PEEK_BITS(n); \ + REMOVE_BITS(n); \ + } \ + else { \ + (v) = 0; \ + } \ +} while (0) + +/* Huffman macros */ + +#define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS) +#define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS) +#define SYMTABLE(tbl) (LZX(tbl##_table)) +#define LENTABLE(tbl) (LZX(tbl##_len)) + +/* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths. + * In reality, it just calls make_decode_table() with the appropriate + * values - they're all fixed by some #defines anyway, so there's no point + * writing each call out in full by hand. + */ +#define BUILD_TABLE(tbl) \ + if (make_decode_table( \ + MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \ + )) { return DECR_ILLEGALDATA; } + +/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the + * bitstream using the stated table and puts it in var. + */ +#define READ_HUFFSYM(tbl,var) do { \ + ENSURE_BITS(16); \ + hufftbl = SYMTABLE(tbl); \ + if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \ + j = 1 << (CAB_ULONG_BITS - TABLEBITS(tbl)); \ + do { \ + j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \ + if (!j) { return DECR_ILLEGALDATA; } \ + } while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \ + } \ + j = LENTABLE(tbl)[(var) = i]; \ + REMOVE_BITS(j); \ +} while (0) + +/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols + * first to last in the given table. The code lengths are stored in their + * own special LZX way. + */ +#define READ_LENGTHS(tbl,first,last,fn) do { \ + lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos; \ + if (fn(LENTABLE(tbl),(first),(last),&lb,decomp_state)) { \ + return DECR_ILLEGALDATA; \ + } \ + bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \ +} while (0) + +/* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed + * blocks have zero growth. MSZIP guarantees that it won't grow above + * uncompressed size by more than 12 bytes. LZX guarantees it won't grow + * more than 6144 bytes. + */ +#define CAB_BLOCKMAX (32768) +#define CAB_INPUTMAX (CAB_BLOCKMAX+6144) + +typedef guint8 cab_UBYTE; /* 8 bits */ +typedef guint16 cab_UWORD; /* 16 bits */ +typedef guint32 cab_ULONG; /* 32 bits */ +typedef gint32 cab_LONG; /* 32 bits */ + +/* number of bits in a ULONG */ +#ifndef CHAR_BIT +# define CHAR_BIT (8) +#endif +#define CAB_ULONG_BITS (sizeof(cab_ULONG) * CHAR_BIT) + +/* MSZIP stuff */ +#define ZIPWSIZE 0x8000 /* window size */ +#define ZIPLBITS 9 /* bits in base literal/length lookup table */ +#define ZIPDBITS 6 /* bits in base distance lookup table */ +#define ZIPBMAX 16 /* maximum bit length of any code */ +#define ZIPN_MAX 288 /* maximum number of codes in any set */ + +struct Ziphuft { + cab_UBYTE e; /* number of extra bits or operation */ + cab_UBYTE b; /* number of bits in this code or subcode */ + union { + cab_UWORD n; /* literal, length base, or distance base */ + struct Ziphuft *t; /* pointer to next level of table */ + } v; +}; +struct ZIPstate { + cab_ULONG window_posn; /* current offset within the window */ + cab_ULONG bb; /* bit buffer */ + cab_ULONG bk; /* bits in bit buffer */ + cab_ULONG ll[288+32]; /* literal/length and distance code lengths */ + cab_ULONG c[ZIPBMAX+1]; /* bit length count table */ + cab_LONG lx[ZIPBMAX+1]; /* memory for l[-1..ZIPBMAX-1] */ + struct Ziphuft *u[ZIPBMAX]; /* table stack */ + cab_ULONG v[ZIPN_MAX]; /* values in order of bit length */ + cab_ULONG x[ZIPBMAX+1]; /* bit offsets, then code stack */ + cab_UBYTE *inpos; +}; + +/* LZX stuff */ + +/* some constants defined by the LZX specification */ +#define LZX_MIN_MATCH (2) +#define LZX_MAX_MATCH (257) +#define LZX_NUM_CHARS (256) +#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */ +#define LZX_BLOCKTYPE_VERBATIM (1) +#define LZX_BLOCKTYPE_ALIGNED (2) +#define LZX_BLOCKTYPE_UNCOMPRESSED (3) +#define LZX_PRETREE_NUM_ELEMENTS (20) +#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */ +#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */ +#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */ + +/* LZX huffman defines: tweak tablebits as desired */ +#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS) +#define LZX_PRETREE_TABLEBITS (6) +#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8) +#define LZX_MAINTREE_TABLEBITS (12) +#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1) +#define LZX_LENGTH_TABLEBITS (12) +#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS) +#define LZX_ALIGNED_TABLEBITS (7) + +#define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */ + +#define LZX_DECLARE_TABLE(tbl) \ + cab_UWORD tbl##_table[(1< + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include "gcab-priv.h" + +/** + * SECTION:gcab-cabinet + * @title: GCabCabinet + * @short_description: Cabinet archive file operations + * @see_also: #GCabFolder + * @stability: Stable + * @include: libgcab.h + * + * A GCabCabinet is a handle to a Cabinet archive. It allows examining, + * extracting and creation of archives. + */ + +struct _GCabCabinet { + GObject parent_instance; + + GPtrArray *folders; + GByteArray *reserved; + cheader_t *cheader; + GByteArray *signature; + GInputStream *stream; +}; + +enum { + PROP_0, + + PROP_RESERVED, + PROP_SIGNATURE, +}; + +G_DEFINE_TYPE (GCabCabinet, gcab_cabinet, G_TYPE_OBJECT); + +GQuark +gcab_error_quark (void) +{ + return g_quark_from_static_string ("gcab-error-quark"); +} + +static void +gcab_cabinet_init (GCabCabinet *self) +{ + self->folders = g_ptr_array_new_with_free_func (g_object_unref); +} + +static void +gcab_cabinet_finalize (GObject *object) +{ + GCabCabinet *self = GCAB_CABINET (object); + + cheader_free (self->cheader); + g_ptr_array_unref (self->folders); + if (self->reserved) + g_byte_array_unref (self->reserved); + if (self->signature) + g_byte_array_unref (self->signature); + if (self->stream) + g_object_unref (self->stream); + + G_OBJECT_CLASS (gcab_cabinet_parent_class)->finalize (object); +} + +static void +gcab_cabinet_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GCAB_IS_CABINET (object)); + GCabCabinet *self = GCAB_CABINET (object); + + switch (prop_id) { + case PROP_RESERVED: + if (self->reserved) + g_byte_array_unref (self->reserved); + self->reserved = g_value_dup_boxed (value); + break; + case PROP_SIGNATURE: + if (self->signature) + g_byte_array_unref (self->signature); + self->signature = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gcab_cabinet_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GCAB_IS_CABINET (object)); + GCabCabinet *self = GCAB_CABINET (object); + + switch (prop_id) { + case PROP_RESERVED: + g_value_set_boxed (value, self->reserved); + break; + case PROP_SIGNATURE: + g_value_set_boxed (value, gcab_cabinet_get_signature (self, NULL, NULL)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gcab_cabinet_class_init (GCabCabinetClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + object_class->finalize = gcab_cabinet_finalize; + object_class->set_property = gcab_cabinet_set_property; + object_class->get_property = gcab_cabinet_get_property; + + g_object_class_install_property (object_class, PROP_RESERVED, + g_param_spec_boxed ("reserved", "Reserved", "Reserved", + G_TYPE_BYTE_ARRAY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_SIGNATURE, + g_param_spec_boxed ("signature", "Signature", "Signature", + G_TYPE_BYTE_ARRAY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +/** + * gcab_cabinet_add_folder: + * @cabinet: a #GCabCabinet + * @folder: a #GCabFolder + * @error: (allow-none): #GError to set on error, or %NULL + * + * Add @folder to @cabinet. + * + * Returns: %TRUE on success. + **/ +gboolean +gcab_cabinet_add_folder (GCabCabinet *self, + GCabFolder *folder, + GError **error) +{ + g_return_val_if_fail (GCAB_IS_CABINET (self), FALSE); + g_return_val_if_fail (GCAB_IS_FOLDER (folder), FALSE); + g_return_val_if_fail (!error || *error == NULL, FALSE); + + for (guint i = 0; i < self->folders->len; i++) { + GCabFolder *folder_tmp = g_ptr_array_index (self->folders, i); + if (folder_tmp == folder) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "Folder has already been added"); + return FALSE; + } + } + + g_ptr_array_add (self->folders, g_object_ref (folder)); + + return TRUE; +} + +/** + * gcab_cabinet_get_folders: + * @cabinet:a #GCabCabinet + * + * Get the Cabinet folders within the @cabinet. + * Note that Cabinet folders are not like filesystem path, they are + * group of files sharing some layout parameters. + * + * Returns: (element-type GCabFolder) (transfer none): an array of #GCabFolder + **/ +GPtrArray * +gcab_cabinet_get_folders (GCabCabinet *self) +{ + g_return_val_if_fail (GCAB_IS_CABINET (self), NULL); + + return self->folders; +} + +/** + * gcab_cabinet_get_size: + * @cabinet:a #GCabCabinet + * + * Get the size of the compressed cabinet file. + * + * Returns: size in bytes + * + * Since: 1.0 + **/ +guint32 +gcab_cabinet_get_size (GCabCabinet *self) +{ + if (self->cheader == NULL) + return 0; + return self->cheader->size; +} + +/** + * gcab_cabinet_write: + * @cabinet: a #GCabCabinet + * @stream: a #GOutputStream also #GSeekable + * @file_callback: (allow-none) (scope call) (closure user_data): report current file being saved + * @progress_callback: (allow-none) (scope call) (closure user_data): report saving progress + * @user_data: (closure): user data to pass to callbacks + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Save @cabinet to the output stream @out. @out must be a #GSeekable. + * + * Returns: %TRUE on success. + **/ +gboolean +gcab_cabinet_write (GCabCabinet *self, + GOutputStream *out, + GCabFileCallback file_callback, + GFileProgressCallback progress_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(cheader_t) cheader = g_new0 (cheader_t, 1); + cfolder_t folder = { 0, }; + + g_return_val_if_fail (GCAB_IS_CABINET (self), FALSE); + g_return_val_if_fail (G_IS_OUTPUT_STREAM (out), FALSE); + g_return_val_if_fail (G_IS_SEEKABLE (out), FALSE); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (!error || *error == NULL, FALSE); + + /* FIXME: support more than one folder */ + cheader->offsetfiles = CFI_START; // CFHEADER + 1 * CFFOLDER + cheader->nfolders = 1; // a single CAB folder is enough + + /* nothing to do */ + if (self->folders->len == 0) { + g_set_error_literal (error, GCAB_ERROR, GCAB_ERROR_FAILED, + "Cabinet has no added folders"); + return FALSE; + } + + /* unsupported */ + if (self->folders->len > 1) { + g_set_error_literal (error, GCAB_ERROR, GCAB_ERROR_NOT_SUPPORTED, + "Cabinet has more than one added folder"); + return FALSE; + } + + GCabFolder *cabfolder = g_ptr_array_index (self->folders, 0); + gsize nfiles = gcab_folder_get_nfiles (cabfolder); + g_autoptr(GDataOutputStream) dstream = NULL; + gssize len, offset = 0; + cdata_t block = { 0, }; + guint8 data[DATABLOCKSIZE]; + gsize written; + size_t sumstr = 0; + g_autoptr(GSList) files = NULL; + GCabFile *prevf = NULL; + + dstream = g_data_output_stream_new (out); + g_data_output_stream_set_byte_order (dstream, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN); + + if (self->reserved) { + cheader->offsetfiles += self->reserved->len + 4; + cheader->flags = CABINET_HEADER_RESERVE; + cheader->res_header = self->reserved->len; + cheader->res_folder = 0; + cheader->res_data = 0; + cheader->reserved = self->reserved->data; + } + + files = gcab_folder_get_files (cabfolder); + for (GSList *l = files; l != NULL; l = l->next) { + GCabFile *cabfile = GCAB_FILE (l->data); + sumstr += strlen (gcab_file_get_name (cabfile)) + 1; + } + + folder.typecomp = gcab_folder_get_comptype (cabfolder); + folder.offsetdata = cheader->offsetfiles + nfiles * 16 + sumstr; + folder.ndatab = gcab_folder_get_ndatablocks (cabfolder); + + /* avoid seeking to allow growing output streams */ + for (guint i = 0; i < folder.offsetdata; i++) + if (!g_data_output_stream_put_byte (dstream, 0, cancellable, error)) + return FALSE; + + for (GSList *l = files; l != NULL; l = l->next) { + g_autoptr(GInputStream) in = NULL; + + GCabFile *file = GCAB_FILE (l->data); + if (file_callback) + file_callback (file, user_data); + + in = gcab_file_get_input_stream (file, cancellable, error); + if (in == NULL) + return FALSE; + + while ((len = g_input_stream_read (in, + &data[offset], DATABLOCKSIZE - offset, + cancellable, error)) == (DATABLOCKSIZE - offset)) { + if (!cdata_write (&block, dstream, folder.typecomp, data, DATABLOCKSIZE, &written, cancellable, error)) + return FALSE; + cheader->size += written; + offset = 0; + } + + if (len == -1) + return FALSE; + + offset += len; + } + if (offset != 0) { + if (!cdata_write (&block, dstream, folder.typecomp, data, offset, &written, cancellable, error)) + return FALSE; + cheader->size += written; + } + + if (!g_seekable_seek (G_SEEKABLE (out), 0, + G_SEEK_SET, cancellable, error)) + return FALSE; + + cheader->nfiles = nfiles; + cheader->size += cheader->offsetfiles + nfiles * 16; /* 1st part cfile struct = 16 bytes */ + cheader->size += sumstr; + + if (!cheader_write (cheader, dstream, cancellable, error)) + return FALSE; + + if (!cfolder_write (&folder, dstream, cancellable, error)) + return FALSE; + + for (GSList *l = files; l != NULL; l = l->next) { + GCabFile *file = GCAB_FILE (l->data); + gcab_file_set_uoffset (file, prevf ? gcab_file_get_uoffset (prevf) + gcab_file_get_usize (prevf) : 0); + prevf = file; + + /* automatically set flag if UTF-8 encoding */ + if (!g_str_is_ascii (gcab_file_get_name (file))) + gcab_file_add_attribute (file, GCAB_FILE_ATTRIBUTE_NAME_IS_UTF); + + if (!cfile_write (gcab_file_get_cfile (file), dstream, cancellable, error)) + return FALSE; + } + + /* replace the cached copy */ + if (self->cheader != NULL) + cheader_free (self->cheader); + self->cheader = g_steal_pointer (&cheader); + + return TRUE; +} + +/** + * gcab_cabinet_write_simple: + * @cabinet: a #GCabCabinet + * @stream: a #GOutputStream also #GSeekable + * @file_callback: (allow-none) (scope call) (closure user_data): report current file being saved + * @user_data: (closure): user data to pass to callbacks + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Save @cabinet to the output stream @out. @out must be a #GSeekable. + * + * Returns: %TRUE on success. + **/ +gboolean +gcab_cabinet_write_simple (GCabCabinet *self, + GOutputStream *out, + GCabFileCallback file_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + return gcab_cabinet_write (self, out, file_callback, NULL, user_data, cancellable, error); +} + +/** + * gcab_cabinet_new: + * + * Create a new #GCabCabinet object to read or create a Cabinet + * archive. + * + * Returns: a new #GCabCabinet + **/ +GCabCabinet * +gcab_cabinet_new (void) +{ + return g_object_new (GCAB_TYPE_CABINET, NULL); +} + +/** + * gcab_cabinet_load: + * @cabinet: a #GCabCabinet + * @stream: a #GInputStream + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Load a cabinet archive. + * + * Returns: %TRUE on success + **/ +gboolean +gcab_cabinet_load (GCabCabinet *self, + GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (GCAB_IS_CABINET (self), FALSE); + g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (!error || *error == NULL, FALSE); + g_return_val_if_fail (self->folders->len == 0, FALSE); + g_return_val_if_fail (self->stream == NULL, FALSE); + + g_autoptr(cheader_t) cheader = NULL; + g_autoptr(GDataInputStream) in = g_data_input_stream_new (stream); + g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (in), FALSE); + g_data_input_stream_set_byte_order (in, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN); + + cheader = g_new0 (cheader_t, 1); + if (!cheader_read (cheader, in, cancellable, error)) + return FALSE; + + if (cheader->reserved != NULL) { + g_autoptr(GByteArray) blob = NULL; + blob = g_byte_array_new_take (cheader->reserved, cheader->res_header); + g_object_set (self, "reserved", blob, NULL); + cheader->reserved = NULL; + } + + for (guint i = 0; i < cheader->nfolders; i++) { + g_autoptr(cfolder_t) cfolder = g_new0 (cfolder_t, 1); + g_autoptr(GByteArray) blob = NULL; + if (!cfolder_read (cfolder, cheader->res_folder, in, cancellable, error)) + return FALSE; + + /* steal this inelegantly */ + if (cfolder->reserved != NULL) { + blob = g_byte_array_new_take (cfolder->reserved, cheader->res_folder); + cfolder->reserved = NULL; + } + + GCabFolder *folder = gcab_folder_new_steal_cfolder (&cfolder); + if (blob != NULL) + g_object_set (folder, "reserved", blob, NULL); + g_ptr_array_add (self->folders, folder); + } + + for (guint i = 0; i < cheader->nfiles; i++) { + g_autoptr(cfile_t) cfile = g_new0 (cfile_t, 1); + if (!cfile_read (cfile, in, cancellable, error)) + return FALSE; + + if (cfile->index >= self->folders->len) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "Invalid folder index"); + return FALSE; + } + + GCabFolder *folder = g_ptr_array_index (self->folders, cfile->index); + if (folder == NULL) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "Invalid folder pointer"); + return FALSE; + } + + g_autoptr(GCabFile) file = gcab_file_new_steal_cfile (&cfile); + if (!gcab_folder_add_file (folder, file, FALSE, cancellable, error)) + return FALSE; + } + + self->stream = g_object_ref (stream); + self->cheader = g_steal_pointer (&cheader); + return TRUE; +} + +/** + * gcab_cabinet_extract: + * @cabinet: a #GCabCabinet + * @path: (allow-none): the path to extract files + * @file_callback: (allow-none) (scope call) (closure user_data): an optional #GCabFile callback, + * return %FALSE to filter out or skip files. + * @progress_callback: (allow-none) (scope call) (closure user_data): a progress callback + * @user_data: (closure): callback data + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Extract files to given path. + * + * If @path is NULL then the files are decompressed to memory blobs stored on + * each #GCabFile. + * + * Returns: %TRUE on success. + **/ +gboolean +gcab_cabinet_extract (GCabCabinet *self, + GFile *path, + GCabFileCallback file_callback, + GFileProgressCallback progress_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (GCAB_IS_CABINET (self), FALSE); + g_return_val_if_fail (!path || G_IS_FILE (path), FALSE); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (!error || *error == NULL, FALSE); + + /* never loaded from a stream */ + if (self->cheader == NULL) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED, + "Cabinet has not been loaded"); + return FALSE; + } + + g_autoptr(GDataInputStream) data = g_data_input_stream_new (self->stream); + g_data_input_stream_set_byte_order (data, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN); + g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (data), FALSE); + + for (guint i = 0; i < self->folders->len; ++i) { + GCabFolder *folder = g_ptr_array_index (self->folders, i); + if (!gcab_folder_extract (folder, data, path, self->cheader->res_data, + file_callback, progress_callback, user_data, + cancellable, error)) { + return FALSE; + } + } + + return TRUE; +} + +/** + * gcab_cabinet_extract_simple: + * @cabinet: a #GCabCabinet + * @path: the path to extract files + * @file_callback: (allow-none) (scope call) (closure user_data): an optional #GCabFile callback, + * return %FALSE to filter out or skip files. + * @user_data: (closure): callback data + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Extract files to given path. + * + * Returns: %TRUE on success. + **/ +gboolean +gcab_cabinet_extract_simple (GCabCabinet *cabinet, + GFile *path, + GCabFileCallback file_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + return gcab_cabinet_extract (cabinet, path, file_callback, NULL, user_data, cancellable, error); +} + +/** + * gcab_cabinet_get_signature: + * @cabinet: a #GCabCabinet + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Lookup the cabinet authenticode signature if any. + * + * Since: 0.5 + * + * Returns: the array containing the PKCS#7 signed data or %NULL on error. + **/ +const GByteArray * +gcab_cabinet_get_signature (GCabCabinet *self, + GCancellable *cancellable, + GError **error) +{ + const guint8 magic[] = { 0x00, 0x00, 0x10, 0x00 }; + gssize sz; + guint8 *reserved; + guint32 offset; + guint32 size; + + g_return_val_if_fail (GCAB_IS_CABINET (self), NULL); + g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (!error || *error == NULL, NULL); + + if (self->signature) + return self->signature; + + if (!G_IS_SEEKABLE (self->stream)) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_NOT_SUPPORTED, + "Cabinet stream is not seekable"); + return NULL; + } + + if (!self->reserved || self->reserved->len != 20) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED, + "Cabinet has no reserved area"); + return NULL; + } + + reserved = self->reserved->data; + if (memcmp (reserved, magic, sizeof (magic)) != 0) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "Cabinet reserved magic was not correct"); + return NULL; + } + + offset = GCAB_READ_UINT32_LE (reserved + 4); + size = GCAB_READ_UINT32_LE (reserved + 8); + if (g_getenv ("GCAB_DEBUG")) + g_debug ("signature offset: %u size: %u", offset, size); + + self->signature = g_byte_array_sized_new (size); + g_byte_array_set_size (self->signature, size); + + if (!g_seekable_seek (G_SEEKABLE (self->stream), offset, G_SEEK_SET, cancellable, error)) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_INVALID_DATA, + "Cannot seek to reserved area"); + return NULL; + } + + sz = g_input_stream_read (self->stream, + self->signature->data, self->signature->len, + cancellable, error); + if (sz < 0) { + g_prefix_error (error, "Failed to read signature from stream: "); + return NULL; + } + if (sz != self->signature->len) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED, + "Failed to read correct size signature from stream: "); + return NULL; + } + + return self->signature; +} diff --git a/libgcab/gcab-cabinet.h b/libgcab/gcab-cabinet.h new file mode 100644 index 0000000..36d13b1 --- /dev/null +++ b/libgcab/gcab-cabinet.h @@ -0,0 +1,110 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _GCAB_CABINET_H_ +#define _GCAB_CABINET_H_ + +#include +#include + +#include "gcab-folder.h" +#include "gcab-file.h" + +G_BEGIN_DECLS + +/** + * GCabCabinet: + * + * An opaque object holding a Cabinet file reference. + **/ +#define GCAB_TYPE_CABINET (gcab_cabinet_get_type ()) +G_DECLARE_FINAL_TYPE(GCabCabinet, gcab_cabinet, GCAB, CABINET, GObject) + +/** + * GCAB_ERROR: + * + * Error domain for the GCab library. See #GError for more information + * on error domains. + */ +#define GCAB_ERROR gcab_error_quark () +GQuark gcab_error_quark (void); + +/** + * GCabError: + * @GCAB_ERROR_FORMAT: The given file is not of Cabinet format. + * @GCAB_ERROR_FAILED: General function failure. + * @GCAB_ERROR_NOT_SUPPORTED: Action or format is not supported + * @GCAB_ERROR_INVALID_DATA: Data stream was invalid + * + * The various errors triggered by the GCab functions. + **/ +typedef enum GCabError +{ + GCAB_ERROR_FORMAT, + GCAB_ERROR_FAILED, + GCAB_ERROR_NOT_SUPPORTED, /* Since: 1.0 */ + GCAB_ERROR_INVALID_DATA, /* Since: 1.0 */ +} GCabError; + +GCabCabinet * gcab_cabinet_new (void); +gboolean gcab_cabinet_load (GCabCabinet *cabinet, + GInputStream *stream, + GCancellable *cancellable, + GError **error); + +GPtrArray * gcab_cabinet_get_folders (GCabCabinet *cabinet); +guint32 gcab_cabinet_get_size (GCabCabinet *cabinet); + +gboolean gcab_cabinet_add_folder (GCabCabinet *cabinet, + GCabFolder *folder, + GError **error); +gboolean gcab_cabinet_write (GCabCabinet *cabinet, + GOutputStream *stream, + GCabFileCallback file_callback, + GFileProgressCallback progress_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error); +gboolean gcab_cabinet_write_simple (GCabCabinet *cabinet, + GOutputStream *stream, + GCabFileCallback file_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error); +gboolean gcab_cabinet_extract (GCabCabinet *cabinet, + GFile *path, + GCabFileCallback file_callback, + GFileProgressCallback progress_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error); +gboolean gcab_cabinet_extract_simple(GCabCabinet *cabinet, + GFile *path, + GCabFileCallback file_callback, + gpointer user_data, + GCancellable *cancellable, + GError **error); +const GByteArray * gcab_cabinet_get_signature (GCabCabinet *cabinet, + GCancellable *cancellable, + GError **error); + +G_END_DECLS + +#endif /* _GCAB_CABINET_H_ */ diff --git a/libgcab/gcab-enums.c.etemplate b/libgcab/gcab-enums.c.etemplate new file mode 100644 index 0000000..2957403 --- /dev/null +++ b/libgcab/gcab-enums.c.etemplate @@ -0,0 +1,55 @@ +/*** BEGIN file-header ***/ +/* + * Copyright (C) 2012 Marc-André Lureau + * + * This 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 of the License, or (at your option) any later version. + * + * This 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 this library. If not, see . + */ + +#include "gcab-enums.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +#include "@filename@" +/*** END file-production ***/ + + +/*** BEGIN value-header ***/ + +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/*** END value-tail ***/ diff --git a/libgcab/gcab-enums.h.etemplate b/libgcab/gcab-enums.h.etemplate new file mode 100644 index 0000000..7dcf015 --- /dev/null +++ b/libgcab/gcab-enums.h.etemplate @@ -0,0 +1,36 @@ +/*** BEGIN file-header ***/ +/* + * Copyright (C) 2012 Marc-André Lureau + * + * This 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 of the License, or (at your option) any later version. + * + * This 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 this library. If not, see . + */ + +#ifndef GCAB_ENUMS_H +#define GCAB_ENUMS_H + +#include + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define GCAB_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS + +#endif +/*** END file-tail ***/ diff --git a/libgcab/gcab-file.c b/libgcab/gcab-file.c new file mode 100644 index 0000000..cbf8a22 --- /dev/null +++ b/libgcab/gcab-file.c @@ -0,0 +1,558 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include "gcab-priv.h" +#include "gcab-file.h" + +/** + * SECTION:gcab-file + * @title: GCabFile + * @short_description: A file contained in the Cabinet + * @see_also: #GCabFolder + * @stability: Stable + * @include: libgcab.h + * + * A GCabFile is a handle to a file inside a Cabinet archive. + * It can either be a file that is already within an exisiting + * archive, or a file that reference a file on disk that will be used + * for a new archive creation. In the later case, gcab_file_get_file() + * must return a valid handle. + */ + +struct _GCabFile +{ + GObject parent_instance; + + gchar *extract_name; + GFile *file; + GBytes *bytes; + cfile_t *cfile; +}; + +enum { + PROP_0, + + PROP_NAME, + PROP_FILE, + PROP_BYTES, +}; + +G_DEFINE_TYPE (GCabFile, gcab_file, G_TYPE_OBJECT); + +static void +gcab_file_init (GCabFile *self) +{ +} + +static void +gcab_file_finalize (GObject *object) +{ + GCabFile *self = GCAB_FILE (object); + + if (self->file != NULL) + g_object_unref (self->file); + if (self->bytes != NULL) + g_bytes_unref (self->bytes); + cfile_free (self->cfile); + g_free (self->extract_name); + + G_OBJECT_CLASS (gcab_file_parent_class)->finalize (object); +} + +static void +gcab_file_set_name (GCabFile *self, const gchar *name) +{ + gchar *fname = g_strdup (name); + + g_return_if_fail (self->cfile != NULL); + + /* assuming that on win32 we don't get unix paths */ +#ifndef G_OS_WIN32 + if (fname) { + int i, len = strlen (fname); + for (i = 0; i < len; i++) + if (fname[i] == '/') + fname[i] = '\\'; + } +#endif + + g_free (self->cfile->name); + self->cfile->name = fname; +} + +G_GNUC_INTERNAL void +gcab_file_set_bytes (GCabFile *self, GBytes *bytes) +{ + if (self->bytes != NULL) + g_bytes_unref (self->bytes); + self->bytes = g_bytes_ref (bytes); + + /* this is embedded into the archive */ + self->cfile->usize = g_bytes_get_size (bytes); +} + +static void +gcab_file_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GCAB_IS_FILE (object)); + GCabFile *self = GCAB_FILE (object); + + switch (prop_id) { + case PROP_NAME: + gcab_file_set_name (self, g_value_get_string (value)); + break; + case PROP_FILE: + self->file = g_value_dup_object (value); + break; + case PROP_BYTES: + gcab_file_set_bytes (self, g_value_get_boxed (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gcab_file_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GCAB_IS_FILE (object)); + GCabFile *self = GCAB_FILE(object); + + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, self->cfile->name); + break; + case PROP_FILE: + g_value_set_object (value, self->file); + break; + case PROP_BYTES: + g_value_set_boxed (value, self->bytes); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gcab_file_class_init (GCabFileClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gcab_file_finalize; + object_class->set_property = gcab_file_set_property; + object_class->get_property = gcab_file_get_property; + + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string ("name", "name", "name", NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_FILE, + g_param_spec_object ("file", "file", "file", G_TYPE_FILE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_BYTES, + g_param_spec_boxed ("bytes", "bytes", "bytes", G_TYPE_BYTES, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +/** + * gcab_file_set_date: + * @file: a #GCabFile + * @tv: a #GTimeVal + * + * Sets the file modification date, instead of the value provided by the GFile. + * + * Since: 1.0 + **/ +void +gcab_file_set_date (GCabFile *self, const GTimeVal *tv) +{ + g_autoptr(GDateTime) dt = g_date_time_new_from_timeval_utc (tv); + self->cfile->date = ((g_date_time_get_year (dt) - 1980 ) << 9 ) + + ((g_date_time_get_month (dt)) << 5) + + (g_date_time_get_day_of_month (dt)); + self->cfile->time = ((g_date_time_get_hour (dt)) << 11) + + (g_date_time_get_minute (dt) << 5) + + (g_date_time_get_second (dt) / 2); +} + +G_GNUC_INTERNAL gboolean +gcab_file_update_info (GCabFile *self, GFileInfo *info) +{ + GTimeVal tv; + + g_return_val_if_fail (GCAB_IS_FILE (self), FALSE); + g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE); + + g_file_info_get_modification_time (info, &tv); + if (self->cfile->date == 0) + gcab_file_set_date (self, &tv); + self->cfile->usize = g_file_info_get_size (info); + self->cfile->fattr = GCAB_FILE_ATTRIBUTE_ARCH; + + return TRUE; +} + +G_GNUC_INTERNAL gboolean +gcab_file_set_uoffset (GCabFile *self, guint32 uoffset) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), FALSE); + + self->cfile->uoffset = uoffset; + + return TRUE; +} + +G_GNUC_INTERNAL guint32 +gcab_file_get_uoffset (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), 0); + return self->cfile->uoffset; +} + +G_GNUC_INTERNAL guint32 +gcab_file_get_usize (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), 0); + return self->cfile->usize; +} + +G_GNUC_INTERNAL GFile * +gcab_file_get_gfile (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), NULL); + return self->file; +} + +G_GNUC_INTERNAL void +gcab_file_add_attribute (GCabFile *self, guint32 attribute) +{ + g_return_if_fail (GCAB_IS_FILE (self)); + self->cfile->fattr |= attribute; +} + +G_GNUC_INTERNAL cfile_t * +gcab_file_get_cfile (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), NULL); + return self->cfile; +} + +/** + * gcab_file_get_size: + * @file: a #GCabFile + * + * Get the file size. + * + * Returns: the cabinet file size + * Since: 0.6 + **/ +guint32 +gcab_file_get_size (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), 0); + + return self->cfile->usize; +} + +/** + * gcab_file_get_date: + * @file: a #GCabFile + * @result: a #GTimeVal to return date + * + * Get the file date, in @result. + * + * Since: 0.6 + * + * Returns: %TRUE if @tv was set + **/ +gboolean +gcab_file_get_date (GCabFile *self, GTimeVal *tv) +{ + guint16 date, time; + g_autoptr(GDateTime) dt = NULL; + + g_return_val_if_fail (GCAB_IS_FILE (self), FALSE); + g_return_val_if_fail (tv != NULL, FALSE); + + date = self->cfile->date; + time = self->cfile->time; + dt = g_date_time_new_utc ((date >> 9) + 1980, + (date >> 5) & 0xf, + (date & 0x1f), + (time >> 11), + (time >> 5) & 0x3f, + (time & 0x1f) * 2); + if (dt == NULL) + return FALSE; + return g_date_time_to_timeval (dt, tv); +} + +/** + * gcab_file_get_attributes: + * @file: a #GCabFile + * + * Get the file attributes. + * + * Returns: the cabinet file attributes + * Since: 0.6 + **/ +guint32 +gcab_file_get_attributes (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), 0); + + return self->cfile->fattr; +} + +/** + * gcab_file_set_attributes: + * @file: a #GCabFile + * @attr: the attributes, e.g. %GCAB_FILE_ATTRIBUTE_RDONLY + * + * Set the file attributes. + * + * Since: 1.0 + **/ +void +gcab_file_set_attributes (GCabFile *self, guint32 attr) +{ + g_return_if_fail (GCAB_IS_FILE (self)); + self->cfile->fattr = attr; +} + +/** + * gcab_file_get_name: + * @file: a #GCabFile + * + * Get the file name within the cabinet. + * + * Returns: the cabinet file name + **/ +const gchar * +gcab_file_get_name (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), NULL); + + return self->cfile->name; +} + +/** + * gcab_file_get_file: + * @file: a #GCabFile + * + * If the cabinet is being created, get the #GFile associated with + * @file. This must be an exisiting file that can be read, in order to + * be added to the archive during cabinet creation. + * + * If @file is from an existing cabinet, the fuction will return + * %NULL. + * + * Returns: (transfer none): the associated #GFile or %NULL + **/ +GFile * +gcab_file_get_file (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), NULL); + + return self->file; +} + +/** + * gcab_file_get_bytes: + * @file: a #GCabFile + * + * Get the #GFile associated with @file. This will only be non-%NULL if the + * #GCabFile has been created using gcab_file_new_with_bytes(). + * + * Returns: (transfer none): the associated #GBytes or %NULL + * + * Since: 1.0 + **/ +GBytes * +gcab_file_get_bytes (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), NULL); + return self->bytes; +} + +/** + * gcab_file_new_with_file: + * @name: name of the file within the cabinet + * @file: a #GFile to be added to the cabinet + * + * Create a #GCabFile from a given #GFile, to be added to a + * #GCabCabinet for archive creation. + * + * Returns: a new #GCabFile + **/ +GCabFile * +gcab_file_new_with_file (const gchar *name, GFile *file) +{ + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (G_IS_FILE (file), NULL); + + GCabFile *self = g_object_new (GCAB_TYPE_FILE, + "file", file, + NULL); + self->cfile = g_new0 (cfile_t, 1); + gcab_file_set_name (self, name); + return self; +} + +/** + * gcab_file_new_with_bytes: + * @name: name of the file within the cabinet + * @bytes: a #GBytes to be added to the cabinet + * + * Create a #GCabFile from a given #GBytes. + * + * If this file is to be added to an archive you should also probably use + * gcab_file_set_date() and gcab_file_set_attributes() to set sensible values. + * + * Returns: a new #GCabFile + * + * Since: 1.0 + **/ +GCabFile * +gcab_file_new_with_bytes (const gchar *name, GBytes *bytes) +{ + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (bytes != NULL, NULL); + + GCabFile *self = g_object_new (GCAB_TYPE_FILE, NULL); + self->cfile = g_new0 (cfile_t, 1); + gcab_file_set_bytes (self, bytes); + gcab_file_set_name (self, name); + return self; +} + +G_GNUC_INTERNAL GCabFile * +gcab_file_new_steal_cfile (cfile_t **cfile) +{ + g_return_val_if_fail (cfile != NULL, NULL); + + GCabFile *file = g_object_new (GCAB_TYPE_FILE, NULL); + file->cfile = g_steal_pointer (cfile); + + return file; +} + +G_GNUC_INTERNAL GInputStream * +gcab_file_get_input_stream (GCabFile *self, GCancellable *cancellable, GError **error) +{ + /* backed by a GFile */ + if (self->file != NULL) + return G_INPUT_STREAM (g_file_read (self->file, cancellable, error)); + + /* backed by a GBytes */ + if (self->bytes != NULL) + return g_memory_input_stream_new_from_bytes (self->bytes); + + /* nothing to do */ + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "No GFile for %s", gcab_file_get_name (self)); + return NULL; +} + +G_GNUC_INTERNAL GOutputStream * +gcab_file_get_output_stream (GCabFile *self, + GFile *path_extract, + GCancellable *cancellable, + GError **error) +{ + /* not writing to a GFile */ + if (path_extract == NULL) + return g_memory_output_stream_new_resizable (); + + /* make path have UNIX directory slashes */ + g_autofree gchar *fname = g_strdup (gcab_file_get_extract_name (self)); + g_strdelimit (fname, "\\", '/'); + + /* "Rebase" the file in the given path, to ensure we never escape it */ + g_autoptr(GFile) file = g_file_resolve_relative_path (path_extract, fname); + if (!g_file_has_prefix (file, path_extract)) { + g_autofree gchar *rawpath = g_file_get_path (file); + if (rawpath != NULL) { + char *newpath = rawpath; + while (*newpath != 0 && *newpath == G_DIR_SEPARATOR) { + newpath++; + } + g_autoptr(GFile) newfile = g_file_resolve_relative_path (path_extract, newpath); + g_set_object (&file, newfile); + } + } + + /* create parent directories */ + g_autoptr(GFile) parent = g_file_get_parent (file); + g_autoptr(GError) error_local = NULL; + if (!g_file_make_directory_with_parents (parent, cancellable, &error_local)) { + if (!g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_EXISTS)) { + g_propagate_error (error, g_steal_pointer (&error_local)); + return NULL; + } + } + + /* write to a file */ + return G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_REPLACE_DESTINATION, + cancellable, error)); +} + +/** + * gcab_file_get_extract_name: + * @file: a #GCabFile + * + * Get the file name to use for extraction, or %NULL. + * + * Returns: (allow-none): a file name + **/ +const gchar * +gcab_file_get_extract_name (GCabFile *self) +{ + g_return_val_if_fail (GCAB_IS_FILE (self), NULL); + + return self->extract_name ? self->extract_name : self->cfile->name; +} + +/** + * gcab_file_set_extract_name: + * @file: a #GCabFile + * @name: (allow-none): a file name or %NULL + * + * Sets the file name to use for extraction, instead of the name + * provided by the Cabinet. + **/ +void +gcab_file_set_extract_name (GCabFile *self, const gchar *name) +{ + g_return_if_fail (GCAB_IS_FILE (self)); + + g_free (self->extract_name); + self->extract_name = g_strdup (name); +} diff --git a/libgcab/gcab-file.h b/libgcab/gcab-file.h new file mode 100644 index 0000000..bb03bf0 --- /dev/null +++ b/libgcab/gcab-file.h @@ -0,0 +1,83 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _GCAB_FILE_H_ +#define _GCAB_FILE_H_ + +#include +#include + +G_BEGIN_DECLS + +/** + * GCabFile: + * + * An opaque object, referencing a file in a Cabinet. + **/ +#define GCAB_TYPE_FILE (gcab_file_get_type ()) +G_DECLARE_FINAL_TYPE(GCabFile, gcab_file, GCAB, FILE, GObject) + +/** + * GCabFileAttribute: + * @GCAB_FILE_ATTRIBUTE_RDONLY: file is read-only + * @GCAB_FILE_ATTRIBUTE_HIDDEN: file is hidden + * @GCAB_FILE_ATTRIBUTE_SYSTEM: file is a system file + * @GCAB_FILE_ATTRIBUTE_ARCH: file modified since last backup + * @GCAB_FILE_ATTRIBUTE_EXEC: run after extraction + * @GCAB_FILE_ATTRIBUTE_NAME_IS_UTF: name contains UTF + * + * Attributes associated with the #GCabFile. + **/ +typedef enum +{ + GCAB_FILE_ATTRIBUTE_RDONLY = 0x01, + GCAB_FILE_ATTRIBUTE_HIDDEN = 0x02, + GCAB_FILE_ATTRIBUTE_SYSTEM = 0x04, + GCAB_FILE_ATTRIBUTE_ARCH = 0x20, + GCAB_FILE_ATTRIBUTE_EXEC = 0x40, + GCAB_FILE_ATTRIBUTE_NAME_IS_UTF = 0x80 +} GCabFileAttribute; + +/** + * GCabFileCallback: + * @file: the file being processed + * @user_data: user data passed to the callback. + * + * The type used for callback called when processing Cabinet archive + * files. + **/ +typedef gboolean (*GCabFileCallback) (GCabFile *file, gpointer user_data); + +GCabFile * gcab_file_new_with_file (const gchar *name, GFile *file); +GCabFile * gcab_file_new_with_bytes (const gchar *name, GBytes *bytes); +GFile * gcab_file_get_file (GCabFile *file); +GBytes * gcab_file_get_bytes (GCabFile *file); +const gchar * gcab_file_get_name (GCabFile *file); +guint32 gcab_file_get_size (GCabFile *file); +guint32 gcab_file_get_attributes (GCabFile *file); +gboolean gcab_file_get_date (GCabFile *file, GTimeVal *result); +const gchar * gcab_file_get_extract_name (GCabFile *file); +void gcab_file_set_extract_name (GCabFile *file, const gchar *name); +void gcab_file_set_date (GCabFile *file, const GTimeVal *tv); +void gcab_file_set_attributes (GCabFile *file, guint32 attr); + +G_END_DECLS + +#endif /* _GCAB_FILE_H_ */ diff --git a/libgcab/gcab-folder.c b/libgcab/gcab-folder.c new file mode 100644 index 0000000..1b09fa3 --- /dev/null +++ b/libgcab/gcab-folder.c @@ -0,0 +1,493 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#include "gcab-priv.h" + +/** + * SECTION:gcab-folder + * @title: GCabFolder + * @short_description: A Cabinet folder + * @see_also: #GCabFolder + * @stability: Stable + * @include: libgcab.h + * + * A GCabFolder is a handle to a folder within the Cabinet archive. A + * Cabinet folder is not like a directory. It is + * a sub-container grouping GCabFiles together, sharing some common + * settings like the compression method. + * + * You can retrieve the files within a folder with + * gcab_folder_get_files(). + * + * In order to add a file to a folder for creation, use + * gcab_folder_add_file(). + */ + +struct _GCabFolder +{ + GObject parent_instance; + + GSList *files; + GHashTable *hash; + gint comptype; + GByteArray *reserved; + cfolder_t *cfolder; +}; + +enum { + PROP_0, + + PROP_COMPRESSION, + PROP_COMPTYPE, + PROP_RESERVED +}; + +G_DEFINE_TYPE (GCabFolder, gcab_folder, G_TYPE_OBJECT); + +static void +gcab_folder_init (GCabFolder *self) +{ + self->files = NULL; + self->hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); +} + +static void +gcab_folder_finalize (GObject *object) +{ + GCabFolder *self = GCAB_FOLDER (object); + + cfolder_free (self->cfolder); + g_slist_free_full (self->files, g_object_unref); + g_hash_table_unref (self->hash); + if (self->reserved) + g_byte_array_unref (self->reserved); + + G_OBJECT_CLASS (gcab_folder_parent_class)->finalize (object); +} + +static void +gcab_folder_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GCAB_IS_FOLDER (object)); + GCabFolder *self = GCAB_FOLDER (object); + + switch (prop_id) { + case PROP_COMPTYPE: + self->comptype = g_value_get_int (value); + break; + case PROP_RESERVED: + if (self->reserved) + g_byte_array_unref (self->reserved); + self->reserved = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gcab_folder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + g_return_if_fail (GCAB_IS_FOLDER (object)); + GCabFolder *self = GCAB_FOLDER (object); + + switch (prop_id) { + case PROP_COMPRESSION: + g_value_set_enum (value, self->comptype & GCAB_COMPRESSION_MASK); + break; + case PROP_COMPTYPE: + g_value_set_int (value, self->comptype); + break; + case PROP_RESERVED: + g_value_set_boxed (value, self->reserved); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gcab_folder_class_init (GCabFolderClass *klass) +{ + GObjectClass* object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gcab_folder_finalize; + object_class->set_property = gcab_folder_set_property; + object_class->get_property = gcab_folder_get_property; + + g_object_class_install_property (object_class, PROP_COMPRESSION, + g_param_spec_enum ("compression", "compression", "compression", + GCAB_TYPE_COMPRESSION, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_COMPTYPE, + g_param_spec_int ("comptype", "comptype", "comptype", + 0, G_MAXINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_RESERVED, + g_param_spec_boxed ("reserved", "Reserved", "Reserved", + G_TYPE_BYTE_ARRAY, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + +} + +/* calculate the number of datablocks we will need: + cabinet files are written in blocks of 32768 bytes */ +G_GNUC_INTERNAL gsize +gcab_folder_get_ndatablocks (GCabFolder *self) +{ + gsize total_size = 0; + + for (GSList *l = self->files; l != NULL; l = l->next) { + GCabFile *file = GCAB_FILE (l->data); + total_size += gcab_file_get_usize (file); + } + + return total_size / DATABLOCKSIZE + 1 ; +} + +/** + * gcab_folder_get_comptype: + * @cabfolder: a #GCabFolder + * + * Returns the compression used in this folder. + * + * Returns: a #GCabCompression, e.g. %GCAB_COMPRESSION_MSZIP + * + * Since: 1.0 + **/ +gint +gcab_folder_get_comptype (GCabFolder *self) +{ + return self->comptype; +} + +static gboolean +add_file (GCabFolder *self, GCabFile *file, GError **error) +{ + if (g_hash_table_lookup (self->hash, (gpointer)gcab_file_get_name (file))) { + g_set_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT, + "File '%s' has already been added", gcab_file_get_name (file)); + return FALSE; + } + + g_hash_table_insert (self->hash, + (gpointer)gcab_file_get_name (file), g_object_ref (file)); + self->files = g_slist_prepend (self->files, g_object_ref (file)); + + return TRUE; +} + +#define FILE_ATTRS "standard::*,time::modified" + +static gint +_sort_cfiles (GCabFile *file_a, GCabFile *file_b) +{ + return g_strcmp0 (gcab_file_get_name (file_a), gcab_file_get_name (file_b)); +} + +static gboolean +add_file_info (GCabFolder *self, GCabFile *file, GFileInfo *info, + const gchar *name, gboolean recurse, GError **error) +{ + GFileType file_type = g_file_info_get_file_type (info); + + if (file_type == G_FILE_TYPE_DIRECTORY) { + if (!recurse) + return TRUE; + + g_autoptr(GFileEnumerator) dir = g_file_enumerate_children (gcab_file_get_gfile (file), FILE_ATTRS, 0, NULL, error); + if (dir == NULL) { + g_warning ("Couldn't enumerate directory %s: %s", name, (*error)->message); + g_clear_error (error); + return TRUE; + } + + while ((info = g_file_enumerator_next_file (dir, NULL, error)) != NULL) { + g_autoptr(GFile) child = g_file_get_child (gcab_file_get_gfile (file), g_file_info_get_name (info)); + g_autofree gchar *child_name = g_build_path ("\\", name, g_file_info_get_name (info), NULL); + g_autoptr(GCabFile) child_file = gcab_file_new_with_file (child_name, child); + if (!add_file_info (self, child_file, info, child_name, recurse, error)) { + g_object_unref (info); + return FALSE; + } + + /* sort the files to avoid depending on filesystem order */ + self->files = g_slist_sort (self->files, (GCompareFunc)_sort_cfiles); + + g_object_unref (info); + } + + } else if (file_type == G_FILE_TYPE_REGULAR) { + gcab_file_update_info (file, info); + if (!add_file (self, file, error)) + return FALSE; + + } else { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "Unhandled file type: %u", file_type); + return FALSE; + } + + return TRUE; +} + +/** + * gcab_folder_add_file: + * @cabfolder: a #GCabFolder + * @cabfile: file to be added + * @recurse: whether to recurse through subdirectories + * @cancellable: (allow-none): optional #GCancellable object, + * %NULL to ignore + * @error: (allow-none): #GError to set on error, or %NULL + * + * Add @file to the #GCabFolder. + * + * Returns: %TRUE on succes + **/ +gboolean +gcab_folder_add_file (GCabFolder *self, GCabFile *file, + gboolean recurse, GCancellable *cancellable, + GError **error) +{ + gboolean success; + + g_return_val_if_fail (GCAB_IS_FOLDER (self), FALSE); + g_return_val_if_fail (GCAB_IS_FILE (file), FALSE); + g_return_val_if_fail (!error || *error == NULL, FALSE); + + GFile *gfile = gcab_file_get_file (file); + if (gfile) { + g_return_val_if_fail (G_IS_FILE (gfile), FALSE); + + g_autoptr(GFileInfo) info = g_file_query_info (gfile, FILE_ATTRS, 0, NULL, error); + if (info == NULL) + return FALSE; + + success = add_file_info (self, file, info, + gcab_file_get_name (file), recurse, error); + } else { + success = add_file (self, file, error); + } + + return success; +} + +/** + * gcab_folder_get_nfiles: + * @cabfolder: a #GCabFolder + * + * Get the number of files in this @folder. + * + * Returns: a #guint + **/ +guint +gcab_folder_get_nfiles (GCabFolder *self) +{ + g_return_val_if_fail (GCAB_IS_FOLDER (self), 0); + + return g_hash_table_size (self->hash); +} + +/** + * gcab_folder_new: + * @comptype: compression to used in this folder + * + * Creates a new empty Cabinet folder. Use gcab_folder_add_file() to + * add files to an archive. + * + * A Cabinet folder is not a file path, it is a container for files. + * + * Returns: a new #GCabFolder + **/ +GCabFolder * +gcab_folder_new (gint comptype) +{ + return g_object_new (GCAB_TYPE_FOLDER, + "comptype", comptype, + NULL); +} + +G_GNUC_INTERNAL GCabFolder * +gcab_folder_new_steal_cfolder (cfolder_t **cfolder) +{ + g_return_val_if_fail (cfolder != NULL, NULL); + + GCabFolder *self = g_object_new (GCAB_TYPE_FOLDER, + "comptype", (*cfolder)->typecomp, + NULL); + self->cfolder = g_steal_pointer (cfolder); + + return self; +} + +/** + * gcab_folder_get_files: + * @cabfolder: a #GCabFolder + * + * Get the list of #GCabFile files contained in the @cabfolder. + * + * Returns: (element-type GCabFile) (transfer container): list of files + **/ +GSList * +gcab_folder_get_files (GCabFolder *self) +{ + g_return_val_if_fail (GCAB_IS_FOLDER (self), 0); + + return g_slist_reverse (g_slist_copy (self->files)); +} + +/** + * gcab_folder_get_file_by_name: + * @cabfolder: a #GCabFolder + * @name: a file name + * + * Gets a specific #GCabFile files contained in the @cabfolder. + * + * Returns: (transfer none): A #GCabFile, or %NULL if not found + **/ +GCabFile * +gcab_folder_get_file_by_name (GCabFolder *self, const gchar *name) +{ + GCabFile *cabfile; + + g_return_val_if_fail (GCAB_IS_FOLDER (self), NULL); + g_return_val_if_fail (name != NULL, NULL); + + /* try the hash first */ + cabfile = g_hash_table_lookup (self->hash, name); + if (cabfile != NULL) + return cabfile; + + /* if the extract name is different, look for that too */ + for (GSList *l = self->files; l != NULL; l = l->next) { + cabfile = GCAB_FILE (l->data); + if (gcab_file_get_name (cabfile) != gcab_file_get_extract_name (cabfile)) { + if (g_strcmp0 (gcab_file_get_extract_name (cabfile), name) == 0) + return cabfile; + } + } + + /* nothing found */ + return NULL; +} + +static gint +sort_by_offset (GCabFile *a, GCabFile *b) +{ + g_return_val_if_fail (a != NULL, 0); + g_return_val_if_fail (b != NULL, 0); + + return (gint64) gcab_file_get_uoffset (a) - (gint64) gcab_file_get_uoffset (b); +} + +G_GNUC_INTERNAL gboolean +gcab_folder_extract (GCabFolder *self, + GDataInputStream *data, + GFile *path_extract, + guint8 res_data, + GCabFileCallback file_callback, + GFileProgressCallback progress_callback, + gpointer callback_data, + GCancellable *cancellable, + GError **error) +{ + GSList *f = NULL; + g_autoptr(GSList) files = NULL; + g_autoptr(cdata_t) cdata = g_new0 (cdata_t, 1); + guint32 nubytes = 0; + + /* never loaded from a stream */ + g_assert (self->cfolder != NULL); + + if (!g_seekable_seek (G_SEEKABLE (data), self->cfolder->offsetdata, G_SEEK_SET, cancellable, error)) + return FALSE; + + files = g_slist_sort (g_slist_copy (self->files), (GCompareFunc)sort_by_offset); + + /* this is allocated for every block, but currently unused */ + cdata->reserved = g_malloc (res_data); + + for (f = files; f != NULL; f = f->next) { + GCabFile *file = f->data; + + if (file_callback && !file_callback (file, callback_data)) + continue; + + g_autoptr(GOutputStream) out = NULL; + out = gcab_file_get_output_stream (file, path_extract, cancellable, error); + if (out == NULL) + return FALSE; + + guint32 usize = gcab_file_get_usize (file); + guint32 uoffset = gcab_file_get_uoffset (file); + + /* let's rewind if need be */ + if (uoffset < nubytes) { + if (!g_seekable_seek (G_SEEKABLE (data), self->cfolder->offsetdata, + G_SEEK_SET, cancellable, error)) + return FALSE; + nubytes = 0; + } + + while (usize > 0) { + if ((nubytes + cdata->nubytes) <= uoffset) { + nubytes += cdata->nubytes; + if (!cdata_read (cdata, res_data, self->comptype, + data, cancellable, error)) + return FALSE; + continue; + } else { + gsize offset = gcab_file_get_uoffset (file) > nubytes ? + gcab_file_get_uoffset (file) - nubytes : 0; + const void *p = &cdata->out[offset]; + gsize count = MIN (usize, cdata->nubytes - offset); + if (!g_output_stream_write_all (G_OUTPUT_STREAM (out), p, count, + NULL, cancellable, error)) + return FALSE; + usize -= count; + uoffset += count; + } + } + + if (!g_output_stream_close (out, cancellable, error)) + return FALSE; + + /* no backing GFile */ + if (path_extract == NULL) { + g_autoptr(GBytes) blob = NULL; + blob = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out)); + gcab_file_set_bytes (file, blob); + } + + } + + return TRUE; +} diff --git a/libgcab/gcab-folder.h b/libgcab/gcab-folder.h new file mode 100644 index 0000000..e4f7168 --- /dev/null +++ b/libgcab/gcab-folder.h @@ -0,0 +1,72 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _GCAB_FOLDER_H_ +#define _GCAB_FOLDER_H_ + +#include +#include +#include "gcab-file.h" + +G_BEGIN_DECLS + +/** + * GCabFolder: + * + * An opaque object, referencing a folder in a Cabinet. + **/ +#define GCAB_TYPE_FOLDER (gcab_folder_get_type ()) +G_DECLARE_FINAL_TYPE(GCabFolder, gcab_folder, GCAB, FOLDER, GObject) + +/** + * GCabCompression: + * @GCAB_COMPRESSION_NONE: No compression. + * @GCAB_COMPRESSION_MSZIP: MSZIP compression. + * @GCAB_COMPRESSION_QUANTUM: QUANTUM compression (unsupported). + * @GCAB_COMPRESSION_LZX: LZX compression (only decompression supported). + * @GCAB_COMPRESSION_MASK: compression value mask. + * + * Compression used by the #GCabFolder. + **/ +typedef enum +{ + GCAB_COMPRESSION_NONE = 0, + GCAB_COMPRESSION_MSZIP = 1, + GCAB_COMPRESSION_QUANTUM = 2, + GCAB_COMPRESSION_LZX = 3, + + GCAB_COMPRESSION_MASK = 0xf, +} GCabCompression; + +GCabFolder * gcab_folder_new (gint comptype); +gboolean gcab_folder_add_file (GCabFolder *cabfolder, + GCabFile *cabfile, + gboolean recurse, + GCancellable *cancellable, + GError **error); +guint gcab_folder_get_nfiles (GCabFolder *cabfolder); +GSList * gcab_folder_get_files (GCabFolder *cabfolder); +GCabFile * gcab_folder_get_file_by_name (GCabFolder *cabfolder, + const gchar *name); +gint gcab_folder_get_comptype (GCabFolder *cabfolder); + +G_END_DECLS + +#endif /* _GCAB_FILE_H_ */ diff --git a/libgcab/gcab-priv.h b/libgcab/gcab-priv.h new file mode 100644 index 0000000..a3894e8 --- /dev/null +++ b/libgcab/gcab-priv.h @@ -0,0 +1,73 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef GCAB_PRIV_H +#define GCAB_PRIV_H + +#include "config.h" + +#include + +#include "cabinet.h" +#include "gcab-file.h" +#include "gcab-folder.h" +#include "gcab-cabinet.h" +#include "gcab-enums.h" + +/* Copied from GStream, FIXME that should be in GLib imho */ +#define _GCAB_GET(__data, __idx, __size, __shift) \ + (((guint##__size) (((const guint8 *) (__data))[__idx])) << (__shift)) + +#define GCAB_READ_UINT32_LE(data) (_GCAB_GET (data, 3, 32, 24) | \ + _GCAB_GET (data, 2, 32, 16) | \ + _GCAB_GET (data, 1, 32, 8) | \ + _GCAB_GET (data, 0, 32, 0)) + +GCabFolder * gcab_folder_new_steal_cfolder (cfolder_t **cfolder); +GCabFile * gcab_file_new_steal_cfile (cfile_t **cfile); + +gboolean gcab_file_update_info (GCabFile *file, GFileInfo *info); +guint32 gcab_file_get_uoffset (GCabFile *file); +gboolean gcab_file_set_uoffset (GCabFile *file, guint32 uoffset); +guint32 gcab_file_get_usize (GCabFile *file); +GFile *gcab_file_get_gfile (GCabFile *file); +cfile_t *gcab_file_get_cfile (GCabFile *file); +void gcab_file_add_attribute (GCabFile *file, guint32 attribute); +void gcab_file_set_bytes (GCabFile *file, GBytes *bytes); + +gsize gcab_folder_get_ndatablocks (GCabFolder *folder); +gboolean gcab_folder_extract (GCabFolder *self, + GDataInputStream *data, + GFile *path, + guint8 res_data, + GCabFileCallback file_callback, + GFileProgressCallback progress_callback, + gpointer callback_data, + GCancellable *cancellable, + GError **error); +GInputStream *gcab_file_get_input_stream (GCabFile *file, + GCancellable *cancellable, + GError **error); +GOutputStream *gcab_file_get_output_stream (GCabFile *cabfile, + GFile *path_extract, + GCancellable *cancellable, + GError **error); + +#endif /* GCAB_PRIV_H */ diff --git a/libgcab/libgcab.h b/libgcab/libgcab.h new file mode 100644 index 0000000..58b6147 --- /dev/null +++ b/libgcab/libgcab.h @@ -0,0 +1,27 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +#ifndef _LIBGCAB_H_ +#define _LIBGCAB_H_ + +#include +#include +#include + +#endif /* _LIBGCAB_H_ */ diff --git a/libgcab/libgcab.syms b/libgcab/libgcab.syms new file mode 100644 index 0000000..c0ad194 --- /dev/null +++ b/libgcab/libgcab.syms @@ -0,0 +1,53 @@ +LIBGCAB1_0.0 { + global: + gcab_cabinet_add_folder; + gcab_cabinet_get_folders; + gcab_cabinet_get_type; + gcab_cabinet_load; + gcab_cabinet_new; + gcab_cabinet_write; + gcab_compression_get_type; + gcab_error_quark; + gcab_file_get_file; + gcab_file_get_name; + gcab_file_get_type; + gcab_file_new_with_file; + gcab_folder_add_file; + gcab_folder_get_files; + gcab_folder_get_nfiles; + gcab_folder_get_type; + gcab_folder_new; + local: + *; +}; + +LIBGCAB1_0.2 { + gcab_cabinet_write_simple; + + gcab_cabinet_extract; + gcab_cabinet_extract_simple; + + gcab_file_get_extract_name; + gcab_file_set_extract_name; +} LIBGCAB1_0.0; + +LIBGCAB1_0.5 { + gcab_cabinet_get_signature; +} LIBGCAB1_0.2; + +LIBGCAB1_0.6 { + gcab_file_attribute_get_type; + gcab_file_get_attributes; + gcab_file_get_date; + gcab_file_get_size; +} LIBGCAB1_0.5; + +LIBGCAB1_1.0 { + gcab_cabinet_get_size; + gcab_file_get_bytes; + gcab_file_new_with_bytes; + gcab_file_set_attributes; + gcab_file_set_date; + gcab_folder_get_comptype; + gcab_folder_get_file_by_name; +} LIBGCAB1_0.6; diff --git a/libgcab/meson.build b/libgcab/meson.build new file mode 100644 index 0000000..6ff8801 --- /dev/null +++ b/libgcab/meson.build @@ -0,0 +1,101 @@ +cargs = [ + '-DG_LOG_DOMAIN="gcab"', +] + +enum_headers = ['gcab-folder.h', 'gcab-file.h'] +enums = gnome.mkenums( + 'gcab-enums', + sources : enum_headers, + c_template : 'gcab-enums.c.etemplate', + h_template : 'gcab-enums.h.etemplate', + install_header : true, + install_dir : 'include/libgcab-1.0/libgcab', + symbol_prefix : 'gcab', + identifier_prefix : 'GCab', +) + +install_headers( + 'libgcab.h', + subdir : 'libgcab-1.0', +) + +install_headers([ + 'gcab-cabinet.h', + 'gcab-file.h', + 'gcab-folder.h', + ], + subdir : 'libgcab-1.0/libgcab', +) + +mapfile = 'libgcab.syms' +vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) +libgcab = shared_library( + 'gcab-1.0', + enums, + sources : [ + 'gcab-cabinet.c', + 'gcab-folder.c', + 'gcab-file.c', + 'cabinet.c', + 'decomp.c', + ], + soversion : lt_current, + version : lt_version, + dependencies : [ + gio, + libz, + ], + c_args : cargs, + include_directories : [ + include_directories('.'), + include_directories('..'), + ], + link_args : vflag, + link_depends : mapfile, + install : true +) + +pkgg = import('pkgconfig') +pkgg.generate( + libraries : libgcab, + requires : [ 'gio-2.0' ], + subdirs : 'libgcab-1.0', + version : meson.project_version(), + name : 'libgcab', + filebase : 'libgcab-1.0', + description : 'Cabinet file library', +) + +if get_option('introspection') + gir = gnome.generate_gir(libgcab, + sources : [ + enums, + 'gcab-cabinet.c', + 'gcab-cabinet.h', + 'gcab-folder.c', + 'gcab-folder.h', + 'gcab-file.c', + 'gcab-file.h', + ], + nsversion : '1.0', + namespace : 'GCab', + symbol_prefix : 'gcab', + header : 'libgcab.h', + identifier_prefix : 'GCab', + export_packages : 'libgcab-1.0', + dependencies : [ + gio, + ], + includes : [ + 'GLib-2.0', + 'Gio-2.0', + 'GObject-2.0', + ], + install : true + ) + gnome.generate_vapi('libgcab-1.0', + sources: gir[0], + packages : ['gio-2.0'], + install : true, + ) +endif diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..1a29b5a --- /dev/null +++ b/meson.build @@ -0,0 +1,122 @@ +project('gcab', 'c', + version : '1.1', + license : 'LGPL-2.1+', + meson_version : '>=0.37.0', + default_options : ['warning_level=2', 'c_std=c99'], +) + +git_version = run_command(['git', 'describe', '--abbrev=4', 'HEAD']).stdout().strip().split('-') + +# libtool versioning +lt_current = '0' +lt_revision = '0' +lt_age = '0' +lt_version = '@0@.@1@.@2@'.format(lt_current, lt_age, lt_revision) + +# get suported warning flags +test_args = [ + '-fstack-protector-strong', + '-Waggregate-return', + '-Wunused', + '-Warray-bounds', + '-Wcast-align', + '-Wclobbered', + '-Wduplicated-branches', + '-Wduplicated-cond', + '-Wempty-body', + '-Wformat=2', + '-Wformat-nonliteral', + '-Wformat-security', + '-Wformat-signedness', + '-Wignored-qualifiers', + '-Wimplicit-function-declaration', + '-Winit-self', + '-Wlogical-op', + '-Wmissing-declarations', + '-Wmissing-format-attribute', + '-Wmissing-include-dirs', + '-Wmissing-noreturn', + '-Wmissing-parameter-type', + '-Wmissing-prototypes', + '-Wnested-externs', + '-Wno-discarded-qualifiers', + '-Wno-missing-field-initializers', + '-Wno-strict-aliasing', + '-Wno-suggest-attribute=format', + '-Wno-unused-parameter', + '-Wnull-dereference', + '-Wold-style-definition', + '-Woverride-init', + '-Wpointer-arith', + '-Wredundant-decls', + '-Wreturn-type', + '-Wshadow', + '-Wsign-compare', + '-Wstrict-aliasing', + '-Wstrict-prototypes', + '-Wswitch-default', + '-Wtype-limits', + '-Wundef', + '-Wuninitialized', + '-Wunused-but-set-variable', + '-Wunused-variable', + '-Wwrite-strings' +] +cc = meson.get_compiler('c') +foreach arg: test_args + if cc.has_argument(arg) + add_project_arguments(arg, language : 'c') + endif +endforeach + +# enable full RELRO where possible +# FIXME: until https://github.com/mesonbuild/meson/issues/1140 is fixed +global_link_args = [] +test_link_args = [ + '-Wl,-z,relro', + '-Wl,-z,now', +] +foreach arg: test_link_args + if cc.has_argument(arg) + global_link_args += arg + endif +endforeach +add_global_link_arguments( + global_link_args, + language: 'c' +) + +gio = dependency('gio-2.0', version : '>= 2.44.0') +libz = dependency('zlib') + +gnome = import('gnome') +i18n = import('i18n') + +conf = configuration_data() +conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) +conf.set_quoted('PACKAGE_NAME', meson.project_name()) +if git_version.length() == 3 + conf.set_quoted('PACKAGE_STRING', '@0@ @1@.@2@-@3@'.format(meson.project_name(), git_version[0], git_version[1], git_version[2])) +else + conf.set_quoted('PACKAGE_STRING', '@0@ v@1@'.format(meson.project_name(), meson.project_version())) +endif + +conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) +conf.set_quoted('PACKAGE_BUGREPORT', 'https://bugzilla.gnome.org/enter_bug.cgi?product=msitools&component=gcab') +conf.set_quoted('TESTDATADIR', join_paths(meson.source_root(), 'tests')) +configure_file( + output : 'config.h', + configuration : conf +) + +subdir('libgcab') +subdir('po') +subdir('src') + +if get_option('docs') +subdir('docs') +endif + +if get_option('tests') +subdir('tests') +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..bbcbbea --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,3 @@ +option('docs', type : 'boolean', value : true, description : 'enable developer documentation') +option('introspection', type : 'boolean', value : true, description : 'generate GObject Introspection data') +option('tests', type : 'boolean', value : true, description : 'enable tests') diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..ec70494 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,29 @@ +# keep this list sorted +bs +cs +da +de +el +es +eu +fi +fr +fur +gl +hu +id +lt +lv +nb +oc +pl +pt +pt_BR +ru +sl +sr +sr@latin +sv +tg +tr +zh_CN diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..76d7cce --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,5 @@ +libgcab/cabinet.c +libgcab/gcab-cabinet.c +libgcab/gcab-file.c +libgcab/gcab-folder.c +src/gcab.c diff --git a/po/bs.po b/po/bs.po new file mode 100644 index 0000000..d9c1ee2 --- /dev/null +++ b/po/bs.po @@ -0,0 +1,167 @@ +# Bosnian translation for bosnianuniversetranslation +# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013 +# This file is distributed under the same license as the bosnianuniversetranslation package. +# FIRST AUTHOR , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: bosnianuniversetranslation\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-02-27 05:46+0000\n" +"PO-Revision-Date: 2015-02-05 00:28+0000\n" +"Last-Translator: Aida Granulo \n" +"Language-Team: Bosnian \n" +"Language: bs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2015-02-05 07:03+0000\n" +"X-Generator: Launchpad (build 17331)\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Uklanjanje vodećeg '%s' iz imena članova" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Istresanje %s podataka u: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "ne mogu napisati datoteku %s: %s" + +#: ../gcab.c:108 +msgid "Print program version" +msgstr "Odštampaj verziju programa" + +#: ../gcab.c:109 +msgid "Be verbose" +msgstr "Opširniji ispis" + +#: ../gcab.c:110 +msgid "Create archive" +msgstr "Kreairaj arhivu" + +#: ../gcab.c:111 +msgid "Extract all files" +msgstr "Raspakuj sve datoteke" + +#: ../gcab.c:112 +msgid "Dump reserved and extra data" +msgstr "Istresi rezervirane i dodatne podatke" + +#: ../gcab.c:113 +msgid "List content" +msgstr "Lista sadržaja" + +#: ../gcab.c:114 +msgid "Change to directory DIR" +msgstr "Promjeni na direktorij DIR" + +#: ../gcab.c:114 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:115 +msgid "Use zip compression" +msgstr "Koristite zip kompresiju" + +#: ../gcab.c:116 +msgid "Do not include path" +msgstr "Ne uključuj putanju" + +#: ../gcab.c:117 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Rezerviraj prostor u kabinetu za prijavu(e.g. -s1644 rezerbira 6k bajta)" + +#: ../gcab.c:118 +msgid "FILE INPUT_FILES..." +msgstr "DATOTEKA ULAZNE_DATOTEKE..." + +#: ../gcab.c:132 +msgid "- create a Cabinet file" +msgstr "- Stvori Kabinet datoteku" + +#: ../gcab.c:133 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Prijavi bugova na <%s>" + +#: ../gcab.c:136 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab štedi snima mnogo datoteka zajedno u arhivi kabineta, a može vratiti\n" +"pojedinačne datoteke iz arhive." + +#: ../gcab.c:143 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "analiziranje opcija neuspjelo: %s\n" + +#: ../gcab.c:152 +msgid "Please specify a single operation." +msgstr "Navedite jednu operaciju." + +#: ../gcab.c:155 +msgid "cabinet file must be specified." +msgstr "kabinet datoteka mora biti navedena." + +#: ../gcab.c:169 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "ne mogu otvoriti %s za čitanje: %s\n" + +#: ../gcab.c:171 +#, c-format +msgid "error reading %s: %s\n" +msgstr "pogreška čitanja %s: %s\n" + +#: ../gcab.c:188 +#, c-format +msgid "error during extraction: %s" +msgstr "pogreška tijekom ekstrakcije: %s" + +#: ../gcab.c:200 +#, c-format +msgid "error while reading signature: %s" +msgstr "pogreška prilikom čitanja potpisa: %s" + +#: ../gcab.c:211 +msgid "please specify input files." +msgstr "molimo navedite ulazne datoteke." + +#: ../gcab.c:229 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Nemoguće dodati datoteke %s :%s" + +#: ../gcab.c:239 +msgid "no files to be archived." +msgstr "nema datoteka da budu arhiviranje." + +#: ../gcab.c:245 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "nemoguće kreirati cab datoteku %s: %s" + +#: ../gcab.c:249 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "nemoguće dodati direktorij za cab datoteku %s: %s" + +#: ../gcab.c:257 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "nemoguće pisati cab datoteku %s : %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:453 +#, c-format +msgid "unsupported compression method %d" +msgstr "nepodržana metoda kompresije %d" diff --git a/po/cs.po b/po/cs.po new file mode 100644 index 0000000..f3a27e1 --- /dev/null +++ b/po/cs.po @@ -0,0 +1,146 @@ +# Czech translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Marek Černocký , 2013, 2015, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2018-01-23 13:50+0000\n" +"PO-Revision-Date: 2018-01-25 21:32+0100\n" +"Last-Translator: Marek Černocký \n" +"Language-Team: čeština \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Gtranslator 2.91.7\n" + +#: ../src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Vypisují se data do:" + +#: ../src/gcab.c:114 +msgid "Print program version" +msgstr "Vypsat verzi programu" + +#: ../src/gcab.c:115 +msgid "Be verbose" +msgstr "Podrobnosti" + +#: ../src/gcab.c:116 +msgid "Create archive" +msgstr "Vytvořit archiv" + +#: ../src/gcab.c:117 +msgid "Extract all files" +msgstr "Rozbalit všechny soubory" + +#: ../src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Vypsat rezervovaná a doplňková data" + +#: ../src/gcab.c:119 +msgid "List content" +msgstr "Vypsat obsah" + +#: ../src/gcab.c:120 +msgid "List content with file details" +msgstr "Vypsat obsah s podrobnostmi o souborech" + +#: ../src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Změnit složku na SLOŽKA" + +#: ../src/gcab.c:121 +msgid "DIR" +msgstr "SLOŽKA" + +#: ../src/gcab.c:122 +msgid "Use zip compression" +msgstr "Použít komprimaci zip" + +#: ../src/gcab.c:123 +msgid "Do not include path" +msgstr "Nezahrnovat cestu" + +#: ../src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Rezervovat v souboru CAB místo pro podpis (např. -s 6144 rezervuje 6 " +"kilobajtů)" + +#: ../src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "SOUBOR VSTUPNÍ_SOUBORY…" + +#: ../src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "– vytvořit soubor CAB" + +#: ../src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Chyby hlaste na:" + +#: ../src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab ukládá více souborů dohromady do archivu CAB a jednotlivé soubory\n" +"umí z takového archivu obnovit." + +#: ../src/gcab.c:149 +msgid "Option parsing failed" +msgstr "Selhalo zpracování voleb" + +#: ../src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Určete prosím jednu z operací" + +#: ../src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Soubor CAB musí být zadán" + +#: ../src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Nezdařilo se otevřít soubor pro čtení" + +#: ../src/gcab.c:184 +msgid "Error reading" +msgstr "Chyba čtení" + +#: ../src/gcab.c:220 +msgid "Error during extraction" +msgstr "Chyba během rozbalování" + +#: ../src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Chyba při čtení podpisu" + +#: ../src/gcab.c:247 +msgid "No input files specified" +msgstr "Nebyl určen žádný vstupní soubor" + +#: ../src/gcab.c:266 +msgid "Cannot add file" +msgstr "Nezdařilo se přidat soubor" + +#: ../src/gcab.c:272 +msgid "No files to be archived" +msgstr "Nejsou žádné soubory k archivaci" + +#: ../src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Nezdařilo se vytvořit soubor CAB" + +#: ../src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Nezdařilo se přidat složku do souboru CAB" + +#: ../src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Nezdařilo se zapsat soubor CAB" diff --git a/po/da.po b/po/da.po new file mode 100644 index 0000000..8f3fbe4 --- /dev/null +++ b/po/da.po @@ -0,0 +1,175 @@ +# Danish translation for gcab. +# Copyright (C) 2017 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# joehansen , 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2017-02-22 19:27+0000\n" +"PO-Revision-Date: 2017-02-22 19:10+0100\n" +"Last-Translator: Joe Hansen \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Fjerner foranstillet “%s” fra elementnavne" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Dumper %s-data til: %s …\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "kan ikke skrive filen %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Vis programversion" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Vær uddybende" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Opret arkiv" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Udtræk alle filer" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Dump reserverede og ekstra data" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Vis indhold" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Vis indhold med fildetaljer" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Ændr til mappen MAPPE" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "MAPPE" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Brug zip-komprimering" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Inkluder ikke sti" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Reserver plads i cabinet for underskrivning (f.eks. -s 6144 reserverer 6K " +"byte)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "FIL INDDATA_FILER …" + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- opret en Cabinetfil" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Rapporter fejl til <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab gemmer mange filer sammen i et cabinet-arkiv, og kan gendanne\n" +"individuelle filer fra arkivet." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "tilvalgsfortolkning mislykkedes: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Angiv venligst en enkelt operation." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "cabinetfil skal angives." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "kan ikke åbne %s for læsning: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "der opstod en fejl under læsning af %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "der opstod en fejl under udtrækning: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "der opstod en fejl under læsning af signatur: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "angiv venligst inddatafiler." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Kan ikke tilføje filen %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "der er ingen filer at arkivere." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "kan ikke oprette cab-filen %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "kan ikke tilføje mappe til cab-filen %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "kan ikke skrive cab-filen %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "komprimeringsmetoden %d understøttes ikke" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "en fejlagtig kontrolsum blev detekteret" diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..d78dd04 --- /dev/null +++ b/po/de.po @@ -0,0 +1,147 @@ +# German translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Christian Kirbach , 2013. +# Mario Blättermann , 2013, 2015, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2017-12-14 22:08+0000\n" +"PO-Revision-Date: 2018-01-01 20:14+0100\n" +"Last-Translator: Mario Blättermann \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.0.5\n" + +#: ../src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Daten werden abgelegt nach:" + +#: ../src/gcab.c:114 +msgid "Print program version" +msgstr "Programmversion ausgeben" + +#: ../src/gcab.c:115 +msgid "Be verbose" +msgstr "Ausführliche Meldungen" + +#: ../src/gcab.c:116 +msgid "Create archive" +msgstr "Archiv anlegen" + +#: ../src/gcab.c:117 +msgid "Extract all files" +msgstr "Alle Dateien auspacken" + +#: ../src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Reservierte und zusätzliche Daten ablegen" + +#: ../src/gcab.c:119 +msgid "List content" +msgstr "Inhalt auflisten" + +#: ../src/gcab.c:120 +msgid "List content with file details" +msgstr "Inhalt mit Details zu Dateien auflisten" + +#: ../src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "In Ordner ORDNER wechseln" + +#: ../src/gcab.c:121 +msgid "DIR" +msgstr "ORDNER" + +#: ../src/gcab.c:122 +msgid "Use zip compression" +msgstr "zip-Komprimierung verwenden" + +#: ../src/gcab.c:123 +msgid "Do not include path" +msgstr "Pfad nicht mit einschließen" + +#: ../src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Speicherplatz im Cabinet zum Signieren reservieren (z.B. -s 6144 reserviert " +"6 kbyte)" + +#: ../src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "DATEI EINGABE_DATEIEN …" + +#: ../src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "– Eine Cabinet-Datei erstellen" + +#: ../src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Bitte melden Sie Fehler an:" + +#: ../src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab speichert mehrere Dateien gemeinsam in ein Cabinet-Archiv und\n" +"kann einzelne Dateien aus dem Archiv auslesen." + +#: ../src/gcab.c:149 +msgid "Option parsing failed" +msgstr "Verarbeiten der Optionen schlug fehl" + +#: ../src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Bitte geben Sie eine einzige Operation an" + +#: ../src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "cabinet-Datei muss angegeben werden" + +#: ../src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Datei kann nicht zum Lesen geöffnet werden" + +#: ../src/gcab.c:184 +msgid "Error reading" +msgstr "Fehler beim Lesen" + +#: ../src/gcab.c:220 +msgid "Error during extraction" +msgstr "Fehler während des Auspackens" + +#: ../src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Fehler beim Lesen der Signatur" + +#: ../src/gcab.c:247 +msgid "No input files specified" +msgstr "Keine Eingabedateien angegeben" + +#: ../src/gcab.c:266 +msgid "Cannot add file" +msgstr "Datei kann nicht hinzugefügt werden" + +#: ../src/gcab.c:272 +msgid "No files to be archived" +msgstr "Es sind keine Dateien zu archivieren" + +#: ../src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "cab-Datei kann nicht erstellt werden" + +#: ../src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Ordner kann nicht zur Cabinet-Datei hinzugefügt werden" + +#: ../src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "cab-Datei kann nicht geschrieben werden" diff --git a/po/el.po b/po/el.po new file mode 100644 index 0000000..f5c3695 --- /dev/null +++ b/po/el.po @@ -0,0 +1,177 @@ +# Greek translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Dimitris Spingos , 2013. +# Dimitris Spingos (Δημήτρης Σπίγγος) , 2013, 2014. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-08-25 20:08+0000\n" +"PO-Revision-Date: 2015-08-28 23:05+0300\n" +"Last-Translator: Tom Tryfonidis \n" +"Language-Team: team@gnome.gr\n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 1.8.4\n" +"X-Project-Style: gnome\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Αφαίρεση αρχικού '%s' από ονόματα μέλους" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Αποτύπωση δεδομένων %s σε %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "αδύνατη η εγγραφή στο αρχείο %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Εμφάνιση έκδοσης προγράμματος" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Αναλυτικά" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Δημιουργία αρχειοθήκης" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Εξαγωγή όλων των αρχείων" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Αποτύπωση δεσμευμένων και πρόσθετων δεδομένων" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Περιεχόμενο λίστας" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Προβολή περιεχομένου με λεπτομέρειες του αρχείου" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Αλλαγή στον κατάλογο DIR" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Χρήση συμπίεσης zip" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Να μην περιληφθεί η διαδρομή" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Δέσμευση χώρου σε cabinet για υπογραφή (π.χ. -s 6144 δεσμεύει 6Κ bytes)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "FILE INPUT_FILES..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- δημιουργία αρχείου Cabinet" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Αναφορά σφαλμάτων σε <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"Το gcab αποθηκεύει πολλά αρχεία μαζί σε μια αρχειοθήκη cabinet και μπορεί να " +"επαναφέρει\n" +"μεμονωμένα αρχεία από την αρχειοθήκη." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "αποτυχία ανάλυσης επιλογής: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Παρακαλούμε ορίστε μία μόνο λειτουργία." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "πρέπει να καθοριστεί το αρχείο cabinet." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "αδυναμία ανοίγματος του %s για ανάγνωση: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "σφάλμα ανάγνωσης του %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "σφάλμα κατά την εξαγωγή: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "σφάλμα κατά την ανάγνωση της υπογραφής: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "παρακαλούμε ορίστε αρχεία εισόδου." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Αδύνατη η προσθήκη αρχείου %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "δεν υπάρχουν αρχεία για αρχειοθέτηση." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "αδύνατη η δημιουργία αρχείου cab %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "αδύνατη η προσθήκη φακέλου στο αρχείο cab %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "αδύνατη η εγγραφή αρχείου cab %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "ανυποστήρικτη μέθοδος συμπίεσης %d" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "εντοπίστηκε εσφαλμένο άθροισμα ελέγχου" diff --git a/po/es.po b/po/es.po new file mode 100644 index 0000000..8925ea0 --- /dev/null +++ b/po/es.po @@ -0,0 +1,178 @@ +# Spanish translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# FIRST AUTHOR , YEAR. +# Daniel Mustieles , 2013, 2015, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2018-01-23 13:50+0000\n" +"PO-Revision-Date: 2018-01-24 16:57+0100\n" +"Last-Translator: Daniel Mustieles \n" +"Language-Team: es \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Gtranslator 2.91.6\n" + +#: ../src/gcab.c:82 +#| msgid "Dumping %s data to: %s ...\n" +msgid "Dumping data to:" +msgstr "Volcando datos a:" + +#: ../src/gcab.c:114 +msgid "Print program version" +msgstr "Mostrar la versión del programa" + +#: ../src/gcab.c:115 +msgid "Be verbose" +msgstr "Mostrar detalles" + +#: ../src/gcab.c:116 +msgid "Create archive" +msgstr "Crear archivador" + +#: ../src/gcab.c:117 +msgid "Extract all files" +msgstr "Extraer todos los archivos" + +#: ../src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Volcar datos reservados y adicionales" + +#: ../src/gcab.c:119 +msgid "List content" +msgstr "Listar contenido" + +#: ../src/gcab.c:120 +msgid "List content with file details" +msgstr "Listar el contenido con detalles de los archivos" + +#: ../src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Cambiar a la carpeta CARPETA" + +#: ../src/gcab.c:121 +msgid "DIR" +msgstr "CARPETA" + +#: ../src/gcab.c:122 +msgid "Use zip compression" +msgstr "Usar compresión ZIP" + +#: ../src/gcab.c:123 +msgid "Do not include path" +msgstr "No incluir la ruta" + +#: ../src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Reservar espacio en el archivo cabinet para la firma (ej. -s 6144 reserva 6K " +"bytes)" + +#: ../src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "ARCHIVO ARCHIVOS_DE_ENTRADA…" + +#: ../src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- crear un archivo Cabinet" + +#: ../src/gcab.c:140 +#| msgid "Report bugs to <%s>" +msgid "Report bugs to:" +msgstr "Informar de errores a:" + +#: ../src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab guarda varios archivos juntos en un archivador cabinet, y puede " +"restaurar\n" +"archivos individuales del archivador." + +#: ../src/gcab.c:149 +#| msgid "option parsing failed: %s\n" +msgid "Option parsing failed" +msgstr "Falló al analizar la opción" + +#: ../src/gcab.c:159 +#| msgid "Please specify a single operation." +msgid "Please specify a single operation" +msgstr "Especifique una única operación" + +#: ../src/gcab.c:164 +#| msgid "cabinet file must be specified." +msgid "Cabinet file must be specified" +msgstr "Se debe especificar un archivo cabinet" + +#: ../src/gcab.c:180 +#| msgid "can't open %s for reading: %s\n" +msgid "Cannot open file for reading" +msgstr "No se puede abrir para lectura" + +#: ../src/gcab.c:184 +#| msgid "error reading %s: %s\n" +msgid "Error reading" +msgstr "Error al leer" + +#: ../src/gcab.c:220 +#| msgid "error during extraction: %s" +msgid "Error during extraction" +msgstr "Error durante la extracción" + +#: ../src/gcab.c:235 +#| msgid "error while reading signature: %s" +msgid "Error while reading signature" +msgstr "Error al leer la firma" + +#: ../src/gcab.c:247 +#| msgid "cabinet file must be specified." +msgid "No input files specified" +msgstr "No se han especificado archivos de entrada" + +#: ../src/gcab.c:266 +#| msgid "Can't add file %s: %s" +msgid "Cannot add file" +msgstr "No se puede añadir el archivo" + +#: ../src/gcab.c:272 +#| msgid "no files to be archived." +msgid "No files to be archived" +msgstr "No hay archivos que comprimir" + +#: ../src/gcab.c:280 +#| msgid "can't create cab file %s: %s" +msgid "Cannot create cab file" +msgstr "No se puede crear el archivo cab" + +#: ../src/gcab.c:286 +#| msgid "can't add folder to cab file %s: %s" +msgid "Cannot add folder to cab file" +msgstr "No se puede añadir una carpeta al archivo cabinet" + +#: ../src/gcab.c:296 +#| msgid "can't write cab file %s: %s" +msgid "Cannot write cab file" +msgstr "No se puede escribir el archivo cab" + +#~ msgid "Removing leading '%s' from member names" +#~ msgstr "Quitando «%s» inicial de los nombres de los miembros" + +#~ msgid "can't write file %s: %s" +#~ msgstr "no se puede escribir el archivo %s: %s" + +#~ msgid "please specify input files." +#~ msgstr "especifique los archivos de entrada." + +#~ msgid "unsupported compression method %d" +#~ msgstr "método de compresión %d no soportado" + +#~ msgid "incorrect checksum detected" +#~ msgstr "detectada suma de verificación incorrecta" diff --git a/po/eu.po b/po/eu.po new file mode 100644 index 0000000..11b7737 --- /dev/null +++ b/po/eu.po @@ -0,0 +1,176 @@ +# Basque translation for gcab +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Iñaki Larrañaga Murgoitio , 2013, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-04-04 17:34+0200\n" +"PO-Revision-Date: 2015-04-04 17:35+0200\n" +"Last-Translator: Iñaki Larrañaga Murgoitio \n" +"Language-Team: Basque \n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 1.5\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Hasierako '%s' kideen izenetatik kentzen" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "'%s'(r)en datuak hona iraultzen: %s...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "ezin da '%s' fitxategia idatzi: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Erakutsi programaren bertsioa" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Eman xehetasunak" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Sortu artxiboa" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Erauzi fitxategi guztiak" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Irauli gordetako datuak eta datu gehigarriak" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Zerrendatu edukia" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Zerrendatu edukia fitxategien xehetasunekin" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Aldatu DIR direktoriora" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Erabili zip konpresioa" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Ez sartu bide-izena" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Gorde lekua 'cabinet' artxiboan sinatzeko (adib. '-s 6144' aukerak 6 Kbyte " +"gordetzen ditu)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "ARTXIBOA SARRERAKO_FITXATEGIAK..." + +# Cabinet formatua artxibo konprimitua da, ezin da beraz 'fitxategi' bezala euskaratu. +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- sortu Cabinet artxiboa" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Bidali erroreei buruzko informazioa hona: <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab aplikazioak hainbat fitxategi batera gordetzen ditu 'cabinet' motako " +"artxibo batean,\n" +"eta banakako fitxategiak lehenera ditzake artxibotik." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "Huts egin du aukera aztertzean: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Zehaztu eragiketa bakar bat." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "cabinet artxiboa zehaztu behar da." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "ezin da '%s' irakurtzeko ireki: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "errorea '%s' irakurtzean: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "errorea erauztean: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "errorea sinadura irakurtzean: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "zehaztu sarrerako fitxategiak." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Ezin da '%s' fitxategia gehitu: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "ez dago fitxategirik artxibatzeko." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "ezin da '%s' cab artxiboa sortu: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "ezin zaio '%s' cab artxiboari karpeta gehitu: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "ezin da '%s' cab artxiboa idatzi: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "onartu gabeko %d konpresio-metodoa" + diff --git a/po/fi.po b/po/fi.po new file mode 100644 index 0000000..25065b8 --- /dev/null +++ b/po/fi.po @@ -0,0 +1,145 @@ +# Finnish translation for gcab. +# Copyright (C) 2018 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2018-01-27 09:07+0000\n" +"PO-Revision-Date: 2018-01-27 15:12+0200\n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: Jiri Grönroos \n" +"X-Generator: Poedit 1.8.7.1\n" + +#: src/gcab.c:82 +msgid "Dumping data to:" +msgstr "" + +#: src/gcab.c:114 +msgid "Print program version" +msgstr "Tulosta ohjelman versio" + +#: src/gcab.c:115 +msgid "Be verbose" +msgstr "" + +#: src/gcab.c:116 +msgid "Create archive" +msgstr "Luo arkisto" + +#: src/gcab.c:117 +msgid "Extract all files" +msgstr "Pura kaikki tiedostot" + +#: src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "" + +#: src/gcab.c:119 +msgid "List content" +msgstr "Listaa sisältö" + +#: src/gcab.c:120 +msgid "List content with file details" +msgstr "Listaa sisältö tiedostojen tietojen kera" + +#: src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Vaihda hakemistoon DIR" + +#: src/gcab.c:121 +msgid "DIR" +msgstr "DIR" + +#: src/gcab.c:122 +msgid "Use zip compression" +msgstr "Käytä zip-pakkausta" + +#: src/gcab.c:123 +msgid "Do not include path" +msgstr "Älä sisällytä polkua" + +#: src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" + +#: src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "" + +#: src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- luo Cabinet-tiedosto" + +#: src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Ilmoita vioista:" + +#: src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab tallentaa useita tiedostoja yhteen cabinet-arkistoksi, ja voi " +"palauttaa\n" +"yksittäisiä tiedostoja arkistosta." + +#: src/gcab.c:149 +msgid "Option parsing failed" +msgstr "" + +#: src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Määritä yksittäinen toimenpide" + +#: src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Cabinet-tiedosto tulee määrittää" + +#: src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Tiedostoa ei voida avata lukemista varten" + +#: src/gcab.c:184 +msgid "Error reading" +msgstr "Virhe luettaessa" + +#: src/gcab.c:220 +msgid "Error during extraction" +msgstr "Virhe purkamisen aikana" + +#: src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Virhe allekirjoitusta luettaessa" + +#: src/gcab.c:247 +msgid "No input files specified" +msgstr "Syötetiedostoja ei määritelty" + +#: src/gcab.c:266 +msgid "Cannot add file" +msgstr "Tiedostoa ei voi lisätä" + +#: src/gcab.c:272 +msgid "No files to be archived" +msgstr "Ei tiedostoja arkistoitavaksi" + +#: src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Cab-tiedoston luominen ei onnistu" + +#: src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Kansiota ei voi lisätä cab-tiedostoon" + +#: src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Cab-tiedostoa ei voi kirjoittaa" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..b93180c --- /dev/null +++ b/po/fr.po @@ -0,0 +1,146 @@ +# French translation for gcab. +# Copyright (C) 2013-2018 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Yoann Fievez , 2013. +# Julien Hardelin , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2018-01-26 14:27+0000\n" +"PO-Revision-Date: 2018-01-27 15:35+0100\n" +"Last-Translator: Claude Paroz \n" +"Language-Team: GNOME French Team \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Vidage des données vers :" + +#: src/gcab.c:114 +msgid "Print program version" +msgstr "Afficher la version du programme" + +#: src/gcab.c:115 +msgid "Be verbose" +msgstr "Être verbeux" + +#: src/gcab.c:116 +msgid "Create archive" +msgstr "Créer une archive" + +#: src/gcab.c:117 +msgid "Extract all files" +msgstr "Extraire tous les fichiers" + +#: src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Vider les données extra et réservées" + +#: src/gcab.c:119 +msgid "List content" +msgstr "Lister le contenu" + +#: src/gcab.c:120 +msgid "List content with file details" +msgstr "Lister le contenu avec détails des fichiers" + +#: src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Changer vers le répertoire DIR" + +#: src/gcab.c:121 +msgid "DIR" +msgstr "DIR" + +#: src/gcab.c:122 +msgid "Use zip compression" +msgstr "Utiliser la compression zip" + +#: src/gcab.c:123 +msgid "Do not include path" +msgstr "Ne pas inclure le chemin" + +#: src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Réserver de l'espace dans le cabinet pour la signature (p.e. -s 6144 réserve " +"6K octets)" + +#: src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "FICHIER FICHIERS_ENTRÉE…" + +#: src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- créer un fichier Cabinet" + +#: src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Signaler des anomalies à :" + +#: src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"GCAB enregistre plusieurs fichiers en même temps dans une archive cabinet,\n" +"et peut restaurer les fichiers individuels à partir de l'archive." + +#: src/gcab.c:149 +msgid "Option parsing failed" +msgstr "L'analyse des options a échoué" + +#: src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Veuillez spécifier une seule opération" + +#: src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Le fichier cabinet doit être indiqué" + +#: src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Impossible d'ouvrir le fichier en lecture" + +#: src/gcab.c:184 +msgid "Error reading" +msgstr "Erreur de lecture" + +#: src/gcab.c:220 +msgid "Error during extraction" +msgstr "Erreur pendant l'extraction" + +#: src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Erreur pendant la lecture de la signature" + +#: src/gcab.c:247 +msgid "No input files specified" +msgstr "Aucun fichier d'entrée n'a été indiqué" + +#: src/gcab.c:266 +msgid "Cannot add file" +msgstr "Impossible d'ajouter le fichier" + +#: src/gcab.c:272 +msgid "No files to be archived" +msgstr "Aucun fichier à archiver" + +#: src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Impossible de créer le fichier cab" + +#: src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Impossible d'ajouter le dossier au fichier cab" + +#: src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Impossible d'écrire le fichier cab" diff --git a/po/fur.po b/po/fur.po new file mode 100644 index 0000000..f0e0cfa --- /dev/null +++ b/po/fur.po @@ -0,0 +1,176 @@ +# Friulian translation for gcab. +# Copyright (C) 2017 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Fabio Tomat , 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2017-03-03 08:39+0000\n" +"PO-Revision-Date: 2017-04-08 15:07+0200\n" +"Language-Team: Friulian \n" +"Language: fur\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Fabio Tomat \n" +"X-Generator: Poedit 1.8.12\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Daûr a gjavâ “%s” principâl dai nons dai membris" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Daûr a butâ i dâts di %s su: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "impussibil scrivi il file %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Stampe la version dal program" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Jessi prolìs" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Cree archivi" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Tire fûr ducj i file" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Bute i dâts riservâts e adizionâi" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Liste il contignût" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Liste il contignût cui detais dai file" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Va ae cartele CARTELE" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "CARTELE" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Dopre compression zip" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "No stâ includi il percors" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Riserve spazi tal archivi cabinet pe firme (p.e. -s 6144 al riserve 6K " +"byte)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "FILE INPUT_FILES..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- cree un file Cabinet" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Segnale erôrs a <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab al salve tancj file adun intun archivi cabinet e al puest " +"ripristinâ,\n" +"dal archivi, file individuâi ." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "no si è rivâts a analizâ la opzion: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Specifiche une uniche operazion." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "il file cabinet al à di jessi specificât." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "impussibil vierzi %s pe leture: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "erôr tal lei %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "erôr dilunc la estrazion: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "erôr inte leture de firme: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "specifiche i file di jentrade." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Impussibil zontâ il file %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "nissun file di archiviâ." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "impussibil creâ il file cab %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "impussibil zontâ la cartele sul file cab %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "impussibil scrivi il file cab %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:469 +#, c-format +msgid "unsupported compression method %d" +msgstr "metodi di compression %d no supuartât" + +#: ../libgcab/cabinet.c:483 +msgid "incorrect checksum detected" +msgstr "rilevât checksum no just" diff --git a/po/gl.po b/po/gl.po new file mode 100644 index 0000000..3df3425 --- /dev/null +++ b/po/gl.po @@ -0,0 +1,166 @@ +# Galician translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Fran Dieguez , 2013. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-08-02 12:30+0200\n" +"PO-Revision-Date: 2013-08-02 12:30+0200\n" +"Last-Translator: Fran Dieguez \n" +"Language-Team: gnome-l10n-gl@gnome.org\n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Virtaal 0.7.1\n" +"X-Project-Style: gnome\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Eliminando os «%s» ao final dos nombres dos membros" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Extraéndo os datos %s a: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "non é posíbel escribir o ficheiro %s: %s" + +#: ../gcab.c:108 +msgid "Print program version" +msgstr "Mostra a versión do programa" + +#: ../gcab.c:109 +msgid "Be verbose" +msgstr "Saída detallada" + +#: ../gcab.c:110 +msgid "Create archive" +msgstr "Crear arquivo" + +#: ../gcab.c:111 +msgid "Extract all files" +msgstr "Extraer todos os ficheiros" + +#: ../gcab.c:112 +msgid "Dump reserved and extra data" +msgstr "Mostrar os datos reservados e adicionais" + +#: ../gcab.c:113 +msgid "List content" +msgstr "Mostrar o contido" + +#: ../gcab.c:114 +msgid "Change to directory DIR" +msgstr "Cambiar ao directorio DIR" + +#: ../gcab.c:114 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:115 +msgid "Use zip compression" +msgstr "Usar a compresión zip" + +#: ../gcab.c:116 +msgid "Do not include path" +msgstr "Non incluír a ruta" + +#: ../gcab.c:117 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Espacio reservado no cab para o asinado (p.ex. -x 6144 reserva 6K bytes)" + +#: ../gcab.c:118 +msgid "FILE INPUT_FILES..." +msgstr "FICHEIRO FICHEIROS_ENTRADA..." + +#: ../gcab.c:132 +msgid "- create a Cabinet file" +msgstr "- crear un ficheiro Cabinet" + +#: ../gcab.c:133 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Informe de fallos a <%s>." + +#: ../gcab.c:136 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab garda moitos ficheiros de forma conxunta nun ficheiro cabinet, e pode " +"restaurar ficheiros de forma individual desde o ficheiro." + +#: ../gcab.c:143 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "Produciuse un erro ao analizar a opción: %s\n" + +#: ../gcab.c:152 +msgid "Please specify a single operation." +msgstr "Por favor especifique unha única operación." + +#: ../gcab.c:155 +msgid "cabinet file must be specified." +msgstr "Debe especificar un ficheiro cabinet." + +#: ../gcab.c:169 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "non é posíbel abrir %s para lectura: %s\n" + +#: ../gcab.c:171 +#, c-format +msgid "error reading %s: %s\n" +msgstr "produciuse un erro en %s: %s\n" + +#: ../gcab.c:188 +#, c-format +msgid "error during extraction: %s" +msgstr "Produciuse un erro ao extraer: %s" + +#: ../gcab.c:200 +#, c-format +msgid "error while reading signature: %s" +msgstr "Produciuse un erro ao ler a sinatura: %s" + +#: ../gcab.c:211 +msgid "please specify input files." +msgstr "por favor especifique os ficheiros de entrada." + +#: ../gcab.c:229 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Non é posíbel engadir o ficheiro %s: %s" + +#: ../gcab.c:239 +msgid "no files to be archived." +msgstr "non hai ficheiros para arquivar." + +#: ../gcab.c:245 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "non é posíebel crear o ficheiro cab %s: %s" + +#: ../gcab.c:249 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "non é posíbel engadir o ficheiro ao cab %s: %s" + +#: ../gcab.c:257 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "Non é posíbel escribir no ficheiro cab %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:453 +#, c-format +msgid "unsupported compression method %d" +msgstr "método de compresión non compatíbel %d" diff --git a/po/hu.po b/po/hu.po new file mode 100644 index 0000000..849e8f6 --- /dev/null +++ b/po/hu.po @@ -0,0 +1,147 @@ +# Hungarian translation for gcab. +# Copyright (C) 2013, 2015, 2018 Free Software Foundation, Inc. +# This file is distributed under the same license as the gcab package. +# +# Balázs Úr , 2013, 2015, 2018. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2018-01-26 14:27+0000\n" +"PO-Revision-Date: 2018-01-27 10:05+0100\n" +"Last-Translator: Balázs Úr \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 1.2\n" + +#: src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Adatok kiírása ide:" + +#: src/gcab.c:114 +msgid "Print program version" +msgstr "Programverzió kiírása" + +#: src/gcab.c:115 +msgid "Be verbose" +msgstr "Legyen bőbeszédű" + +#: src/gcab.c:116 +msgid "Create archive" +msgstr "Archívum létrehozása" + +#: src/gcab.c:117 +msgid "Extract all files" +msgstr "Minden fájl kibontása" + +#: src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Foglalt és extra adatok kiírása" + +#: src/gcab.c:119 +msgid "List content" +msgstr "Tartalom listázása" + +#: src/gcab.c:120 +msgid "List content with file details" +msgstr "Tartalom listázása a fájl részleteivel" + +#: src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Váltás a DIR könyvtárra" + +#: src/gcab.c:121 +msgid "DIR" +msgstr "DIR" + +#: src/gcab.c:122 +msgid "Use zip compression" +msgstr "Zip tömörítés használata" + +#: src/gcab.c:123 +msgid "Do not include path" +msgstr "Ne vegyen fel útvonalat" + +#: src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Szóköz lefoglalása a cabinetben aláíráshoz (például -s 6144 lefoglal 6K " +"bájtot)" + +#: src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "FILE INPUT_FILES…" + +#: src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- egy Cabinet fájl létrehozása" + +#: src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Hibák jelentése itt:" + +#: src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"A gcab több fájlt együtt ment egy cabinet archívumba, és képes\n" +"visszaállítani egyedüli fájlokat az archívumból." + +#: src/gcab.c:149 +msgid "Option parsing failed" +msgstr "A kapcsoló feldolgozása sikertelen" + +#: src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Kérjük adjon meg egy egyedüli műveletet" + +#: src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Cabinet fájl megadása kötelező" + +#: src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Nem nyitható meg a fájl olvasásra" + +#: src/gcab.c:184 +msgid "Error reading" +msgstr "Hiba az olvasás közben" + +#: src/gcab.c:220 +msgid "Error during extraction" +msgstr "Hiba a kibontás során" + +#: src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Hiba az aláírás olvasása közben" + +#: src/gcab.c:247 +msgid "No input files specified" +msgstr "Nincsenek bemeneti fájlok megadva" + +#: src/gcab.c:266 +msgid "Cannot add file" +msgstr "Nem lehet hozzáadni a fájlt" + +#: src/gcab.c:272 +msgid "No files to be archived" +msgstr "Nincsenek archiválandó fájlok" + +#: src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Nem hozható létre cab fájl" + +#: src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Nem lehet mappát hozzáadni a cab fájlhoz" + +#: src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Nem írható a cab fájl" + diff --git a/po/id.po b/po/id.po new file mode 100644 index 0000000..93ba5a2 --- /dev/null +++ b/po/id.po @@ -0,0 +1,160 @@ +# Indonesian translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Andika Triwidada , 2013, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2018-01-26 14:27+0000\n" +"PO-Revision-Date: 2018-01-31 11:40+0700\n" +"Last-Translator: Kukuh Syafaat \n" +"Language-Team: Indonesian \n" +"Language: id\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.6\n" + +#: src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Mencurahkan data ke:" + +#: src/gcab.c:114 +msgid "Print program version" +msgstr "Cetak versi program" + +#: src/gcab.c:115 +msgid "Be verbose" +msgstr "Terrinci" + +#: src/gcab.c:116 +msgid "Create archive" +msgstr "Buat arsip" + +#: src/gcab.c:117 +msgid "Extract all files" +msgstr "Ekstrak semua berkas" + +#: src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Curahkan data ekstra dan cadangan" + +#: src/gcab.c:119 +msgid "List content" +msgstr "Tampilkan daftar isi" + +#: src/gcab.c:120 +msgid "List content with file details" +msgstr "Lihat daftar isi dengan rincian berkas" + +#: src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Ubah ke direktori DIR" + +#: src/gcab.c:121 +msgid "DIR" +msgstr "DIR" + +#: src/gcab.c:122 +msgid "Use zip compression" +msgstr "Gunakan kompresi zip" + +#: src/gcab.c:123 +msgid "Do not include path" +msgstr "Jangan sertakan path" + +#: src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Cadangkan ruang dalam kabinet untuk penandatanganan (mis. -s 6144 " +"mencadangkan 6k bita)" + +#: src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "BERKAS BERKAS_MASUKAN..." + +#: src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- buat suatu berkas Kabinet" + +#: src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Laporkan kutu ke:" + +#: src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab menyimpan banyak berkas bersama-sama ke dalam suatu arsip\n" +"kabinet, dan dapat memulihkan berkas individu dari arsip." + +#: src/gcab.c:149 +msgid "Option parsing failed" +msgstr "Penguraian opsi gagal" + +#: src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Harap nyatakan suatu operasi tunggal" + +#: src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Berkas kabinet mesti dinyatakan" + +#: src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Tidak bisa membuka berkas untuk dibaca" + +#: src/gcab.c:184 +msgid "Error reading" +msgstr "Galat saat baca" + +#: src/gcab.c:220 +msgid "Error during extraction" +msgstr "Galat saat ekstraksi" + +#: src/gcab.c:235 +msgid "Error while reading signature" +msgstr "galat saat membaca tanda tangan" + +#: src/gcab.c:247 +msgid "No input files specified" +msgstr "Tidak ada berkas masukan yang ditentukan" + +#: src/gcab.c:266 +msgid "Cannot add file" +msgstr "Tidak bisa menambahkan berkas" + +#: src/gcab.c:272 +msgid "No files to be archived" +msgstr "Tidak ada berkas yang akan diarsipkan." + +#: src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Tidak bisa membuat berkas cab" + +#: src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Tidak bisa menambahkan folder ke berkas kab" + +#: src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Tidak bisa menulis berkas kab" + +#~ msgid "Removing leading '%s' from member names" +#~ msgstr "Menghapus awalan '%s' dari nama-nama anggota" + +#~ msgid "can't write file %s: %s" +#~ msgstr "tak bisa menulis berkas %s: %s" + +#~ msgid "please specify input files." +#~ msgstr "harap nyatakan berkas masukan." + +#~ msgid "unsupported compression method %d" +#~ msgstr "metoda kompresi tak didukung %d" + +#~ msgid "incorrect checksum detected" +#~ msgstr "checksum yang salah terdeteksi" diff --git a/po/lt.po b/po/lt.po new file mode 100644 index 0000000..88d9b8e --- /dev/null +++ b/po/lt.po @@ -0,0 +1,176 @@ +# Lithuanian translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Aurimas Černius , 2013, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2016-01-08 06:29+0000\n" +"PO-Revision-Date: 2016-01-08 13:14+0200\n" +"Last-Translator: Aurimas Černius \n" +"Language-Team: Lietuvių \n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" +"%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 1.8.6\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Šalinami „%s“ narių pavadinimų pradžiose" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Įrašomi %s duomenys į: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "nepavyksta įrašyti failo %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Atspausdinti programos versiją" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Būti išsamiu" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Sukurti archyvą" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Išskleisti visus failus" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Įrašyti rezervuotus ir papildomus duomenis" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Išvardinti turinį" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Išvardinti turinį su failų informacija" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Keisti aplanką į KAT" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "KAT" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Naudoti zip suspaudimą" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Neįtraukti kelio" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Rezervuoti vietos archyve pasirašymui (pvz. -s 6144 rezervuoja 6K baitų)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "FILE ĮVESTIES_FAILAI..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- sukurti Cabinet failą" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Pranešti apie klaidas <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab įrašo daug failų kartu viename cabinet archyve ir gali atkurti\n" +"pavienius failus iš archyvo." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "nepavyko perskaityti parametro: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Nurodykite vieną veiksmą." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "turi būti nurodytas cabinet failas." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "nepavyksta atverti %s skaitymui: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "klaida skaitant %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "klaida išskleidžiant: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "klaida skaitant parašą: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "nurodykite įvesties failus." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Nepavyksta pridėti failo %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "nėra archyvuojamų failų." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "nepavyksta sukurti cab failo %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "nepavyksta pridėti aplanko į cab failą %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "nepavyksta įrašyti cab failo %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "nepalaikomas suspaudimo metodas %d" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "Aptikta neteisinga kontrolinė suma" diff --git a/po/lv.po b/po/lv.po new file mode 100644 index 0000000..5431582 --- /dev/null +++ b/po/lv.po @@ -0,0 +1,168 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Rūdolfs Mazurs , 2013. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2013-10-13 13:46+0000\n" +"PO-Revision-Date: 2013-10-14 20:10+0300\n" +"Last-Translator: Rūdolfs Mazurs \n" +"Language-Team: Latvian \n" +"Language: lv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " +"2);\n" +"X-Generator: Lokalize 1.5\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Noņem sākuma “%s” no biedru nosaukumiem" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Nomet %s datus uz: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "nevar ierakstīt datnē %s — %s" + +#: ../gcab.c:108 +msgid "Print program version" +msgstr "Drukāt programmas versiju" + +#: ../gcab.c:109 +msgid "Be verbose" +msgstr "Rādīt detalizētāku informāciju" + +#: ../gcab.c:110 +msgid "Create archive" +msgstr "Izveidot arhīvu" + +#: ../gcab.c:111 +msgid "Extract all files" +msgstr "Atspiest visas datnes" + +#: ../gcab.c:112 +msgid "Dump reserved and extra data" +msgstr "Nomest rezervētos un papildu datus" + +#: ../gcab.c:113 +msgid "List content" +msgstr "Saraksta saturs" + +#: ../gcab.c:114 +msgid "Change to directory DIR" +msgstr "Pāriet uz direktoriju DIR" + +#: ../gcab.c:114 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:115 +msgid "Use zip compression" +msgstr "Lietot zip saspiešanu" + +#: ../gcab.c:116 +msgid "Do not include path" +msgstr "Neiekļaut ceļu" + +#: ../gcab.c:117 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Kabinetā rezervēt vietu parakstīšanai (piemēram, -s 6144 rezervē 6K baitus)" + +#: ../gcab.c:118 +msgid "FILE INPUT_FILES..." +msgstr "DATNE IEVADES_DATNES..." + +#: ../gcab.c:132 +msgid "- create a Cabinet file" +msgstr "- izveidot Cabinet datni" + +#: ../gcab.c:133 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Ziņot <%s> par kļūdām" + +#: ../gcab.c:136 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab kopā saglabā vairākas datnes kabineta arhīvā, un var\n" +"atjaunot atsevišķas datnes no arhīva." + +#: ../gcab.c:143 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "neizdevās parsēt opcijas: %s\n" + +#: ../gcab.c:152 +msgid "Please specify a single operation." +msgstr "Lūdzu, norādiet vienu darbību." + +#: ../gcab.c:155 +msgid "cabinet file must be specified." +msgstr "jānorāda kabineta datne." + +#: ../gcab.c:169 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "nevar atvērt %s lasīšanai: %s\n" + +#: ../gcab.c:171 +#, c-format +msgid "error reading %s: %s\n" +msgstr "kļūda, nolasot \"%s\": %s\n" + +#: ../gcab.c:188 +#, c-format +msgid "error during extraction: %s" +msgstr "kļūda, izvilkšanas laikā: %s" + +#: ../gcab.c:200 +#, c-format +msgid "error while reading signature: %s" +msgstr "Kļūda, nolasot parakstu: %s" + +#: ../gcab.c:211 +msgid "please specify input files." +msgstr "lūdzu, norādiet ievades datnes." + +#: ../gcab.c:229 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Nevar pievienot datni %s — %s" + +#: ../gcab.c:239 +msgid "no files to be archived." +msgstr "nav datņu, ko arhivēt." + +#: ../gcab.c:245 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "nevar izveidot cab datni %s — %s" + +#: ../gcab.c:249 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "nevar pievienot mapi cab datnei %s — %s" + +#: ../gcab.c:257 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "nevar ierakstīt cab datnē %s — %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:453 +#, c-format +msgid "unsupported compression method %d" +msgstr "neatbalstīta saspiešanas metode %d" + diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 0000000..6b9a7bc --- /dev/null +++ b/po/meson.build @@ -0,0 +1,6 @@ +i18n.gettext(meson.project_name(), + preset : 'glib', + args: [ + '--default-domain=' + meson.project_name(), + ] +) diff --git a/po/nb.po b/po/nb.po new file mode 100644 index 0000000..849412b --- /dev/null +++ b/po/nb.po @@ -0,0 +1,161 @@ +# Norwegian bokmål translation of gcab. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# FIRST AUTHOR , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-07-25 14:09+0200\n" +"PO-Revision-Date: 2014-07-25 14:19+0200\n" +"Last-Translator: Kjartan Maraas \n" +"Language-Team: Norwegian bokmål \n" +"Language: nb\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Dumper %s data til: %s …\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "kan ikke skrive fil %s: %s" + +#: ../gcab.c:108 +msgid "Print program version" +msgstr "Skriv programversjon" + +#: ../gcab.c:109 +msgid "Be verbose" +msgstr "Vis mer informasjon" + +#: ../gcab.c:110 +msgid "Create archive" +msgstr "Lag arkiv" + +#: ../gcab.c:111 +msgid "Extract all files" +msgstr "Hent ut alle filer" + +#: ../gcab.c:112 +msgid "Dump reserved and extra data" +msgstr "Dump reserverte og ekstra data" + +#: ../gcab.c:113 +msgid "List content" +msgstr "Vis innhold" + +#: ../gcab.c:114 +msgid "Change to directory DIR" +msgstr "Bytt katalog til KAT" + +#: ../gcab.c:114 +msgid "DIR" +msgstr "KAT" + +#: ../gcab.c:115 +msgid "Use zip compression" +msgstr "Bruk zip-komprimering" + +#: ../gcab.c:116 +msgid "Do not include path" +msgstr "Ikke ta med sti" + +#: ../gcab.c:117 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" + +#: ../gcab.c:118 +msgid "FILE INPUT_FILES..." +msgstr "" + +#: ../gcab.c:132 +msgid "- create a Cabinet file" +msgstr "- lag en kabinettfil" + +#: ../gcab.c:133 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Rapporter feil til <%s>" + +#: ../gcab.c:136 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" + +#: ../gcab.c:143 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "" + +#: ../gcab.c:152 +msgid "Please specify a single operation." +msgstr "" + +#: ../gcab.c:155 +msgid "cabinet file must be specified." +msgstr "" + +#: ../gcab.c:169 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "" + +#: ../gcab.c:171 +#, c-format +msgid "error reading %s: %s\n" +msgstr "feil ved lesing av %s: %s\n" + +#: ../gcab.c:188 +#, c-format +msgid "error during extraction: %s" +msgstr "feil ved utpakking: %s" + +#: ../gcab.c:200 +#, c-format +msgid "error while reading signature: %s" +msgstr "feil ved lesing av signatur: %s" + +#: ../gcab.c:211 +msgid "please specify input files." +msgstr "" + +#: ../gcab.c:229 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Kan ikke legge til fil %s: %s" + +#: ../gcab.c:239 +msgid "no files to be archived." +msgstr "ingen filer å arkivere" + +#: ../gcab.c:245 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "" + +#: ../gcab.c:249 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "" + +#: ../gcab.c:257 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "kan ikke skrive cab-fil %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:453 +#, c-format +msgid "unsupported compression method %d" +msgstr "" diff --git a/po/oc.po b/po/oc.po new file mode 100644 index 0000000..b1a3b16 --- /dev/null +++ b/po/oc.po @@ -0,0 +1,174 @@ +# French translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Yoann Fievez , 2013. +# Julien Hardelin , 2014. +# Cédric Valmary (Tot en òc) , 2015. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gcab&ke" +"ywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-03-12 21:39+0000\n" +"PO-Revision-Date: 2015-05-30 19:26+0200\n" +"Last-Translator: Cédric Valmary (Tot en òc) \n" +"Language-Team: Tot en òc (totenoc.eu)\n" +"Language: oc\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Virtaal 0.7.1\n" +"X-Project-Style: gnome\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Supression dels '%s' en tèsta dels noms de membre" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Voidatge de las donadas %s cap a : %s ... \n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "Impossible d'escriure lo fichièr %s : %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Afichar la version del programa" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Èsser verbós" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Crear un archiu" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Extraire totes los fichièrs" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Voidar las donadas extra e reservadas" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Listar lo contengut" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Listar lo contengut amb losdetalhs del fichièr" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Cambiar cap al repertòri DIR" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Utilizar la compression zip" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Inclure pas lo camin" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Reservar d'espaci dins lo cabinet per la signatura (p.e. -s 6144 resèrva 6K " +"octets)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "FICHIÈR INPUT_FILES..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- crear un fichièr Cabinet" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Senhalar d'anomalias a <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"GCAB enregistra mantun fichièr en mème temps dins un archiu cabinet, e pòt " +"restablir los fichièrs individuals a partir de l'archiu." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "L'analisi de las opcions a fracassat : %s \n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Especificatz una sola operacion." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "lo fichièr cabinet deu èsser especificat." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "Impossible de dobrir %s en lectura : %s \n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "error pendent la lectura %s : %s \n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "error pendent l'extraccion : %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "error pendent la lectura de la signatura : %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "Especificatz los fichièrs d'entrada." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Impossible d'apondre lo fichièr %s : %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "Pas cap de fichièr d'archivar." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "Impossible de crear lo fichièr cab %s : %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "Impossible d'apondre lo dorsièr al fichièr cab %s : %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "Impossible d'escriure lo fichièr cab %s : %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "Metòde de compression %d pas pres en carga" diff --git a/po/pl.po b/po/pl.po new file mode 100644 index 0000000..17f76fd --- /dev/null +++ b/po/pl.po @@ -0,0 +1,145 @@ +# Polish translation for gcab. +# Copyright © 2013-2018 the gcab authors. +# This file is distributed under the same license as the gcab package. +# Piotr Drąg , 2013-2018. +# Aviary.pl , 2013-2018. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-12 17:34+0100\n" +"PO-Revision-Date: 2018-01-12 17:35+0100\n" +"Last-Translator: Piotr Drąg \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" + +#: ../src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Zrzucanie danych do:" + +#: ../src/gcab.c:114 +msgid "Print program version" +msgstr "Wyświetla wersję programu" + +#: ../src/gcab.c:115 +msgid "Be verbose" +msgstr "Więcej komunikatów" + +#: ../src/gcab.c:116 +msgid "Create archive" +msgstr "Tworzy archiwum" + +#: ../src/gcab.c:117 +msgid "Extract all files" +msgstr "Rozpakowuje wszystkie pliki" + +#: ../src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Zrzuca zarezerwowane i dodatkowe dane" + +#: ../src/gcab.c:119 +msgid "List content" +msgstr "Wyświetla listę zawartości" + +#: ../src/gcab.c:120 +msgid "List content with file details" +msgstr "Wyświetla listę zawartości z informacjami o plikach" + +#: ../src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Przechodzi do KATALOGU" + +#: ../src/gcab.c:121 +msgid "DIR" +msgstr "KATALOG" + +#: ../src/gcab.c:122 +msgid "Use zip compression" +msgstr "Używa kompresji zip" + +#: ../src/gcab.c:123 +msgid "Do not include path" +msgstr "Bez dołączania ścieżki" + +#: ../src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Rezerwuje miejsce w pliku Cabinet do podpisania (np. -s 6144 rezerwuje 6 KB)" + +#: ../src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "PLIK PLIKI_WEJŚCIOWE…" + +#: ../src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "— tworzy plik Cabinet" + +#: ../src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Prosimy zgłaszać błędy pod adresem (w języku angielskim):" + +#: ../src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab zapisuje wiele plików w jednym archiwum Cabinet, a także przywraca\n" +"pojedyncze pliki z archiwum." + +#: ../src/gcab.c:149 +msgid "Option parsing failed" +msgstr "Przetworzenie opcji się nie powiodło" + +#: ../src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Proszę podać jedno działanie" + +#: ../src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Należy podać plik Cabinet" + +#: ../src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Nie można otworzyć pliku do odczytania" + +#: ../src/gcab.c:184 +msgid "Error reading" +msgstr "Błąd podczas odczytywania" + +#: ../src/gcab.c:220 +msgid "Error during extraction" +msgstr "Błąd podczas rozpakowywania" + +#: ../src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Błąd podczas odczytywania podpisu" + +#: ../src/gcab.c:247 +msgid "No input files specified" +msgstr "Nie podano plików wejściowych" + +#: ../src/gcab.c:266 +msgid "Cannot add file" +msgstr "Nie można dodać pliku" + +#: ../src/gcab.c:272 +msgid "No files to be archived" +msgstr "Brak plików do dołączenia do archiwum" + +#: ../src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Nie można utworzyć pliku Cabinet" + +#: ../src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Nie można dodać katalogu do pliku Cabinet" + +#: ../src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Nie można zapisać pliku Cabinet" diff --git a/po/pt.po b/po/pt.po new file mode 100644 index 0000000..eba0822 --- /dev/null +++ b/po/pt.po @@ -0,0 +1,176 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2015 +# This file is distributed under the same license as the PACKAGE package. +# Pedro Albuquerque , 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-08-25 20:08+0000\n" +"PO-Revision-Date: 2015-08-26 06:35+0100\n" +"Last-Translator: Pedro Albuquerque \n" +"Language-Team: Português \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Gtranslator 2.91.6\n" +"X-Project-Style: gnome\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "A remover \"%s\" inicial dos nomes de membros" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "A despejar %s dados para: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "impossível escrever o ficheiro %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Imprimir versão do programa" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Ser verboso" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Criar arquivo" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Extrair todos os ficheiros" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Despejar dados reservados e extra" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Conteúdo da lista" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Conteúdo da lista com detalhes de ficheiro" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Mudar para a pasta DIR" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Usar compressão zip" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Não incluir caminho" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Reservar espaço no cabinet para assinar (ex.: -s 6144 reserva 6K bytes)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "FILE INPUT_FILES..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- criar um ficheiro cabinet" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Reportar erros a <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"O gcab grava muitos ficheiros juntos num arquivo cabinet e pode restaurar\n" +"ficheiros individuais desse arquivo." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "falha ao processar opção: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Por favor, especifique uma única operação." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "O ficheiro cabinet tem de ser especificado." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "impossível abrir %s para leitura: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "erro ao ler %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "erro durante a extração: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "erro ao ler assinatura: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "por favor, especifique ficheiros de entrada" + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Impossível adicionar %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "sem ficheiros para arquivar." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "impossível criar ficheiro cab %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "impossível adicionar pasta ao ficheiro cab %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "impossível escrever ficheiro cab %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "método de compressão não suportado %d" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "Detetada checksum incorreta" diff --git a/po/pt_BR.po b/po/pt_BR.po new file mode 100644 index 0000000..17f61a2 --- /dev/null +++ b/po/pt_BR.po @@ -0,0 +1,176 @@ +# Brazilian Portuguese translation for gcab. +# Copyright (C) 2018 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Enrico Nicoletto , 2013. +# Rafael Fontenelle , 2013, 2015, 2018. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2017-12-14 22:08+0000\n" +"PO-Revision-Date: 2018-01-08 20:23-0200\n" +"Last-Translator: Rafael Fontenelle \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Virtaal 1.0.0-beta1\n" +"X-Project-Style: gnome\n" + +#: ../src/gcab.c:82 +#| msgid "Dumping %s data to: %s ...\n" +msgid "Dumping data to:" +msgstr "Despejando dados para:" + +#: ../src/gcab.c:114 +msgid "Print program version" +msgstr "Informa a versão do programa" + +#: ../src/gcab.c:115 +msgid "Be verbose" +msgstr "Ser detalhista" + +#: ../src/gcab.c:116 +msgid "Create archive" +msgstr "Cria pacote" + +#: ../src/gcab.c:117 +msgid "Extract all files" +msgstr "Extrai todos os arquivos" + +#: ../src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Despejar dados reservados e adicionais" + +#: ../src/gcab.c:119 +msgid "List content" +msgstr "Lista conteúdo" + +#: ../src/gcab.c:120 +msgid "List content with file details" +msgstr "Lista conteúdo com detalhes de arquivo" + +#: ../src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Muda para o diretório DIR" + +#: ../src/gcab.c:121 +msgid "DIR" +msgstr "DIR" + +#: ../src/gcab.c:122 +msgid "Use zip compression" +msgstr "Usa compressão zip" + +#: ../src/gcab.c:123 +msgid "Do not include path" +msgstr "Não inclui caminho" + +#: ../src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Reservar espaço no cabinet para assinatura (ex: -s 6144 reserva 6K bytes)" + +#: ../src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "ARQUIVO ARQUIVOS_ENTRADAS..." + +#: ../src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- cria um arquivo Cabinet" + +#: ../src/gcab.c:140 +#| msgid "Report bugs to <%s>" +msgid "Report bugs to:" +msgstr "Relate erros para:" + +#: ../src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab salva muitos arquivos juntos em um pacote cabinet e pode restaurar\n" +"arquivos individuais do pacote." + +#: ../src/gcab.c:149 +#| msgid "option parsing failed: %s\n" +msgid "Option parsing failed" +msgstr "Falha ao analisar opção" + +#: ../src/gcab.c:159 +#| msgid "Please specify a single operation." +msgid "Please specify a single operation" +msgstr "Por favor, especifique uma única operação" + +#: ../src/gcab.c:164 +#| msgid "cabinet file must be specified." +msgid "Cabinet file must be specified" +msgstr "Arquivo cabinet deve ser especificado" + +#: ../src/gcab.c:180 +#| msgid "can't open %s for reading: %s\n" +msgid "Cannot open file for reading" +msgstr "Não foi possível abrir arquivo para leitura" + +#: ../src/gcab.c:184 +#| msgid "error reading %s: %s\n" +msgid "Error reading" +msgstr "Erro de leitura" + +#: ../src/gcab.c:220 +#| msgid "error during extraction: %s" +msgid "Error during extraction" +msgstr "Erro durante extração" + +#: ../src/gcab.c:235 +#| msgid "error while reading signature: %s" +msgid "Error while reading signature" +msgstr "Ocorreu erro ao ler assinatura" + +#: ../src/gcab.c:247 +#| msgid "cabinet file must be specified." +msgid "No input files specified" +msgstr "Nenhum arquivo cabinet especificado" + +#: ../src/gcab.c:266 +#| msgid "Can't add file %s: %s" +msgid "Cannot add file" +msgstr "Não foi possível adicionar arquivo" + +#: ../src/gcab.c:272 +#| msgid "no files to be archived." +msgid "No files to be archived" +msgstr "Nenhum arquivo para ser empacotado" + +#: ../src/gcab.c:280 +#| msgid "can't create cab file %s: %s" +msgid "Cannot create cab file" +msgstr "Não foi possível criar o arquivo cab" + +#: ../src/gcab.c:286 +#| msgid "can't add folder to cab file %s: %s" +msgid "Cannot add folder to cab file" +msgstr "Não foi possível adicionar a pasta ao arquivo cab" + +#: ../src/gcab.c:296 +#| msgid "can't write cab file %s: %s" +msgid "Cannot write cab file" +msgstr "Não foi possível escrever arquivo cab" + +#~ msgid "Removing leading '%s' from member names" +#~ msgstr "Removendo \"%s\" da frente dos nomes dos membros" + +#~ msgid "can't write file %s: %s" +#~ msgstr "não foi possível escrever arquivo %s: %s" + +#~ msgid "please specify input files." +#~ msgstr "por favor, especifique os arquivos de entrada." + +#~ msgid "unsupported compression method %d" +#~ msgstr "método de compressão %d não suportado" + +#~ msgid "incorrect checksum detected" +#~ msgstr "checksum incorreto detectado" diff --git a/po/ru.po b/po/ru.po new file mode 100644 index 0000000..c0be5d1 --- /dev/null +++ b/po/ru.po @@ -0,0 +1,177 @@ +# Russian translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# sds , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-08-25 20:08+0000\n" +"PO-Revision-Date: 2015-12-10 13:52+0300\n" +"Last-Translator: Aleksey Kabanov \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 1.6.4\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Удаление начального «%s» из имён объектов" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Создание дампа данных %s на: %s …\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "не удалось записать файл %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Показать версию программы" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Выводить подробную информацию" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Создать архив" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Извлечь все файлы" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Включать в дамп резервные и дополнительные данные" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Список содержимого" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Вывести список содержимого со сведениями о файлах" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Изменить на каталог КАТАЛОГ" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "КАТАЛОГ" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Использовать zip-сжатие" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Не включать путь" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Зарезервировать место в архиве для подписи (например, -s 6144 зарезервирует " +"6 Кб)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "ФАЙЛ ВХОДНЫЕ_ФАЙЛЫ..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- создать Cab-файл" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Отправить отчёт об ошибке на <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab упаковывает несколько файлов в cab-архив и может извлекать\n" +"отдельные файлы из архива." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "ошибка разбора параметра: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Выберите одну операцию." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "должен быть указан файл архива." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "не удалось открыть %s для чтения: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "ошибка чтения %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "ошибка во время извлечения: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "ошибка чтения подписи: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "укажите входные файлы." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Не удалось добавить файл %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "нет файлов для архивирования." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "не удалось создать cab-файл %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "не удалось добавить папку в cab-файл %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "не удалось записать cab-файл %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "метод сжатия %d не поддерживается" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "обнаружена неверная контрольная сумма" diff --git a/po/sl.po b/po/sl.po new file mode 100644 index 0000000..38f78c0 --- /dev/null +++ b/po/sl.po @@ -0,0 +1,179 @@ +# Slovenian translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# +# Matej Urbančič , 2013-2016. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2016-03-12 21:28+0100\n" +"PO-Revision-Date: 2016-03-12 21:28+0100\n" +"Last-Translator: Matej Urbančič \n" +"Language-Team: Slovenian GNOME Translation Team \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" +"X-Poedit-SourceCharset: utf-8\n" +"X-Generator: Poedit 1.8.4\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Odstranjevanje začetnih '%s' iz imen" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Odlaganje zapisa podatkov %s v: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "ni mogoče pisati v datoteko %s: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Izpiši različico programa" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Podrobni izpis" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Ustvari arhiv" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Razširi vse datoteke" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Odloži izpis zadržani in posebnih podatkov" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Izpiši vsebino" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Izpiši seznam s podrobnostmi o datotekah" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Zamenjaj mapo v mapo DIR" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "MAPA" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Uporabi stiskanje zip" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Ne vključi poti" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Zadrži prostor v kabinetu za podpisovanje (na primer -s 6144 zadrži 6Kb)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "DATOTEKA VHODNE_DATOTEKE ..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- ustvari datoteko cab" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Pošljite poročilo o hroščih na <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"Program gcab shrani več datotek v arhivsko datoteko cab, lahko pa tudi " +"obnovi\n" +"iz arhiva vse ali le posamične datoteke." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "razčlenjevanje možnosti je spodletelo: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Navesti je treba le eno opravilo." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "določena mora biti datoteka cab." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "ni mogoče odpreti %s za branje: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "napaka med branjem %s: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "napaka med razširjanjem: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "napaka med branjem podpisa: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "določiti je treba vhodne datoteke" + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Ni mogoče dodati datoteke %s: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "ni datotek za arhiviranje." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "ni mogoče ustvariti datoteke cab %s: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "ni mogoče dodati mape v datoteko cab %s: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "ni mogoče zapisati datoteke cab %s: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "nepodprt način stiskanja %d" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "zaznana je nepravilna nadzorna vsota" diff --git a/po/sr.po b/po/sr.po new file mode 100644 index 0000000..3655a58 --- /dev/null +++ b/po/sr.po @@ -0,0 +1,175 @@ +# Serbian translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Мирослав Николић , 2013—2015. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gcab&ke" +"ywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-08-25 20:08+0000\n" +"PO-Revision-Date: 2015-12-30 09:58+0200\n" +"Last-Translator: Мирослав Николић \n" +"Language-Team: Serbian \n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : " +"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Project-Style: gnome\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Уклањам водеће „%s“ из назива чланова" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Избацујем %s податке до: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "не могу да запишем датотеку „%s“: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Исписује издање програма" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Опширнији испис" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Прави архиву" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Извлачи све датотеке" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Избацује резервисане и посебне податке" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Исписује садржај" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Исписује садржај са појединостима датотеке" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Прелази у директоријум ДИР" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "ДИР" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Користи зип сажимање" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Не укључује путању" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Обезбеђује простор у кабинету за потпис (нпр. „-s 6144“ обезбеђује 6K бајта)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "УЛАЗНЕ_ДАТОТЕКЕ ДАТОТЕКЕ..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "— направите Кабинет датотеку" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Грешке пријавите на <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"гкаб чува заједно много датотека у кабинет архиви, и може да врати\n" +"појединачне датотеке из архиве." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "није успела обрада опције: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Молим наведите једну радњу." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "мора бити наведена кабинет датотека." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "не могу да отворим „%s“ за читање: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "грешка читања „%s“: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "грешка приликом извлачења: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "грешка приликом читања потписа: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "молим наведите улазне датотеке." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Не могу да додам датотеку „%s“: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "нема датотека за архивирање." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "не могу да направим каб датотеку „%s“: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "не могу да додам фасциклу у каб датотеку„%s“: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "не могу да запишем каб датотеку „%s“: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "неподржан режим паковања „%d“" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "откривена је неисправна сума провере" diff --git a/po/sr@latin.po b/po/sr@latin.po new file mode 100644 index 0000000..134ccbf --- /dev/null +++ b/po/sr@latin.po @@ -0,0 +1,175 @@ +# Serbian translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Miroslav Nikolić , 2013—2015. +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gcab&ke" +"ywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-08-25 20:08+0000\n" +"PO-Revision-Date: 2015-12-30 09:58+0200\n" +"Last-Translator: Miroslav Nikolić \n" +"Language-Team: Serbian \n" +"Language: sr@latin\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : " +"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Project-Style: gnome\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Uklanjam vodeće „%s“ iz naziva članova" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Izbacujem %s podatke do: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "ne mogu da zapišem datoteku „%s“: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Ispisuje izdanje programa" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Opširniji ispis" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Pravi arhivu" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Izvlači sve datoteke" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Izbacuje rezervisane i posebne podatke" + +#: ../gcab.c:114 +msgid "List content" +msgstr "Ispisuje sadržaj" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "Ispisuje sadržaj sa pojedinostima datoteke" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "Prelazi u direktorijum DIR" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Koristi zip sažimanje" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Ne uključuje putanju" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Obezbeđuje prostor u kabinetu za potpis (npr. „-s 6144“ obezbeđuje 6K bajta)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "ULAZNE_DATOTEKE DATOTEKE..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "— napravite Kabinet datoteku" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Greške prijavite na <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gkab čuva zajedno mnogo datoteka u kabinet arhivi, i može da vrati\n" +"pojedinačne datoteke iz arhive." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "nije uspela obrada opcije: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Molim navedite jednu radnju." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "mora biti navedena kabinet datoteka." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "ne mogu da otvorim „%s“ za čitanje: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "greška čitanja „%s“: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "greška prilikom izvlačenja: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "greška prilikom čitanja potpisa: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "molim navedite ulazne datoteke." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Ne mogu da dodam datoteku „%s“: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "nema datoteka za arhiviranje." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "ne mogu da napravim kab datoteku „%s“: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "ne mogu da dodam fasciklu u kab datoteku„%s“: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "ne mogu da zapišem kab datoteku „%s“: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "nepodržan režim pakovanja „%d“" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "otkrivena je neispravna suma provere" diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000..81d6b6c --- /dev/null +++ b/po/sv.po @@ -0,0 +1,162 @@ +# Swedish translation for gcab. +# Copyright © 2013, 2015, 2018 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Kristoffer Grundström , 2013. +# Anders Jonsson , 2015, 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab.master-sv\n" +"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?" +"product=msitools&keywords=I18N+L10N&component=gcab\n" +"POT-Creation-Date: 2017-12-14 22:08+0000\n" +"PO-Revision-Date: 2018-01-04 02:10+0100\n" +"Last-Translator: Anders Jonsson \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.5\n" + +#: ../src/gcab.c:82 +msgid "Dumping data to:" +msgstr "Dumpar data till:" + +#: ../src/gcab.c:114 +msgid "Print program version" +msgstr "Skriv ut version på programmet" + +#: ../src/gcab.c:115 +msgid "Be verbose" +msgstr "Var informativ" + +#: ../src/gcab.c:116 +msgid "Create archive" +msgstr "Skapa arkiv" + +#: ../src/gcab.c:117 +msgid "Extract all files" +msgstr "Extrahera alla filer" + +#: ../src/gcab.c:118 +msgid "Dump reserved and extra data" +msgstr "Dumpa reserverad och extra data" + +#: ../src/gcab.c:119 +msgid "List content" +msgstr "Lista innehåll" + +#: ../src/gcab.c:120 +msgid "List content with file details" +msgstr "Lista innehåll med fildetaljer" + +#: ../src/gcab.c:121 +msgid "Change to directory DIR" +msgstr "Ändra till katalogen KAT" + +#: ../src/gcab.c:121 +msgid "DIR" +msgstr "KAT" + +#: ../src/gcab.c:122 +msgid "Use zip compression" +msgstr "Använd zip-komprimering" + +#: ../src/gcab.c:123 +msgid "Do not include path" +msgstr "Inkludera inte sökväg" + +#: ../src/gcab.c:124 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Reservera utrymme i kabinettet för signering (-s 6144 reserverar t.ex 6K " +"byte)" + +#: ../src/gcab.c:125 +msgid "FILE INPUT_FILES..." +msgstr "FIL INDATAFILER…" + +#: ../src/gcab.c:139 +msgid "- create a Cabinet file" +msgstr "- skapa en kabinettfil" + +#: ../src/gcab.c:140 +msgid "Report bugs to:" +msgstr "Rapportera fel till:" + +#: ../src/gcab.c:142 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab sparar många filer samtidigt till ett kabinettarkiv och kan " +"återställa\n" +"individuella filer från arkivet." + +#: ../src/gcab.c:149 +msgid "Option parsing failed" +msgstr "Tolkning av flaggor misslyckades" + +#: ../src/gcab.c:159 +msgid "Please specify a single operation" +msgstr "Ange en enstaka åtgärd" + +#: ../src/gcab.c:164 +msgid "Cabinet file must be specified" +msgstr "Kabinettfil måste anges" + +#: ../src/gcab.c:180 +msgid "Cannot open file for reading" +msgstr "Kan inte öppna fil för läsning" + +#: ../src/gcab.c:184 +msgid "Error reading" +msgstr "Fel vid läsning" + +#: ../src/gcab.c:220 +msgid "Error during extraction" +msgstr "Fel vid extrahering" + +#: ../src/gcab.c:235 +msgid "Error while reading signature" +msgstr "Fel vid läsning av signatur" + +#: ../src/gcab.c:247 +msgid "No input files specified" +msgstr "Inga indatafiler angivna" + +#: ../src/gcab.c:266 +msgid "Cannot add file" +msgstr "Kan inte lägga till fil" + +#: ../src/gcab.c:272 +msgid "No files to be archived" +msgstr "Inga filer att arkivera" + +#: ../src/gcab.c:280 +msgid "Cannot create cab file" +msgstr "Kan inte skapa cab-fil" + +#: ../src/gcab.c:286 +msgid "Cannot add folder to cab file" +msgstr "Kan inte lägga till mapp till cab-fil" + +#: ../src/gcab.c:296 +msgid "Cannot write cab file" +msgstr "Kan inte skriva cab-fil" + +#~ msgid "Removing leading '%s' from member names" +#~ msgstr "Tar bort ledande ”%s” från medlemsnamnen" + +#~ msgid "can't write file %s: %s" +#~ msgstr "kan inte skriva fil %s: %s" + +#~ msgid "please specify input files." +#~ msgstr "ange indatafiler." + +#~ msgid "unsupported compression method %d" +#~ msgstr "komprimeringsmetoden %d stöds inte" + +#~ msgid "incorrect checksum detected" +#~ msgstr "felaktig kontrollsumma upptäckt" diff --git a/po/tg.po b/po/tg.po new file mode 100644 index 0000000..7bea6a5 --- /dev/null +++ b/po/tg.po @@ -0,0 +1,170 @@ +# Tajik translation for gcab. +# Copyright (C) 2013 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Victor Ibragimov , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2013-03-24 21:58+0000\n" +"PO-Revision-Date: 2013-04-04 11:22+0500\n" +"Last-Translator: Victor Ibragimov \n" +"Language-Team: Tajik \n" +"Language: tg\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=1;\n" +"X-Generator: Poedit 1.5.4\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Тозакунии '%s' аз номҳои аъзо" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "Нусхабардории иттилооти %s ба: %s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "файли %s сабт карда намешавад: %s" + +#: ../gcab.c:108 +msgid "Print program version" +msgstr "Чоп кардани версияи барнома" + +#: ../gcab.c:109 +msgid "Be verbose" +msgstr "Ботафсил" + +#: ../gcab.c:110 +msgid "Create archive" +msgstr "Эҷод кардани бойгонӣ" + +#: ../gcab.c:111 +msgid "Extract all files" +msgstr "Баровардани ҳамаи файлҳо" + +#: ../gcab.c:112 +msgid "Dump reserved and extra data" +msgstr "Нусхабардории иттилооти ҳифзшуда ва иловагӣ" + +#: ../gcab.c:113 +msgid "List content" +msgstr "Рӯйхати мӯҳтаво" + +#: ../gcab.c:114 +msgid "Change to directory DIR" +msgstr "Тағйир додан ба директорияи DIR" + +#: ../gcab.c:114 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:115 +msgid "Use zip compression" +msgstr "Истифода бурдани фушурдани zip" + +#: ../gcab.c:116 +msgid "Do not include path" +msgstr "Масирро илова накунед" + +#: ../gcab.c:117 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "" +"Нигоҳ доштани фазо дар cab барои имзокунӣ (мисол -s 6144 тақрибан 6K байтро " +"захира мекунад)" + +#: ../gcab.c:118 +msgid "FILE INPUT_FILES..." +msgstr "ҚАЙДКУНИИ _ФАЙЛҲОИ ВУРУДӢ..." + +#: ../gcab.c:132 +msgid "- create a Cabinet file" +msgstr "- эҷод кардани файли CAB" + +#: ../gcab.c:133 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Гузоришдиҳии хатоҳо ба <%s>" + +#: ../gcab.c:136 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"Барномаи gcab бисёр файлҳоро ба бойгонии cab якҷоя захира мекунад, ва " +"метавонад\n" +"файлҳои алоҳидаро аз бойгонӣ барқарор кунад." + +#: ../gcab.c:143 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "таҷзияи интихобӣ қатъ шудааст: %s\n" + +#: ../gcab.c:152 +msgid "Please specify a single operation." +msgstr "Лутфан, кори ягонаро муайян кунед." + +#: ../gcab.c:155 +msgid "cabinet file must be specified." +msgstr "файли cab бояд муайян карда шавад." + +#: ../gcab.c:169 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "%s барои хониш кушода намешавад: %s\n" + +#: ../gcab.c:171 +#, c-format +msgid "error reading %s: %s\n" +msgstr "хатои хониши %s: %s\n" + +#: ../gcab.c:188 +#, c-format +msgid "error during extraction: %s" +msgstr "ҳангоми барориш хатогӣ ба вуҷуд омад: %s" + +#: ../gcab.c:200 +#, c-format +msgid "error while reading signature: %s" +msgstr "ҳангоми хониши имзо хатогӣ ба вуҷуд омад: %s" + +#: ../gcab.c:211 +msgid "please specify input files." +msgstr "лутфан, файлҳои вурудиро муайян кунед." + +#: ../gcab.c:229 +#, c-format +msgid "Can't add file %s: %s" +msgstr "Файли %s илова намешавад: %s" + +#: ../gcab.c:239 +msgid "no files to be archived." +msgstr "ягон файл бойгонӣ карда намешавад." + +#: ../gcab.c:245 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "файли cab-и %s эҷод карда намешавад: %s" + +#: ../gcab.c:249 +#, c-format +msgid "can't add folder to cabinet: %s" +msgstr "ҷузвдон ба cab илова намешавад: %s" + +#: ../gcab.c:257 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "файли cab-и %s сабт карда намешавад: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:453 +#, c-format +msgid "unsupported compression method %d" +msgstr "тарзи фушурдани нодурусти %d" diff --git a/po/tr.po b/po/tr.po new file mode 100644 index 0000000..1825fcf --- /dev/null +++ b/po/tr.po @@ -0,0 +1,176 @@ +# Turkish translation for gcab. +# Copyright (C) 2014 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Necdet Yücel , 2014. +# Muhammet Kara , 2014, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2015-08-25 20:08+0000\n" +"PO-Revision-Date: 2015-12-31 22:50+0200\n" +"Last-Translator: Muhammet Kara \n" +"Language-Team: Türkçe \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Gtranslator 2.91.7\n" +"X-POOTLE-MTIME: 1419291970.000000\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "Üye adlarının başındaki '%s' siliniyor" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "%s verileri şuraya boşaltılıyor: %s...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "%s dosyası yazılamıyor: %s" + +#: ../gcab.c:109 +msgid "Print program version" +msgstr "Program sürümünü yazdır" + +#: ../gcab.c:110 +msgid "Be verbose" +msgstr "Detaylı ol" + +#: ../gcab.c:111 +msgid "Create archive" +msgstr "Arşiv oluştur" + +#: ../gcab.c:112 +msgid "Extract all files" +msgstr "Tüm dosyaları çıkart" + +#: ../gcab.c:113 +msgid "Dump reserved and extra data" +msgstr "Ayrılmış ve ekstra veriyi dök" + +#: ../gcab.c:114 +msgid "List content" +msgstr "İçeriği listele" + +#: ../gcab.c:115 +msgid "List content with file details" +msgstr "İçeriği dosya ayrıntılarıyla birlikte listele" + +#: ../gcab.c:116 +msgid "Change to directory DIR" +msgstr "DİZİN klasörüne geç" + +#: ../gcab.c:116 +msgid "DIR" +msgstr "DİZİN" + +#: ../gcab.c:117 +msgid "Use zip compression" +msgstr "Zip sıkıştırma kullan" + +#: ../gcab.c:118 +msgid "Do not include path" +msgstr "Yolu dahil etme" + +#: ../gcab.c:119 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "İmzalamak için alan ayır (örneğin -s 6144, 6K bayt ayırır)" + +#: ../gcab.c:120 +msgid "FILE INPUT_FILES..." +msgstr "DOSYA GİRDİ_DOSYALARI..." + +#: ../gcab.c:134 +msgid "- create a Cabinet file" +msgstr "- bir Cabinet dosyası oluştur" + +#: ../gcab.c:135 +#, c-format +msgid "Report bugs to <%s>" +msgstr "Hataları şuraya bildirin: <%s>" + +#: ../gcab.c:138 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "" +"gcab bir çok dosyayı bir kabin arşivine kaydeder ve bu arşivden\n" +"tekil dosyaları geri yükleyebilir." + +#: ../gcab.c:145 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "seçenek ayrıştırma başarısız oldu: %s\n" + +#: ../gcab.c:154 +msgid "Please specify a single operation." +msgstr "Lütfen tek bir işlem belirtin." + +#: ../gcab.c:157 +msgid "cabinet file must be specified." +msgstr "kabin dosyası belirtilmelidir." + +#: ../gcab.c:171 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "%s okuma için açılamıyor: %s\n" + +#: ../gcab.c:173 +#, c-format +msgid "error reading %s: %s\n" +msgstr "%s okuma hatası: %s\n" + +#: ../gcab.c:208 +#, c-format +msgid "error during extraction: %s" +msgstr "çıkartma sırasında hata oluştu: %s" + +#: ../gcab.c:220 +#, c-format +msgid "error while reading signature: %s" +msgstr "imza okunurken hata oluştu: %s" + +#: ../gcab.c:231 +msgid "please specify input files." +msgstr "Lütfen girdi dosyalarını belirtin." + +#: ../gcab.c:249 +#, c-format +msgid "Can't add file %s: %s" +msgstr "%s dosyası eklenemiyor: %s" + +#: ../gcab.c:259 +msgid "no files to be archived." +msgstr "arşivlenecek dosya yok." + +#: ../gcab.c:265 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "cab dosyası %s oluşturulamıyor: %s" + +#: ../gcab.c:269 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "cab dosyası %s'e klasör eklenemiyor: %s" + +#: ../gcab.c:277 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "cab dosyası %s yazılamıyor: %s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:468 +#, c-format +msgid "unsupported compression method %d" +msgstr "desteklenmeyen sıkıştırma yöntemi %d" + +#: ../libgcab/cabinet.c:482 +msgid "incorrect checksum detected" +msgstr "hatalı sağlama toplamı saptandı" diff --git a/po/zh_CN.po b/po/zh_CN.po new file mode 100644 index 0000000..af0d4f7 --- /dev/null +++ b/po/zh_CN.po @@ -0,0 +1,162 @@ +# Chinese (China) translation for gcab. +# Copyright (C) 2014 gcab's COPYRIGHT HOLDER +# This file is distributed under the same license as the gcab package. +# Wylmer Wang , 2014. +# +msgid "" +msgstr "" +"Project-Id-Version: gcab master\n" +"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" +"product=gcab&keywords=I18N+L10N&component=general\n" +"POT-Creation-Date: 2013-12-18 18:10+0000\n" +"PO-Revision-Date: 2014-01-05 15:17+0800\n" +"Last-Translator: Wylmer Wang \n" +"Language-Team: Chinese (Simplified) \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../gcab.c:62 +#, c-format +msgid "Removing leading '%s' from member names" +msgstr "正在移除成员名称开头的“%s”" + +#: ../gcab.c:74 +#, c-format +msgid "Dumping %s data to: %s ...\n" +msgstr "正在将 %s 数据转储到:%s ...\n" + +#: ../gcab.c:82 +#, c-format +msgid "can't write file %s: %s" +msgstr "无法写入文件 %s:%s" + +#: ../gcab.c:108 +msgid "Print program version" +msgstr "打印程序版本" + +#: ../gcab.c:109 +msgid "Be verbose" +msgstr "详尽模式" + +#: ../gcab.c:110 +msgid "Create archive" +msgstr "创建归档" + +#: ../gcab.c:111 +msgid "Extract all files" +msgstr "提取所有文件" + +#: ../gcab.c:112 +msgid "Dump reserved and extra data" +msgstr "转储保留和额外的数据" + +#: ../gcab.c:113 +msgid "List content" +msgstr "列出内容" + +#: ../gcab.c:114 +msgid "Change to directory DIR" +msgstr "切换到 DIR 目录" + +#: ../gcab.c:114 +msgid "DIR" +msgstr "DIR" + +#: ../gcab.c:115 +msgid "Use zip compression" +msgstr "使用 zip 压缩" + +#: ../gcab.c:116 +msgid "Do not include path" +msgstr "不包括路径" + +#: ../gcab.c:117 +msgid "Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)" +msgstr "在 cabinet 归档中预留签名空间(例如 -s 6144 会预留 6k 字节)" + +#: ../gcab.c:118 +msgid "FILE INPUT_FILES..." +msgstr "FILE INPUT_FILES..." + +#: ../gcab.c:132 +msgid "- create a Cabinet file" +msgstr "- 创建 Cabinet 归档文件" + +#: ../gcab.c:133 +#, c-format +msgid "Report bugs to <%s>" +msgstr "向 <%s> 报告问题" + +#: ../gcab.c:136 +msgid "" +"gcab saves many files together into a cabinet archive, and can restore\n" +"individual files from the archive." +msgstr "gcab 可以将多个文件保存为 cabinet 归档,及从归档中恢复单独的文件。" + +#: ../gcab.c:143 +#, c-format +msgid "option parsing failed: %s\n" +msgstr "解析选项失败:%s\n" + +#: ../gcab.c:152 +msgid "Please specify a single operation." +msgstr "请只指定一项操作。" + +#: ../gcab.c:155 +msgid "cabinet file must be specified." +msgstr "必须指定 cabinet 归档文件。" + +#: ../gcab.c:169 +#, c-format +msgid "can't open %s for reading: %s\n" +msgstr "无法打开 %s 进行读取:%s\n" + +#: ../gcab.c:171 +#, c-format +msgid "error reading %s: %s\n" +msgstr "读取 %s 出错:%s\n" + +#: ../gcab.c:188 +#, c-format +msgid "error during extraction: %s" +msgstr "提取时出错:%s" + +#: ../gcab.c:200 +#, c-format +msgid "error while reading signature: %s" +msgstr "读取签名时出错:%s" + +#: ../gcab.c:211 +msgid "please specify input files." +msgstr "请指定输入文件。" + +#: ../gcab.c:229 +#, c-format +msgid "Can't add file %s: %s" +msgstr "无法添加文件 %s:%s" + +#: ../gcab.c:239 +msgid "no files to be archived." +msgstr "没有要归档的文件。" + +#: ../gcab.c:245 +#, c-format +msgid "can't create cab file %s: %s" +msgstr "无法创建 cab 文件 %s:%s" + +#: ../gcab.c:249 +#, c-format +msgid "can't add folder to cab file %s: %s" +msgstr "无法向 cab 文件 %s 添加文件夹:%s" + +#: ../gcab.c:257 +#, c-format +msgid "can't write cab file %s: %s" +msgstr "无法写入 cab 文件 %s:%s" + +#: ../libgcab/cabinet.c:20 ../libgcab/cabinet.c:453 +#, c-format +msgid "unsupported compression method %d" +msgstr "不支持压缩方法 %d" diff --git a/src/gcab-bzero.c b/src/gcab-bzero.c new file mode 100644 index 0000000..eca4b89 --- /dev/null +++ b/src/gcab-bzero.c @@ -0,0 +1,101 @@ +/* + * LibGCab + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include + +int +main (int argc, char *argv[]) +{ + guint64 bufsz = 1024; + guint64 nfiles = 1; + g_autofree guint8 *buf = NULL; + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GCabFolder) folder = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) opfile = NULL; + g_autoptr(GOutputStream) ostream = NULL; + + /* check args */ + if (argc < 2) { + g_printerr ("Incorrect args, expected FILENAME [SIZE-IN-MB] [NR-FILES]\n"); + return EXIT_FAILURE; + } + + /* get size */ + if (argc > 2) { + bufsz = g_ascii_strtoull (argv[2], NULL, 10); + if (bufsz == 0) { + g_printerr ("Failed to parse base-10 integer: %s\n", argv[2]); + return EXIT_FAILURE; + } + } + bufsz *= 0x100000; + + /* get number of files */ + if (argc > 3) { + nfiles = g_ascii_strtoull (argv[3], NULL, 10); + if (nfiles == 0) { + g_printerr ("Failed to parse base-10 integer: %s\n", argv[3]); + return EXIT_FAILURE; + } + } + + /* create archive */ + cabinet = gcab_cabinet_new (); + folder = gcab_folder_new (GCAB_COMPRESSION_MSZIP); + if (!gcab_cabinet_add_folder (cabinet, folder, &error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + + /* allocate huge buffer */ + buf = g_malloc0 (bufsz); + bytes = g_bytes_new_take (g_steal_pointer (&buf), bufsz); + + /* add multiple files to the archive */ + for (guint64 i = 0; i < nfiles; i++) { + g_autofree gchar *name = g_strdup_printf ("%04x", (guint) i); + g_autoptr(GCabFile) file = gcab_file_new_with_bytes (name, bytes); + if (!gcab_folder_add_file (folder, file, FALSE, NULL, &error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + } + + /* save file */ + opfile = g_file_new_for_path (argv[1]); + ostream = G_OUTPUT_STREAM (g_file_replace (opfile, NULL, FALSE, + 0, NULL, &error)); + if (ostream == NULL) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + if (!gcab_cabinet_write_simple (cabinet, ostream, NULL, NULL, NULL, &error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + + /* success */ + return EXIT_SUCCESS; +} diff --git a/src/gcab-fuzz.c b/src/gcab-fuzz.c new file mode 100644 index 0000000..e66003d --- /dev/null +++ b/src/gcab-fuzz.c @@ -0,0 +1,82 @@ +/* + * LibGCab + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include + +static gboolean +_process_file (GFile *file, GError **error) +{ + GPtrArray *folders; + g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); + g_autoptr(GInputStream) in = NULL; + + /* load file */ + in = G_INPUT_STREAM (g_file_read (file, NULL, error)); + if (in == NULL) { + g_prefix_error (error, "Cannot open file: "); + return FALSE; + } + if (!gcab_cabinet_load (cabinet, in, NULL, error)) { + g_prefix_error (error, "Error reading: "); + return FALSE; + } + + /* print file list and extract to memory */ + folders = gcab_cabinet_get_folders (cabinet); + for (guint i = 0; i < folders->len; i++) { + GCabFolder *folder = GCAB_FOLDER (g_ptr_array_index (folders, i)); + g_autoptr(GSList) files = gcab_folder_get_files (folder); + for (GSList *l = files; l != NULL; l = l->next) + g_print ("%s\n", gcab_file_get_name (GCAB_FILE (l->data))); + } + if (!gcab_cabinet_extract (cabinet, NULL, NULL, NULL, NULL, NULL, error)) { + g_prefix_error (error, "Error during extraction: "); + return FALSE; + } + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + g_autoptr(GError) error = NULL; + + /* check args */ + if (argc < 2) { + g_printerr ("No input files specified\n"); + return EXIT_FAILURE; + } + + /* try to extract each file */ + g_setenv ("GCAB_SKIP_CHECKSUM", "1", FALSE); + for (gint i = 1; i < argc; i++) { + g_autoptr(GFile) file = g_file_new_for_commandline_arg (argv[i]); + if (!_process_file (file, &error)) { + g_printerr ("Failed to read %s: %s\n", argv[i], error->message); + return EXIT_FAILURE; + } + } + + /* success */ + return EXIT_SUCCESS; +} diff --git a/src/gcab.1.in b/src/gcab.1.in new file mode 100644 index 0000000..9bcef08 --- /dev/null +++ b/src/gcab.1.in @@ -0,0 +1,38 @@ +.TH GCAB "1" "December 2012" @PACKAGE_STRING@ +.SH NAME +gcab \- Program to create Microsoft cabinet (.cab) archives +.SH SYNOPSIS +.B gcab +[\fIOPTION\fR]... \fICABFILE\fR \fIFILES...\fR +.SH DESCRIPTION +.PP +Create the cabinet file CABFILE from the list of FILES. +.SH OPTIONS +.TP +\fB\-c, --create\fR +create a new cabinet archive +.TP +\fB\-x, --extract\fR +extract files from a cabinet archive +.TP +\fB\-t, --list\fR +list files of a cabinet archive +.TP +\fB\-n, --nopath\fR +create files without pathnames +.TP +\fB\-C, --directory DIR\fR +change or extract to directory DIR +.TP +\fB\-v, --verbose\fR +verbosely list files processed +.TP +\fB\-z, --zip\fR +use zip compression +.SH AUTHOR +Written by Marc-André Lureau . + +.SH "SEE ALSO" +.TP +\fBcabextract\fR(1) +program to extract files from Microsoft cabinet (.cab) archives diff --git a/src/gcab.c b/src/gcab.c new file mode 100644 index 0000000..2023fec --- /dev/null +++ b/src/gcab.c @@ -0,0 +1,301 @@ +/* + * LibGCab + * Copyright (c) 2012, Marc-André Lureau + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +int verbose = 0; + +static gboolean +file_callback (GCabFile *cabfile, gpointer data) +{ + GFile *file = gcab_file_get_file (cabfile); + GFile *cwd = G_FILE (data); + + if (!verbose) + return TRUE; + + if (file) { + g_autofree gchar *path = g_file_get_relative_path (cwd, file); + if (!path) + path = g_file_get_parse_name (file); + g_print ("%s\n", path); + } else { + g_print ("%s\n", gcab_file_get_name (cabfile)); + } + + return TRUE; +} + +static const gchar * +remove_leading_path (gchar *name) +{ + unsigned i; + + i = 0; + if (name[0] == G_DIR_SEPARATOR) + i = 1; + while (name[i] == '.' && name[i + 1] == '.' && name[i + 2] == G_DIR_SEPARATOR) + i += 3; + + if (i != 0) { + gchar c = name[i]; + + name[i] = '\0'; + g_debug ("removing leading '%s' from member names", name); + name[i] = c; + } + + return name + i; +} + +static gboolean +save_array_to_file (const GByteArray *array, const gchar *base, const gchar *suffix, GError **error) +{ + g_autofree gchar *resname = NULL; + g_autoptr(GFile) outputfile = NULL; + g_autoptr(GOutputStream) output = NULL; + resname = g_strdup_printf ("%s.%s", base, suffix); + g_print ("%s %s...", _("Dumping data to:"), resname); + outputfile = g_file_new_for_commandline_arg (resname); + output = G_OUTPUT_STREAM (g_file_replace (outputfile, NULL, FALSE, 0, NULL, error)); + if (output == NULL) { + g_prefix_error (error, "cannot write %s: ", resname); + return FALSE; + } + if (!g_output_stream_write_all (output, array->data, array->len, NULL, NULL, error)) { + g_prefix_error (error, "cannot write %s: ", resname); + return FALSE; + } + return TRUE; +} + +int +main (int argc, char *argv[]) +{ + g_autoptr(GError) error = NULL; + g_autoptr(GOptionContext) context = NULL; + + g_auto(GStrv) args = NULL; + g_autofree gchar *change = NULL; + gboolean version = FALSE; + gboolean nopath = FALSE; + gboolean space = FALSE; + gboolean compress = FALSE; + gboolean list = FALSE; + gboolean list_details = FALSE; + gboolean create = FALSE; + gboolean extract = FALSE; + gboolean dump_reserved = FALSE; + GOptionEntry entries[] = { + { "version", 0, 0, G_OPTION_ARG_NONE, &version, N_("Print program version"), NULL }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, N_("Be verbose"), NULL }, + { "create", 'c', 0, G_OPTION_ARG_NONE, &create, N_("Create archive"), NULL }, + { "extract", 'x', 0, G_OPTION_ARG_NONE, &extract, N_("Extract all files"), NULL }, + { "dump-reserved", 'D', 0, G_OPTION_ARG_NONE, &dump_reserved, N_("Dump reserved and extra data"), NULL }, + { "list", 't', 0, G_OPTION_ARG_NONE, &list, N_("List content"), NULL }, + { "list-details", 'l', 0, G_OPTION_ARG_NONE, &list_details, N_("List content with file details"), NULL }, + { "directory", 'C', 0, G_OPTION_ARG_FILENAME, &change, N_("Change to directory DIR"), N_("DIR") }, + { "zip", 'z', 0, G_OPTION_ARG_NONE, &compress, N_("Use zip compression"), NULL }, + { "nopath", 'n', 0, G_OPTION_ARG_NONE, &nopath, N_("Do not include path"), NULL }, + { "space", 's', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &space, N_("Reserve space in cabinet for signing (e.g. -s 6144 reserves 6K bytes)"), NULL }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("FILE INPUT_FILES...") }, + { NULL } + }; + + setlocale (LC_ALL, ""); + textdomain (GETTEXT_PACKAGE); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + +#if !GLIB_CHECK_VERSION(2,35,1) + g_type_init (); +#endif + g_set_prgname (PACKAGE_NAME); + + context = g_option_context_new (_("- create a Cabinet file")); + g_autofree gchar *s = g_strdup_printf ("%s %s", _("Report bugs to:"), PACKAGE_BUGREPORT); + g_option_context_set_description (context, s); + g_option_context_set_summary (context, _("\ +gcab saves many files together into a cabinet archive, and can restore\n\ +individual files from the archive.\ +")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_printerr ("%s: %s\n", _("Option parsing failed"), error->message); + return EXIT_FAILURE; + } + + if (version) { + g_printf (PACKAGE_STRING "\n"); + return 0; + } + + if ((list + extract + create + dump_reserved + list_details) != 1) { + g_printerr ("%s\n", _("Please specify a single operation")); + return EXIT_FAILURE; + } + + if (!args || args[0] == NULL) { + g_printerr ("%s\n", _("Cabinet file must be specified")); + return EXIT_FAILURE; + } + + g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); + g_autoptr(GCabFolder) folder = NULL; + g_autoptr(GCancellable) cancellable = g_cancellable_new (); + g_autoptr(GFile) cwd = NULL; + g_autoptr(GFile) outputfile = NULL; + g_autoptr(GOutputStream) output = NULL; + + if (list || list_details || extract || dump_reserved) { + g_autoptr(GFile) file = g_file_new_for_commandline_arg (args[0]); + g_autoptr(GInputStream) in = G_INPUT_STREAM (g_file_read (file, cancellable, &error)); + + if (in == NULL) { + g_printerr ("%s %s: %s\n", _("Cannot open file for reading"), args[0], error->message); + return EXIT_FAILURE; + } + if (!gcab_cabinet_load (cabinet, in, cancellable, &error)) { + g_printerr ("%s %s: %s\n", _("Error reading"), args[0], error->message); + return EXIT_FAILURE; + } + + if (list || list_details) { + GPtrArray *folders = gcab_cabinet_get_folders (cabinet); + for (guint i = 0; i < folders->len; i++) { + GSList *l; + g_autoptr(GSList) files = gcab_folder_get_files (g_ptr_array_index (folders, i)); + + for (l = files; l != NULL; l = l->next) { + if (list_details) { + gchar date[32]; + struct tm *tm; + GTimeVal tv = {0}; + + gcab_file_get_date (GCAB_FILE (l->data), &tv); + tm = localtime (&tv.tv_sec); + strftime (date, sizeof (date), "%Y-%m-%d %H:%M:%S", tm); + + g_print ("%s %u %s 0x%X\n", + gcab_file_get_name (GCAB_FILE (l->data)), + gcab_file_get_size (GCAB_FILE (l->data)), + date, + gcab_file_get_attributes (GCAB_FILE (l->data))); + } else { + g_print ("%s\n", gcab_file_get_name (GCAB_FILE (l->data))); + } + } + } + } else if (extract) { + g_autoptr(GFile) file2 = NULL; + if (change == NULL) + change = g_get_current_dir (); + file2 = g_file_new_for_path (change); + if (!gcab_cabinet_extract (cabinet, file2, file_callback, NULL, NULL, cancellable, &error)) { + g_printerr ("%s: %s\n", _("Error during extraction"), error->message); + return EXIT_FAILURE; + } + } else if (dump_reserved) { + g_autoptr(GByteArray) reserved = NULL; + g_object_get (cabinet, "reserved", &reserved, NULL); + if (reserved != NULL) { + if (!save_array_to_file (reserved, args[0], "header", &error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + } + + reserved = (GByteArray *)gcab_cabinet_get_signature (cabinet, cancellable, &error); + if (reserved == NULL) { + g_printerr ("%s: %s\n", _("Error while reading signature"), error->message); + return EXIT_FAILURE; + } + if (!save_array_to_file (reserved, args[0], "signature", &error)) { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; + } + + if (args[1] == NULL) { + g_printerr ("%s\n", _("No input files specified")); + return EXIT_FAILURE; + } + + if (space) { + g_autoptr(GByteArray) reserved = g_byte_array_sized_new (space); + g_byte_array_set_size (reserved, space); + g_object_set (cabinet, "reserved", reserved, NULL); + } + + folder = gcab_folder_new (compress ? GCAB_COMPRESSION_MSZIP : 0); + + for (gint i = 1; args[i]; i++) { + g_autoptr(GFile) file = g_file_new_for_commandline_arg (args[i]); + g_autofree gchar *name = nopath ? g_path_get_basename (args[i]) : g_strdup (args[i]); + g_autoptr(GCabFile) cabfile = gcab_file_new_with_file ( + remove_leading_path (name), file); + + if (!gcab_folder_add_file (folder, cabfile, TRUE, NULL, &error)) { + g_warning ("%s %s: %s", _("Cannot add file"), args[i], error->message); + g_clear_error (&error); + } + } + + if (gcab_folder_get_nfiles (folder) == 0) { + g_printerr ("%s\n", _("No files to be archived")); + return EXIT_FAILURE; + } + + outputfile = g_file_new_for_commandline_arg (args[0]); + output = G_OUTPUT_STREAM (g_file_replace (outputfile, NULL, FALSE, + 0, NULL, &error)); + if (output == NULL) { + g_printerr ("%s %s: %s\n", _("Cannot create cab file"), args[0], error->message); + return EXIT_FAILURE; + } + + cwd = g_file_new_for_commandline_arg ("."); + if (!gcab_cabinet_add_folder (cabinet, folder, &error)) { + g_printerr ("%s %s: %s\n", _("Cannot add folder to cab file"), args[0], error->message); + return EXIT_FAILURE; + } + + if (!gcab_cabinet_write (cabinet, output, + file_callback, + NULL, + cwd, + NULL, + &error)) { + g_printerr ("%s %s: %s\n", _("Cannot write cab file"), args[0], error->message); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..4149fbc --- /dev/null +++ b/src/meson.build @@ -0,0 +1,63 @@ +configure_file( + input : 'gcab.1.in', + output : 'gcab.1', + configuration : conf, + install : true, + install_dir : join_paths(get_option('mandir'), 'man1'), +) + +executable( + 'gcab', + sources : [ + 'gcab.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libgcab'), + ], + dependencies : [ + gio, + ], + link_with : [ + libgcab, + ], + c_args : cargs, + install : true, + install_dir : get_option('bindir') +) + +executable( + 'gcab-fuzz', + sources : [ + 'gcab-fuzz.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libgcab'), + ], + dependencies : [ + gio, + ], + link_with : [ + libgcab, + ], + c_args : cargs, +) + +executable( + 'gcab-bzero', + sources : [ + 'gcab-bzero.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libgcab'), + ], + dependencies : [ + gio, + ], + link_with : [ + libgcab, + ], + c_args : cargs, +) diff --git a/tests/CVE-2014-9556.cab b/tests/CVE-2014-9556.cab new file mode 100644 index 0000000..94e0fcd Binary files /dev/null and b/tests/CVE-2014-9556.cab differ diff --git a/tests/CVE-2014-9732.cab b/tests/CVE-2014-9732.cab new file mode 100644 index 0000000..1f42eea Binary files /dev/null and b/tests/CVE-2014-9732.cab differ diff --git a/tests/CVE-2015-4470.cab b/tests/CVE-2015-4470.cab new file mode 100644 index 0000000..5e2cb32 Binary files /dev/null and b/tests/CVE-2015-4470.cab differ diff --git a/tests/CVE-2015-4471.cab b/tests/CVE-2015-4471.cab new file mode 100644 index 0000000..bd6f25b Binary files /dev/null and b/tests/CVE-2015-4471.cab differ diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..6b97bec --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,18 @@ +all: test-none.cab test-mszip.cab test-signed.cab + +test-none.cab: src/test.sh src/test.txt + touch -t 201709150000 src/test.sh src/test.txt & + gcab --create --nopath $@ src/test.sh src/test.txt + +test-mszip.cab: src/test.sh src/test.txt + gcab --create --nopath --zip $@ src/test.sh src/test.txt + +privkey.pem: + certtool --generate-privkey --outfile $@ + +test-signed.cab: privkey.pem test-none.cab + osslsigncode sign -certs /etc/pki/fwupd/LVFS-CA.pem \ + -key privkey.pem \ + -n "Test Firmware" -i https://fwupd.org/ \ + -jp low \ + -in test-none.cab -out test-signed.cab diff --git a/tests/gcab-self-test.c b/tests/gcab-self-test.c new file mode 100644 index 0000000..aee690b --- /dev/null +++ b/tests/gcab-self-test.c @@ -0,0 +1,610 @@ +/* + * LibGCab + * Copyright (c) 2017, Richard Hughes + * + * This 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. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include +#include + +#include + +static gchar * +gcab_test_get_filename (const gchar *filename) +{ + gchar *tmp; + char full_tmp[PATH_MAX]; + g_autofree gchar *path = NULL; + path = g_build_filename (TESTDATADIR, filename, NULL); + tmp = realpath (path, full_tmp); + if (tmp != NULL) + return g_strdup (full_tmp); + return NULL; +} + +static void +gcab_test_file_func (void) +{ + gboolean ret; + GTimeVal tv; + g_autofree gchar *fn = NULL; + g_autoptr(GCabFile) cabfile = NULL; + g_autoptr(GDateTime) dt = NULL; + g_autoptr(GFile) gfile = NULL; + g_autoptr(GDateTime) dt_bday = NULL; + + /* create object */ + fn = gcab_test_get_filename ("src/test.sh"); + g_assert (fn != NULL); + gfile = g_file_new_for_path (fn); + cabfile = gcab_file_new_with_file ("tæst.bin", gfile); + g_assert (cabfile != NULL); + + /* set the time */ + dt_bday = g_date_time_new_utc (2017, 9, 15, 0, 0, 0.f); + ret = g_date_time_to_timeval (dt_bday, &tv); + g_assert (ret); + gcab_file_set_date (cabfile, &tv); + + /* verify */ + g_assert (gcab_file_get_file (cabfile) == gfile); + g_assert_cmpstr (gcab_file_get_name (cabfile), ==, "tæst.bin"); + g_assert_cmpstr (gcab_file_get_extract_name (cabfile), ==, "tæst.bin"); + g_assert_cmpint (gcab_file_get_size (cabfile), ==, 0); + g_assert_cmpint (gcab_file_get_attributes (cabfile), ==, 0); + ret = gcab_file_get_date (cabfile, &tv); + g_assert (ret); + dt = g_date_time_new_from_timeval_utc (&tv); + g_assert_cmpint (g_date_time_get_year (dt), ==, 2017); + g_assert_cmpint (g_date_time_get_month (dt), ==, 9); + g_assert_cmpint (g_date_time_get_day_of_month (dt), ==, 15); + g_assert_cmpint (g_date_time_get_hour (dt), ==, 0); + g_assert_cmpint (g_date_time_get_minute (dt), ==, 0); + g_assert_cmpint (g_date_time_get_second (dt), ==, 0); + + /* test changing the extraction name */ + gcab_file_set_extract_name (cabfile, "new.bin"); + g_assert_cmpstr (gcab_file_get_extract_name (cabfile), ==, "new.bin"); + g_assert_cmpstr (gcab_file_get_name (cabfile), ==, "tæst.bin"); +} + +static void +gcab_test_folder_func (void) +{ + GCabFile *cabfile_tmp; + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(GCabFile) cabfile2 = NULL; + g_autoptr(GCabFile) cabfile = NULL; + g_autoptr(GCabFolder) cabfolder = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) gfile = NULL; + g_autoptr(GSList) cabfiles = NULL; + + /* create GCabFile */ + fn = gcab_test_get_filename ("test-none.cab"); + g_assert (fn != NULL); + gfile = g_file_new_for_path (fn); + cabfile = gcab_file_new_with_file ("test.bin", gfile); + + /* add single file */ + cabfolder = gcab_folder_new (GCAB_COMPRESSION_NONE); + ret = gcab_folder_add_file (cabfolder, cabfile, FALSE, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (gcab_folder_get_nfiles (cabfolder), ==, 1); + cabfiles = gcab_folder_get_files (cabfolder); + cabfile_tmp = GCAB_FILE (cabfiles->data); + g_assert (cabfile_tmp == cabfile); + g_assert_cmpstr (gcab_file_get_name (cabfile_tmp), ==, "test.bin"); + + /* add it again */ + cabfile2 = gcab_file_new_with_file ("test.bin", gfile); + ret = gcab_folder_add_file (cabfolder, cabfile2, FALSE, NULL, &error); + g_assert_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT); + g_assert (!ret); + + /* find using the hash table */ + cabfile_tmp = gcab_folder_get_file_by_name (cabfolder, "test.bin"); + g_assert_nonnull (cabfile_tmp); + cabfile_tmp = gcab_folder_get_file_by_name (cabfolder, "notgoingtoexist"); + g_assert_null (cabfile_tmp); + + /* find the extracted name too */ + cabfile_tmp = gcab_folder_get_file_by_name (cabfolder, "test.bin"); + gcab_file_set_extract_name (cabfile_tmp, "LVFS-test.bin"); + cabfile_tmp = gcab_folder_get_file_by_name (cabfolder, "LVFS-test.bin"); + g_assert_nonnull (cabfile_tmp); +} + +static void +gcab_test_folder_path_func (void) +{ + GCabFile *cabfile_tmp; + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(GCabFile) cabfile = NULL; + g_autoptr(GCabFolder) cabfolder = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) gfile = NULL; + g_autoptr(GSList) cabfiles = NULL; + + /* create GCabFile of a path */ + fn = gcab_test_get_filename ("src"); + g_assert (fn != NULL); + gfile = g_file_new_for_path (fn); + cabfile = gcab_file_new_with_file ("dirname", gfile); + + /* add entire subdir */ + cabfolder = gcab_folder_new (GCAB_COMPRESSION_NONE); + ret = gcab_folder_add_file (cabfolder, cabfile, TRUE, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (gcab_folder_get_nfiles (cabfolder), ==, 2); + cabfiles = gcab_folder_get_files (cabfolder); + cabfile_tmp = GCAB_FILE (cabfiles->data); + g_assert (cabfile_tmp != cabfile); + g_assert_cmpstr (gcab_file_get_name (cabfile_tmp), ==, "dirname\\test.txt"); + g_assert_cmpstr (gcab_file_get_extract_name (cabfile_tmp), ==, "dirname\\test.txt"); + + /* add it again */ + ret = gcab_folder_add_file (cabfolder, cabfile, TRUE, NULL, &error); + g_assert_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT); + g_assert (!ret); +} + +static void +gcab_test_cabinet_error_not_loaded_func (void) +{ + gboolean ret; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + + /* we can't extract before loading */ + cabinet = gcab_cabinet_new (); + file = g_file_new_for_path ("/tmp"); + ret = gcab_cabinet_extract_simple(cabinet, file, NULL, NULL, NULL, &error); + g_assert_error (error, GCAB_ERROR, GCAB_ERROR_FAILED); + g_assert (!ret); +} + +static void +gcab_test_cabinet_error_no_folders_func (void) +{ + gboolean ret; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GOutputStream) op = NULL; + + /* we can't write with no folders */ + cabinet = gcab_cabinet_new (); + file = g_file_new_for_path ("/tmp/foo.cab"); + op = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, 0, NULL, &error)); + g_assert_no_error (error); + g_assert (op != NULL); + ret = gcab_cabinet_write_simple (cabinet, op, NULL, NULL, NULL, &error); + g_assert_error (error, GCAB_ERROR, GCAB_ERROR_FAILED); + g_assert (!ret); +} + +static void +gcab_test_cabinet_func (void) +{ + GPtrArray *cabfolders; + gboolean ret; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GCabFolder) folder = NULL; + g_autoptr(GError) error = NULL; + + /* create cabinet */ + cabinet = gcab_cabinet_new (); + g_assert_cmpint (gcab_cabinet_get_size (cabinet), ==, 0); + + /* add folder */ + folder = gcab_folder_new (GCAB_COMPRESSION_NONE); + ret = gcab_cabinet_add_folder (cabinet, folder, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add folder again */ + ret = gcab_cabinet_add_folder (cabinet, folder, &error); + g_assert_error (error, GCAB_ERROR, GCAB_ERROR_FORMAT); + g_assert (!ret); + cabfolders = gcab_cabinet_get_folders (cabinet); + g_assert_cmpint (cabfolders->len, ==, 1); +} + +static void +gcab_test_cabinet_error_not_seekable_func (void) +{ + const GByteArray *signature; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GError) error = NULL; + + /* verify it has no signature */ + cabinet = gcab_cabinet_new (); + signature = gcab_cabinet_get_signature (cabinet, NULL, &error); + g_assert_error (error, GCAB_ERROR, GCAB_ERROR_NOT_SUPPORTED); + g_assert (signature == NULL); +} + +static gchar * +_compute_checksum_for_file (GFile *file, GError **error) +{ + g_autoptr(GBytes) blob = NULL; + g_autoptr(GInputStream) in = NULL; + in = G_INPUT_STREAM (g_file_read (file, NULL, error)); + if (in == NULL) + return NULL; + blob = g_input_stream_read_bytes (in, 1024, NULL, error); + if (blob == NULL) + return NULL; + return g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); +} + +static void +gcab_test_cabinet_blob_func (void) +{ + gboolean ret; + g_autoptr(GError) error = NULL; + g_autoptr(GCabCabinet) cabinet = gcab_cabinet_new (); + + /* create folder and add to cabinet */ + g_autoptr(GCabFolder) folder = gcab_folder_new (GCAB_COMPRESSION_NONE); + ret = gcab_cabinet_add_folder (cabinet, folder, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add the two files */ + struct { + const gchar *fn; + const gchar *contents; + } files[] = { + { "test.sh", "echo ola\n" }, + { "test.txt", "Ola!\n" }, + { NULL, NULL } + }; + for (guint i = 0; files[i].fn != NULL; i++) { + g_autoptr(GBytes) bytes_tmp = g_bytes_new_static (files[i].contents, + strlen (files[i].contents)); + g_autoptr(GCabFile) cabfile = gcab_file_new_with_bytes (files[i].fn, bytes_tmp); + + /* set the time and attributes */ + g_autoptr(GDateTime) dt = dt = g_date_time_new_utc (2017, 9, 15, 0, 0, 0.f); + GTimeVal tv; + ret = g_date_time_to_timeval (dt, &tv); + g_assert (ret); + gcab_file_set_date (cabfile, &tv); + gcab_file_set_attributes (cabfile, GCAB_FILE_ATTRIBUTE_ARCH); + + /* add file to folder */ + ret = gcab_folder_add_file (folder, cabfile, FALSE, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + } + + /* write to a blob */ + g_autoptr(GOutputStream) op = g_memory_output_stream_new_resizable (); + ret = gcab_cabinet_write_simple (cabinet, op, NULL, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* get what the checksum is supposed to be */ + g_autofree gchar *fn = gcab_test_get_filename ("test-none.cab"); + g_assert (fn != NULL); + g_autoptr(GFile) file = g_file_new_for_path (fn); + g_assert (file != NULL); + g_autofree gchar *checksum = _compute_checksum_for_file (file, &error); + g_assert_no_error (error); + g_assert (checksum != NULL); + + /* write for debugging */ + ret = g_output_stream_close (op, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + g_autoptr(GBytes) blob = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (op)); + ret = g_file_set_contents ("/tmp/test-none.cab", g_bytes_get_data (blob, NULL), g_bytes_get_size (blob), &error); + g_assert_no_error (error); + g_assert (ret); + + /* verify the checksum */ + g_autofree gchar *csum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + g_assert_cmpstr (csum, ==, checksum); +} + +static void +gcab_test_cabinet_load_func (void) +{ + struct { + const gchar *fn; + guint32 size; + GCabCompression comptype; + } tests[] = { + { "test-none.cab", 115, GCAB_COMPRESSION_NONE }, + { "test-mszip.cab", 119, GCAB_COMPRESSION_MSZIP }, + { "test-signed.cab", 139, GCAB_COMPRESSION_NONE }, + { NULL, 0, 0 } + }; + + for (guint i = 0; tests[i].fn != NULL; i++) { + GCabFolder *cabfolder_tmp; + GPtrArray *cabfolders; + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFile) file_tmpdir = NULL; + g_autoptr(GInputStream) in = NULL; + struct { + const gchar *fn; + const gchar *checksum; + } files[] = { + { "test.sh", "82b4415cf30efc9b5877e366475d652f263c0ced" }, + { "test.txt", "decc67ff4a11acd93430cbb18c7bbddd00abf4fa" }, + { NULL, NULL } + }; + + /* read file */ + g_print ("%s... ", tests[i].fn); + fn = gcab_test_get_filename (tests[i].fn); + g_assert (fn != NULL); + file = g_file_new_for_path (fn); + in = G_INPUT_STREAM (g_file_read (file, NULL, &error)); + g_assert_no_error (error); + g_assert (in != NULL); + cabinet = gcab_cabinet_new (); + ret = gcab_cabinet_load (cabinet, in, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check size */ + g_assert_cmpint (gcab_cabinet_get_size (cabinet), ==, tests[i].size); + + cabfolders = gcab_cabinet_get_folders (cabinet); + g_assert (cabfolders != NULL); + g_assert_cmpint (cabfolders->len, ==, 1); + cabfolder_tmp = g_ptr_array_index (cabfolders, 0); + g_assert_cmpint (gcab_folder_get_comptype (cabfolder_tmp), ==, tests[i].comptype); + + g_autoptr(GSList) cabfiles = gcab_folder_get_files (cabfolder_tmp); + for (GSList *l = cabfiles; l != NULL; l = l->next) { + GCabFile *cabfile = GCAB_FILE (l->data); + g_assert_null (gcab_file_get_file (cabfile)); + g_assert_null (gcab_file_get_bytes (cabfile)); + g_assert_cmpint (gcab_file_get_attributes (cabfile), ==, GCAB_FILE_ATTRIBUTE_ARCH); + } + + file_tmpdir = g_file_new_for_path ("/tmp"); + ret = gcab_cabinet_extract_simple (cabinet, file_tmpdir, NULL, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check files were decompressed okay */ + for (guint j = 0; files[j].fn != NULL; j++) { + g_autofree gchar *fn_src = g_build_filename ("/tmp", files[j].fn, NULL); + g_autoptr(GFile) file_dst = g_file_new_for_path (fn_src); + g_autofree gchar *csum = _compute_checksum_for_file (file_dst, &error); + g_assert_no_error (error); + g_assert (csum != NULL); + g_assert_cmpstr (csum, ==, files[j].checksum); + } + + /* extract again to a memory blob on each GCabFile */ + ret = gcab_cabinet_extract_simple (cabinet, NULL, NULL, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check each blob checksum */ + for (guint j = 0; files[j].fn != NULL; j++) { + GCabFile *cabfile = gcab_folder_get_file_by_name (cabfolder_tmp, files[j].fn); + g_assert_nonnull (cabfile); + GBytes *blob = gcab_file_get_bytes (cabfile); + g_assert_nonnull (blob); + g_autofree gchar *csum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA1, blob); + g_assert_cmpstr (csum, ==, files[j].checksum); + } + } +} + +static void +gcab_test_cabinet_error_cves_func (void) +{ + const gchar *tests[] = { + "CVE-2014-9556.cab", + "CVE-2014-9732.cab", + "CVE-2015-4470.cab", + "CVE-2015-4471.cab", + NULL }; + g_setenv ("GCAB_SKIP_CHECKSUM", "1", TRUE); + for (guint i = 0; tests[i] != NULL; i++) { + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GFile) file_tmpdir = NULL; + g_autoptr(GInputStream) in = NULL; + + /* read file */ + g_print ("%s... ", tests[i]); + fn = gcab_test_get_filename (tests[i]); + g_assert (fn != NULL); + file = g_file_new_for_path (fn); + in = G_INPUT_STREAM (g_file_read (file, NULL, &error)); + g_assert_no_error (error); + g_assert (in != NULL); + cabinet = gcab_cabinet_new (); + ret = gcab_cabinet_load (cabinet, in, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + file_tmpdir = g_file_new_for_path ("/tmp"); + ret = gcab_cabinet_extract_simple (cabinet, file_tmpdir, NULL, NULL, NULL, &error); + g_assert (error != NULL); + g_assert (!ret); + } + g_unsetenv ("GCAB_SKIP_CHECKSUM"); +} + +static void +gcab_test_cabinet_signature_func (void) +{ + const GByteArray *sig; + gboolean ret; + g_autofree gchar *fn = NULL; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + g_autoptr(GInputStream) in = NULL; + + /* load file */ + fn = gcab_test_get_filename ("test-signed.cab"); + g_assert (fn != NULL); + file = g_file_new_for_path (fn); + in = G_INPUT_STREAM (g_file_read (file, NULL, &error)); + g_assert_no_error (error); + g_assert (in != NULL); + cabinet = gcab_cabinet_new (); + ret = gcab_cabinet_load (cabinet, in, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* get signature */ + sig = gcab_cabinet_get_signature (cabinet, NULL, &error); + g_assert_no_error (error); + g_assert (sig != NULL); + g_assert_cmpint (sig->len, ==, 2040); +} + +static void +gcab_test_cabinet_write_func (void) +{ + struct { + const gchar *fn; + guint32 size; + GCabCompression comptype; + } tests[] = { + { "test-none.cab", 115, GCAB_COMPRESSION_NONE }, + { "test-mszip.cab", 119, GCAB_COMPRESSION_MSZIP }, + { NULL, 0, 0 } + }; + + for (guint i = 0; tests[i].fn != NULL; i++) { + gboolean ret; + g_autofree gchar *checksum_in = NULL; + g_autofree gchar *checksum_out = NULL; + g_autofree gchar *fn_in = NULL; + g_autofree gchar *fn_out = NULL; + g_autoptr(GCabCabinet) cabinet = NULL; + g_autoptr(GCabFolder) cabfolder = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file_in = NULL; + g_autoptr(GFile) file_out = NULL; + g_autoptr(GOutputStream) op = NULL; + struct { + const gchar *fn; + const gchar *checksum; + } files[] = { + { "test.sh", "82b4415cf30efc9b5877e366475d652f263c0ced" }, + { "test.txt", "decc67ff4a11acd93430cbb18c7bbddd00abf4fa" }, + { NULL, NULL } + }; + + /* create new cabinet with a single folder of the correct type */ + cabinet = gcab_cabinet_new (); + cabfolder = gcab_folder_new (tests[i].comptype); + ret = gcab_cabinet_add_folder (cabinet, cabfolder, &error); + g_assert_no_error (error); + g_assert (ret); + + /* add new files to a folder */ + for (guint j = 0; files[j].fn != NULL; j++) { + g_autofree gchar *fn_src = g_build_filename ("src", files[j].fn, NULL); + g_autofree gchar *fn_tmp = gcab_test_get_filename (fn_src); + g_autoptr(GFile) file = g_file_new_for_path (fn_tmp); + g_autoptr(GCabFile) cabfile = gcab_file_new_with_file (files[j].fn, file); + g_autoptr(GDateTime) dt = NULL; + GTimeVal tv; + + /* set the time so the checksums match */ + dt = g_date_time_new_utc (2017, 9, 15, 0, 0, 0.f); + ret = g_date_time_to_timeval (dt, &tv); + g_assert (ret); + gcab_file_set_date (cabfile, &tv); + + ret = gcab_folder_add_file (cabfolder, cabfile, FALSE, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + } + + /* write the file */ + g_print ("%s... ", tests[i].fn); + fn_out = g_build_filename ("/tmp", tests[i].fn, NULL); + file_out = g_file_new_for_path (fn_out); + op = G_OUTPUT_STREAM (g_file_replace (file_out, NULL, FALSE, 0, NULL, &error)); + g_assert_no_error (error); + g_assert (op != NULL); + ret = gcab_cabinet_write_simple (cabinet, op, NULL, NULL, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + + /* check size */ + g_assert_cmpint (gcab_cabinet_get_size (cabinet), ==, tests[i].size); + + /* compare checksums */ + fn_in = gcab_test_get_filename (tests[i].fn); + g_assert (fn_in != NULL); + file_in = g_file_new_for_path (fn_in); + checksum_in = _compute_checksum_for_file (file_in, &error); + g_assert_no_error (error); + g_assert (checksum_in != NULL); + checksum_out = _compute_checksum_for_file (file_out, &error); + g_assert_no_error (error); + g_assert (checksum_out != NULL); + g_assert_cmpstr (checksum_in, ==, checksum_out); + } +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/GCab/file", gcab_test_file_func); + g_test_add_func ("/GCab/folder", gcab_test_folder_func); + g_test_add_func ("/GCab/folder{path}", gcab_test_folder_path_func); + g_test_add_func ("/GCab/cabinet", gcab_test_cabinet_func); + g_test_add_func ("/GCab/cabinet{error-not-seekable}", gcab_test_cabinet_error_not_seekable_func); + g_test_add_func ("/GCab/cabinet{error-not-loaded}", gcab_test_cabinet_error_not_loaded_func); + g_test_add_func ("/GCab/cabinet{error-no-folders}", gcab_test_cabinet_error_no_folders_func); + g_test_add_func ("/GCab/cabinet{error-cves}", gcab_test_cabinet_error_cves_func); + g_test_add_func ("/GCab/cabinet{load}", gcab_test_cabinet_load_func); + g_test_add_func ("/GCab/cabinet{write}", gcab_test_cabinet_write_func); + g_test_add_func ("/GCab/cabinet{blob}", gcab_test_cabinet_blob_func); + g_test_add_func ("/GCab/cabinet{signature}", gcab_test_cabinet_signature_func); + return g_test_run (); +} diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..d9be63c --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,20 @@ +e = executable( + 'gcab-self-test', + sources : [ + 'gcab-self-test.c', + ], + include_directories : [ + include_directories('..'), + include_directories('../libgcab'), + ], + c_args : [ + '-D_XOPEN_SOURCE=500', + ], + dependencies : [ + gio, + ], + link_with : [ + libgcab, + ], +) +test('gcab-self-test', e) diff --git a/tests/privkey.pem b/tests/privkey.pem new file mode 100644 index 0000000..453da42 --- /dev/null +++ b/tests/privkey.pem @@ -0,0 +1,182 @@ +Public Key Info: + Public Key Algorithm: RSA + Key Security Level: High (3072 bits) + +modulus: + 00:c0:d5:5c:1d:6c:d9:8b:98:7a:64:07:72:6c:0d:58 + 62:7f:e1:f3:eb:d5:c7:07:7d:f5:21:f4:61:eb:ad:26 + b4:76:de:e8:9c:97:58:19:17:20:57:0b:bd:e2:0a:f5 + 74:0b:a0:b2:f2:1b:74:f2:25:a5:ae:9e:7e:8e:60:3c + 8a:2a:df:06:52:62:c2:26:8c:86:e9:fe:fb:91:bf:1c + 69:da:65:5a:a3:7c:ee:09:f7:62:a9:da:70:75:b2:2c + 71:9b:df:53:c5:55:ea:ee:89:f2:82:f7:c0:96:f3:40 + 02:84:38:75:4d:52:fd:e8:91:00:27:5f:b1:a5:ec:b3 + dc:35:b0:80:e8:9e:ef:2d:47:3c:31:ce:a8:ff:9a:ef + 10:2e:f3:60:7e:6f:e0:62:8a:bc:8c:a9:97:ed:91:a8 + a7:4d:91:62:46:39:23:ad:e8:9e:f0:37:21:a9:78:c8 + 63:41:f1:37:da:03:a7:68:d2:3a:fe:b0:4c:b3:f5:b6 + f1:f2:a9:6c:e6:51:ac:11:bb:b1:64:f9:09:8d:c4:00 + 9b:94:5a:9d:6d:ea:d7:87:e9:9c:c9:f2:40:b8:a0:67 + 94:29:88:a2:f8:5e:cb:c5:06:6b:9b:a0:20:37:d8:a8 + a6:cb:bb:29:31:31:48:85:33:89:ff:87:2c:b1:f4:96 + 8f:19:64:a0:87:c9:84:e6:d5:f7:e4:9c:11:f8:4f:a3 + 1e:47:9c:b5:5f:1e:f8:40:e0:ff:bb:5d:fb:93:3c:8a + c5:a7:0e:7a:50:4a:3d:9f:cd:ea:61:98:4d:d5:bd:ec + d3:57:0f:0c:21:c3:27:27:90:4b:d2:f9:80:c2:01:76 + 25:ab:0f:32:ad:97:65:bf:49:e1:73:db:c8:fd:8e:a4 + 18:fb:6e:0c:c6:32:4c:cb:7a:bb:79:5b:b2:f7:15:80 + f5:0c:bb:2c:34:ba:36:3a:47:a0:30:27:52:79:e7:ac + 07:52:af:a6:5b:88:03:df:90:4f:f0:12:f3:3f:d7:92 + f7: + +public exponent: + 01:00:01: + +private exponent: + 00:85:68:16:9e:54:db:fc:73:b4:d8:d7:3e:15:fa:f5 + 96:cf:9a:66:c2:55:d7:a8:1b:40:28:09:86:65:22:19 + 90:e8:5c:36:d9:7e:ea:f8:10:c3:d2:f4:d0:9d:3d:af + aa:65:10:fc:3b:fb:3a:e0:fb:a2:b0:37:fe:9e:49:7e + 18:a8:a8:3b:1b:6c:2f:9d:b3:c2:f2:c7:f1:0b:58:08 + 34:43:5f:b3:61:3f:e0:ff:0c:23:3a:17:61:8e:4b:81 + eb:e7:46:8e:12:0b:ea:c8:b4:af:0e:64:90:dc:dd:d4 + fe:e8:b2:96:94:b4:41:ed:4f:c3:a7:79:d0:d1:55:fc + e8:f0:4b:f8:22:f7:31:c9:45:6b:23:9a:31:d9:04:3b + 38:1b:03:4d:52:ab:db:b4:d0:fe:b8:e1:eb:b5:f3:fb + 96:23:57:dd:81:6f:ae:7b:76:5f:df:18:85:35:55:d6 + 6c:b5:06:48:f9:8f:65:96:63:3b:65:50:5b:00:75:91 + e6:85:df:b6:f6:37:9e:89:27:6e:41:b3:37:66:85:e1 + 12:f1:b4:5f:1e:32:b1:0e:ba:ac:8e:42:65:46:ab:73 + 38:df:b8:ec:62:d9:15:f8:a3:22:35:6d:20:16:5b:1e + c8:35:48:5b:10:b5:ec:69:42:66:68:ad:79:ad:43:46 + 57:52:63:77:a7:3b:51:53:49:b1:a5:c5:95:fd:c0:65 + f7:89:5d:8e:38:dd:e9:9a:1c:cb:34:75:77:0d:42:b7 + c5:77:e3:e1:16:c0:b8:67:bd:51:6e:bb:95:a3:38:0b + 6a:7c:17:c5:60:91:df:a9:39:96:2a:17:c8:97:82:a5 + f1:46:ab:9c:47:5c:e6:cc:39:d5:3d:6a:23:74:88:07 + d9:c3:49:8d:10:65:cf:42:7b:3e:b3:be:76:3b:57:bd + d8:7e:d8:c2:ac:c3:66:02:fc:9e:cc:d4:b6:a7:83:ed + 30:8e:c3:3d:90:0a:9c:b8:a0:6c:90:19:56:46:13:d3 + 61: + +prime1: + 00:e1:c0:f0:3d:66:0a:43:71:0b:6d:94:b8:d0:93:f2 + 06:66:21:7c:56:53:ad:02:5e:aa:e9:34:28:11:af:bd + 79:05:ac:2f:05:e1:9d:cf:47:83:a2:46:d8:76:66:3d + f6:48:15:15:e2:cf:fb:e5:35:1d:45:5d:e3:7f:33:4e + de:33:0f:52:af:00:0c:7f:de:13:20:e6:24:9d:71:6c + 2d:3f:e8:1d:3b:82:74:69:fa:fa:3e:ff:5c:0b:2c:22 + 49:f1:fe:b1:6f:41:a0:79:58:84:33:cc:28:3d:59:87 + 41:91:4f:15:cd:26:92:07:d5:b4:92:9f:fc:2c:9c:e0 + 76:85:5b:06:3e:a3:ec:a7:ad:e4:44:f7:53:74:6f:d0 + b6:ed:93:8d:38:e4:61:b8:7c:f5:33:ad:02:ae:95:58 + 69:c5:1a:e2:e7:65:ab:aa:c8:0c:21:74:5d:be:aa:48 + 9b:04:1c:a5:4b:45:e4:91:b1:20:7a:2d:cd:38:9f:d8 + 65: + +prime2: + 00:da:ab:4c:b9:47:a9:4c:b5:f9:a3:18:bd:73:f5:d0 + 10:23:c5:2c:75:df:4e:78:04:12:5f:50:78:c4:7a:20 + cf:7c:90:85:96:5b:57:bb:78:6c:d6:81:05:6d:3b:76 + 13:7b:21:8b:90:97:ed:07:13:fe:c4:36:53:a3:bd:f0 + 90:fb:ae:cb:ec:54:29:3f:fe:08:0b:8e:be:61:cf:89 + 37:fe:e4:23:4b:2d:ec:e1:b9:ca:f0:4b:50:da:54:b8 + bf:bc:25:4d:75:d0:16:ad:53:72:88:55:aa:10:03:d4 + d4:bd:50:1d:0a:04:95:b1:93:40:58:af:6a:6f:29:33 + 65:22:10:08:47:df:5c:38:eb:24:0e:59:df:88:bd:47 + 81:28:8d:81:19:6d:72:e0:29:3e:68:35:48:95:ee:e2 + b0:05:83:52:ea:25:ee:d2:f7:9b:69:72:ae:a6:2d:13 + fd:3c:0e:45:51:b5:58:a1:05:e3:a3:d8:3d:39:e8:b2 + 2b: + +coefficient: + 00:a1:15:c8:80:7a:96:6a:3b:db:40:ef:9b:d3:c9:e4 + 3f:16:17:4b:f4:d2:cb:c7:25:60:82:4f:1c:d5:8c:ea + d9:5e:74:c6:f0:70:91:7d:9e:82:09:8f:03:58:a5:7f + 21:da:49:5d:d6:9e:1e:7c:60:5e:d1:b7:96:0e:b1:c6 + 1d:98:ba:32:4f:50:52:46:f6:48:d2:56:14:6d:50:50 + 64:08:e1:1d:9a:6b:7b:c7:c7:40:54:c1:58:2a:9d:24 + 18:27:38:4e:26:94:8a:21:bc:87:b5:fa:39:64:c1:6a + 4f:12:16:5d:3b:4e:cb:f3:19:17:09:95:1e:e0:36:97 + 46:27:27:f8:ae:fc:24:2d:70:b0:4e:df:1f:7e:f2:fa + f4:c4:af:23:80:c7:2f:da:50:c8:cd:24:31:1b:0b:34 + 16:2f:88:c4:85:42:e9:a2:88:83:aa:40:5e:f8:ec:cb + 33:8a:04:58:ec:d9:9a:1a:1a:7b:8d:34:38:1c:70:b7 + 81: + +exp1: + 05:f5:93:e1:eb:09:a6:52:1b:9d:1e:e9:ea:07:9d:c1 + f1:7c:3c:ce:02:93:74:96:8f:28:6c:ca:09:fd:7b:a0 + f0:37:65:5e:60:60:4c:12:75:35:19:6d:a9:62:75:8c + 44:c6:d9:b7:0d:0a:77:38:79:b7:55:0d:26:54:72:66 + 87:2e:86:5e:3c:40:18:38:02:85:41:ce:01:a1:f6:db + 12:ee:cb:a6:c0:80:d6:33:5b:db:c1:dd:ea:25:96:1a + 21:9b:39:8f:d8:49:a6:2a:62:03:04:06:a3:e7:f3:1c + 15:fb:e2:75:71:e9:34:ef:bd:3e:89:9e:9c:86:df:9e + 01:53:2f:cd:03:82:c1:c2:63:5e:36:b1:2b:47:b0:58 + c3:d8:bb:47:9f:2f:bd:30:ff:40:07:f7:24:28:a9:16 + d1:af:2e:02:31:ba:e0:5d:3b:84:be:8f:a2:f2:d7:cb + cf:c5:f9:cf:0c:df:45:c1:49:3c:30:6d:54:6b:53:c9 + + +exp2: + 55:dd:09:c5:7f:34:25:61:17:63:49:a5:aa:d1:0d:20 + 29:4b:95:47:bb:a5:ce:4e:9b:00:3e:53:0d:a3:7f:1a + ba:28:ed:ab:ba:b6:5a:70:d1:1b:f1:91:b5:f0:b1:4e + b8:fc:d5:16:b3:f1:68:e4:1b:17:e4:d5:36:e8:b0:7b + dd:b8:27:6e:e7:25:43:71:76:ab:43:23:d2:b8:71:83 + 41:5d:47:d6:8f:74:02:b6:b7:cf:5f:63:a2:37:be:4b + db:8f:32:39:5e:ba:68:d8:e9:92:4b:40:fa:04:e7:1f + 9a:2e:c9:18:53:f0:8b:c7:ec:6e:66:82:fe:9f:49:05 + 1f:38:f8:67:70:77:80:0a:25:20:55:7e:06:ed:7c:14 + 65:5e:1b:21:66:ee:c2:c2:af:34:b0:27:8e:68:3d:2f + 2d:1b:02:05:db:5b:4a:0f:dc:40:ad:bd:92:97:04:d0 + 5d:32:a5:59:8e:41:fd:08:98:f8:8f:42:8b:68:a9:fd + + + +Public Key PIN: + pin-sha256:Tb40ht8K5iKsfVxc/VFaN81MoQ0Up4EDiijLVZdBdRA= +Public Key ID: + sha256:4dbe3486df0ae622ac7d5c5cfd515a37cd4ca10d14a781038a28cb5597417510 + sha1:a3994ff1885b904c15351bb545922345f503ba1a + +-----BEGIN RSA PRIVATE KEY----- +MIIG5AIBAAKCAYEAwNVcHWzZi5h6ZAdybA1YYn/h8+vVxwd99SH0YeutJrR23uic +l1gZFyBXC73iCvV0C6Cy8ht08iWlrp5+jmA8iirfBlJiwiaMhun++5G/HGnaZVqj +fO4J92Kp2nB1sixxm99TxVXq7onygvfAlvNAAoQ4dU1S/eiRACdfsaXss9w1sIDo +nu8tRzwxzqj/mu8QLvNgfm/gYoq8jKmX7ZGop02RYkY5I63onvA3Ial4yGNB8Tfa +A6do0jr+sEyz9bbx8qls5lGsEbuxZPkJjcQAm5RanW3q14fpnMnyQLigZ5QpiKL4 +XsvFBmuboCA32Kimy7spMTFIhTOJ/4cssfSWjxlkoIfJhObV9+ScEfhPox5HnLVf +HvhA4P+7XfuTPIrFpw56UEo9n83qYZhN1b3s01cPDCHDJyeQS9L5gMIBdiWrDzKt +l2W/SeFz28j9jqQY+24MxjJMy3q7eVuy9xWA9Qy7LDS6NjpHoDAnUnnnrAdSr6Zb +iAPfkE/wEvM/15L3AgMBAAECggGBAIVoFp5U2/xztNjXPhX69ZbPmmbCVdeoG0Ao +CYZlIhmQ6Fw22X7q+BDD0vTQnT2vqmUQ/Dv7OuD7orA3/p5JfhioqDsbbC+ds8Ly +x/ELWAg0Q1+zYT/g/wwjOhdhjkuB6+dGjhIL6si0rw5kkNzd1P7ospaUtEHtT8On +edDRVfzo8Ev4IvcxyUVrI5ox2QQ7OBsDTVKr27TQ/rjh67Xz+5YjV92Bb657dl/f +GIU1VdZstQZI+Y9llmM7ZVBbAHWR5oXftvY3noknbkGzN2aF4RLxtF8eMrEOuqyO +QmVGq3M437jsYtkV+KMiNW0gFlseyDVIWxC17GlCZmitea1DRldSY3enO1FTSbGl +xZX9wGX3iV2OON3pmhzLNHV3DUK3xXfj4RbAuGe9UW67laM4C2p8F8Vgkd+pOZYq +F8iXgqXxRqucR1zmzDnVPWojdIgH2cNJjRBlz0J7PrO+djtXvdh+2MKsw2YC/J7M +1Lang+0wjsM9kAqcuKBskBlWRhPTYQKBwQDhwPA9ZgpDcQttlLjQk/IGZiF8VlOt +Al6q6TQoEa+9eQWsLwXhnc9Hg6JG2HZmPfZIFRXiz/vlNR1FXeN/M07eMw9SrwAM +f94TIOYknXFsLT/oHTuCdGn6+j7/XAssIknx/rFvQaB5WIQzzCg9WYdBkU8VzSaS +B9W0kp/8LJzgdoVbBj6j7Ket5ET3U3Rv0Lbtk4045GG4fPUzrQKulVhpxRri52Wr +qsgMIXRdvqpImwQcpUtF5JGxIHotzTif2GUCgcEA2qtMuUepTLX5oxi9c/XQECPF +LHXfTngEEl9QeMR6IM98kIWWW1e7eGzWgQVtO3YTeyGLkJftBxP+xDZTo73wkPuu +y+xUKT/+CAuOvmHPiTf+5CNLLezhucrwS1DaVLi/vCVNddAWrVNyiFWqEAPU1L1Q +HQoElbGTQFivam8pM2UiEAhH31w46yQOWd+IvUeBKI2BGW1y4Ck+aDVIle7isAWD +Uuol7tL3m2lyrqYtE/08DkVRtVihBeOj2D056LIrAoHABfWT4esJplIbnR7p6ged +wfF8PM4Ck3SWjyhsygn9e6DwN2VeYGBMEnU1GW2pYnWMRMbZtw0Kdzh5t1UNJlRy +Zocuhl48QBg4AoVBzgGh9tsS7sumwIDWM1vbwd3qJZYaIZs5j9hJpipiAwQGo+fz +HBX74nVx6TTvvT6JnpyG354BUy/NA4LBwmNeNrErR7BYw9i7R58vvTD/QAf3JCip +FtGvLgIxuuBdO4S+j6Ly18vPxfnPDN9FwUk8MG1Ua1PJAoHAVd0JxX80JWEXY0ml +qtENIClLlUe7pc5OmwA+Uw2jfxq6KO2rurZacNEb8ZG18LFOuPzVFrPxaOQbF+TV +Nuiwe924J27nJUNxdqtDI9K4cYNBXUfWj3QCtrfPX2OiN75L248yOV66aNjpkktA ++gTnH5ouyRhT8IvH7G5mgv6fSQUfOPhncHeACiUgVX4G7XwUZV4bIWbuwsKvNLAn +jmg9Ly0bAgXbW0oP3ECtvZKXBNBdMqVZjkH9CJj4j0KLaKn9AoHBAKEVyIB6lmo7 +20Dvm9PJ5D8WF0v00svHJWCCTxzVjOrZXnTG8HCRfZ6CCY8DWKV/IdpJXdaeHnxg +XtG3lg6xxh2YujJPUFJG9kjSVhRtUFBkCOEdmmt7x8dAVMFYKp0kGCc4TiaUiiG8 +h7X6OWTBak8SFl07TsvzGRcJlR7gNpdGJyf4rvwkLXCwTt8ffvL69MSvI4DHL9pQ +yM0kMRsLNBYviMSFQumiiIOqQF747MszigRY7NmaGhp7jTQ4HHC3gQ== +-----END RSA PRIVATE KEY----- diff --git a/tests/src/test.sh b/tests/src/test.sh new file mode 100644 index 0000000..d1ccbd6 --- /dev/null +++ b/tests/src/test.sh @@ -0,0 +1 @@ +echo ola diff --git a/tests/src/test.txt b/tests/src/test.txt new file mode 100644 index 0000000..13e8797 --- /dev/null +++ b/tests/src/test.txt @@ -0,0 +1 @@ +Ola! diff --git a/tests/test-mszip.cab b/tests/test-mszip.cab new file mode 100644 index 0000000..089eada Binary files /dev/null and b/tests/test-mszip.cab differ diff --git a/tests/test-ncbytes-overflow.cab b/tests/test-ncbytes-overflow.cab new file mode 100644 index 0000000..7adddbc Binary files /dev/null and b/tests/test-ncbytes-overflow.cab differ diff --git a/tests/test-none.cab b/tests/test-none.cab new file mode 100644 index 0000000..6bac36b Binary files /dev/null and b/tests/test-none.cab differ diff --git a/tests/test-signed.cab b/tests/test-signed.cab new file mode 100644 index 0000000..5749596 Binary files /dev/null and b/tests/test-signed.cab differ