├── .vs ├── bled.vcxproj ├── bled.vcxproj.filters ├── cmp.vcxproj ├── cmp.vcxproj.filters ├── test.vcxproj ├── test.vcxproj.filters ├── uncompress.vcxproj └── uncompress.vcxproj.filters ├── LICENSE ├── Makefile.am ├── Makefile.in ├── README.md ├── aclocal.m4 ├── bled.sln ├── compile ├── configure ├── configure.ac ├── install-sh ├── missing ├── src ├── Makefile.am ├── Makefile.in ├── bb_archive.h ├── bled.c ├── bled.h ├── crc32.c ├── data_align.c ├── data_extract_all.c ├── data_skip.c ├── decompress_bunzip2.c ├── decompress_gunzip.c ├── decompress_uncompress.c ├── decompress_unlzma.c ├── decompress_unxz.c ├── decompress_unzip.c ├── decompress_unzstd.c ├── decompress_vtsi.c ├── filter_accept_all.c ├── filter_accept_list.c ├── filter_accept_reject_list.c ├── find_list_entry.c ├── fse.h ├── fse_bitstream.h ├── fse_decompress.c ├── header_list.c ├── header_skip.c ├── header_verbose_list.c ├── huf.h ├── huf_decompress.c ├── init_handle.c ├── libbb.h ├── msapi_utf8.h ├── open_transformer.c ├── platform.h ├── seek_by_jump.c ├── seek_by_read.c ├── xxhash.c ├── xxhash.h ├── xz.h ├── xz_config.h ├── xz_dec_bcj.c ├── xz_dec_lzma2.c ├── xz_dec_stream.c ├── xz_lzma2.h ├── xz_private.h ├── xz_stream.h ├── zstd.h ├── zstd_bits.h ├── zstd_common.c ├── zstd_compiler.h ├── zstd_config.h ├── zstd_cpu.h ├── zstd_ddict.c ├── zstd_ddict.h ├── zstd_decompress.c ├── zstd_decompress_block.c ├── zstd_decompress_block.h ├── zstd_decompress_internal.h ├── zstd_deps.h ├── zstd_entropy_common.c ├── zstd_error_private.c ├── zstd_error_private.h ├── zstd_errors.h ├── zstd_internal.h └── zstd_mem.h └── test ├── Makefile.am ├── Makefile.in ├── cmp.c ├── data ├── xz.Z ├── xz.bz2 ├── xz.gz ├── xz.lzma ├── xz.xz ├── xz.zip └── xz.zst ├── test.c └── uncompress.c /.vs/bled.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {396df203-84ec-49b8-ae11-074c50a020f0} 6 | 7 | 8 | {0147b833-dc8f-4666-be99-77dfae5e6679} 9 | 10 | 11 | 12 | 13 | Source Files 14 | 15 | 16 | Source Files 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | Source Files 77 | 78 | 79 | Source Files 80 | 81 | 82 | Source Files 83 | 84 | 85 | Source Files 86 | 87 | 88 | Source Files 89 | 90 | 91 | Source Files 92 | 93 | 94 | Source Files 95 | 96 | 97 | Source Files 98 | 99 | 100 | Source Files 101 | 102 | 103 | Source Files 104 | 105 | 106 | Source Files 107 | 108 | 109 | Source Files 110 | 111 | 112 | Source Files 113 | 114 | 115 | Source Files 116 | 117 | 118 | Source Files 119 | 120 | 121 | 122 | 123 | Header Files 124 | 125 | 126 | Header Files 127 | 128 | 129 | Header Files 130 | 131 | 132 | Header Files 133 | 134 | 135 | Header Files 136 | 137 | 138 | Header Files 139 | 140 | 141 | Header Files 142 | 143 | 144 | Header Files 145 | 146 | 147 | Header Files 148 | 149 | 150 | Header Files 151 | 152 | 153 | Header Files 154 | 155 | 156 | Header Files 157 | 158 | 159 | Header Files 160 | 161 | 162 | Header Files 163 | 164 | 165 | Header Files 166 | 167 | 168 | Header Files 169 | 170 | 171 | Header Files 172 | 173 | 174 | Header Files 175 | 176 | 177 | Header Files 178 | 179 | 180 | Header Files 181 | 182 | 183 | Header Files 184 | 185 | 186 | Header Files 187 | 188 | 189 | Header Files 190 | 191 | 192 | Header Files 193 | 194 | 195 | Header Files 196 | 197 | 198 | Header Files 199 | 200 | 201 | -------------------------------------------------------------------------------- /.vs/cmp.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {8F5C5B08-807F-41A1-93D1-76439E8E1328} 23 | Win32Proj 24 | cmp 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | true 37 | v143 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v143 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | $(SolutionDir)x86_32\$(Configuration)\ 66 | $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ 67 | $(SolutionDir)x86_32\$(Configuration)\ 68 | $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ 69 | $(SolutionDir)x86_64\$(Configuration)\ 70 | $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ 71 | $(SolutionDir)x86_64\$(Configuration)\ 72 | $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ 73 | 74 | 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 81 | MultiThreadedDebug 82 | 83 | 84 | Console 85 | true 86 | 87 | 88 | 89 | 90 | Level3 91 | 92 | 93 | MaxSpeed 94 | true 95 | true 96 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 97 | MultiThreaded 98 | 99 | 100 | Console 101 | true 102 | true 103 | true 104 | 105 | 106 | 107 | 108 | 109 | 110 | Level3 111 | Disabled 112 | _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 113 | MultiThreadedDebug 114 | 115 | 116 | Console 117 | true 118 | 119 | 120 | 121 | 122 | Level3 123 | 124 | 125 | MaxSpeed 126 | true 127 | true 128 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 129 | MultiThreaded 130 | 131 | 132 | Console 133 | true 134 | true 135 | true 136 | 137 | 138 | 139 | 140 | {fb6d52d4-a2f8-c358-db85-bbcaecfddd7d} 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /.vs/cmp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /.vs/test.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93} 23 | Win32Proj 24 | test 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | true 37 | v143 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v143 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | $(SolutionDir)x86_32\$(Configuration)\ 66 | $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ 67 | $(SolutionDir)x86_32\$(Configuration)\ 68 | $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ 69 | $(SolutionDir)x86_64\$(Configuration)\ 70 | $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ 71 | $(SolutionDir)x86_64\$(Configuration)\ 72 | $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ 73 | 74 | 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | _CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) 81 | MultiThreadedDebug 82 | 83 | 84 | Console 85 | true 86 | 87 | 88 | 89 | 90 | Level3 91 | 92 | 93 | MaxSpeed 94 | true 95 | true 96 | %(PreprocessorDefinitions) 97 | MultiThreaded 98 | 99 | 100 | Console 101 | true 102 | true 103 | true 104 | 105 | 106 | 107 | 108 | 109 | 110 | Level3 111 | Disabled 112 | _CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) 113 | MultiThreadedDebug 114 | 115 | 116 | Console 117 | true 118 | 119 | 120 | 121 | 122 | Level3 123 | 124 | 125 | MaxSpeed 126 | true 127 | true 128 | %(PreprocessorDefinitions) 129 | MultiThreaded 130 | 131 | 132 | Console 133 | true 134 | true 135 | true 136 | 137 | 138 | 139 | 140 | {fb6d52d4-a2f8-c358-db85-bbcaecfddd7d} 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /.vs/test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /.vs/uncompress.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2} 23 | Win32Proj 24 | uncompress 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | true 37 | v143 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v143 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | $(SolutionDir)x86_32\$(Configuration)\ 66 | $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ 67 | $(SolutionDir)x86_32\$(Configuration)\ 68 | $(SolutionDir)x86_32\$(Configuration)\$(ProjectName)\ 69 | $(SolutionDir)x86_64\$(Configuration)\ 70 | $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ 71 | $(SolutionDir)x86_64\$(Configuration)\ 72 | $(SolutionDir)x86_64\$(Configuration)\$(ProjectName)\ 73 | 74 | 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | _CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) 81 | MultiThreadedDebug 82 | 83 | 84 | Console 85 | true 86 | 87 | 88 | 89 | 90 | Level3 91 | 92 | 93 | MaxSpeed 94 | true 95 | true 96 | %(PreprocessorDefinitions) 97 | MultiThreaded 98 | 99 | 100 | Console 101 | true 102 | true 103 | true 104 | 105 | 106 | 107 | 108 | 109 | 110 | Level3 111 | Disabled 112 | _CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) 113 | MultiThreadedDebug 114 | 115 | 116 | Console 117 | true 118 | 119 | 120 | 121 | 122 | Level3 123 | 124 | 125 | MaxSpeed 126 | true 127 | true 128 | %(PreprocessorDefinitions) 129 | MultiThreaded 130 | 131 | 132 | Console 133 | true 134 | true 135 | true 136 | 137 | 138 | 139 | 140 | {fb6d52d4-a2f8-c358-db85-bbcaecfddd7d} 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /.vs/uncompress.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | Source Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src test 2 | TARGET = bled 3 | 4 | #release: all 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bled - Base Library for Easy Decompression 2 | ============================================= 3 | 4 | ## What's this then? 5 | 6 | This is _Bled_, the Base Library for Easy Decompression. It 7 | is based almost entirely on the native decompression code found in [BusyBox](http://www.busybox.net/). 8 | 9 | ## What's it for? 10 | 11 | It's a library, that can be used in applications to handle the decompression of 12 | __.Z__, __.gz__, __.bz2__, __.lzma__, __.xz__, __.zip__, __.zst__ compressed files and/or 13 | archives. 14 | 15 | ## Why are you doing that? 16 | 17 | Because I need this stuff for [Rufus](http://rufus.akeo.ie), mostly to handle compressed 18 | disk images, and nobody outside of [BusyBox](http://www.busybox.net/) seems to have put 19 | much effort providing a compact, one-size-fits-all Open Source library, for decompressing 20 | the most common formats. 21 | 22 | As I am very conscious of size in Rufus, and Busybox is targeted at embedded systems, 23 | its decompression library seemed like a natural choice. Sure, the [7-Zip LZMA SDK](http://www.7-zip.org/sdk.html) 24 | is nice, and compiles nicely on Windows, but it only supports lzma/lzma2/xz (+.7z archives), 25 | so you'll need to add stuff like [miniz](https://code.google.com/p/miniz/), and then some 26 | more, and soon enough you're dealing with multiple APIs and a lot of duplicated code. 27 | Plus these libraries also provide compression support, which we don't need, so the whole 28 | thing becomes quite large. 29 | 30 | ## What's the license? 31 | 32 | GPLv2 __or later__. 33 | 34 | While the BusyBox project as a whole is GPLv2 __only__, this library is GPLv2 35 | __or later__, which means it can be used indiscriminately in GPLv2 or GPLv3 projects. 36 | This is possible because the BusyBox sources we used were all explictly tagged GPLv2 or 37 | later and any source that wasn't (`libbb.h`, `crc32.c`, `decompress_unxz.c`) has been 38 | recreated/replaced with versions that are. Also, since we're not using any part of bzlib 39 | there's no additional license notice required. So this really is a _pure_ GPLv2 40 | __or later__ decompression library, for the most common compression formats. 41 | 42 | ## What about compressed tar archives? 43 | 44 | I'm not planning to handle these, because I have no need for tar extraction in Rufus. 45 | However, since tar archive handling is present in the BusyBox sources, I may accept a 46 | patch if you feel like adding support for it. 47 | 48 | ## What about .rar? 49 | 50 | Not planning to add support for RAR, unless a truly Free Source (GPL) RAR decompression 51 | comes along. 52 | 53 | ## Are there any limitations? 54 | 55 | * Only Windows is supported for now (MinGW/gcc and MSVC). That's because: 56 | * Windows is the only platform I need for Rufus 57 | * The original `libbb.h` was GPLv2 __only__, so I had to recreate my own from scratch 58 | that is GPLv2 __or later__. This was a bit of a pain, so I don't want to bother 59 | recreating a GPLv2+ libbb.h for Linux or other platforms. 60 | * Can't query the uncompressed file size. This is mostly due to the limitation of the 61 | compression formats being used, as most of them are stream formats and do not store 62 | that information anywhere. 63 | * .7z archive extraction is not supported. 64 | * No multithreading and not optimized for speed __at all__! 65 | * There probably exist limitations with regards to advanced compression and/or newer 66 | compression formats. 67 | 68 | ## Alright I'm sold. What do I need? 69 | 70 | Either: 71 | 72 | * Visual Studio 2022 73 | * MinGW 74 | 75 | Then use the `.sln` file or run `configure` + `make`. 76 | 77 | ## Is the name a reference to _Bled, Slovenia_? 78 | 79 | It is. You should visit Slovenia too, if you ever have a chance. 80 | -------------------------------------------------------------------------------- /bled.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bled", ".vs\bled.vcxproj", "{FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmp", ".vs\cmp.vcxproj", "{8F5C5B08-807F-41A1-93D1-76439E8E1328}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", ".vs\test.vcxproj", "{5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uncompress", ".vs\uncompress.vcxproj", "{375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|x86_32 = Debug|x86_32 17 | Debug|x86_64 = Debug|x86_64 18 | Release|x86_32 = Release|x86_32 19 | Release|x86_64 = Release|x86_64 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86_32.ActiveCfg = Debug|Win32 23 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86_32.Build.0 = Debug|Win32 24 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86_64.ActiveCfg = Debug|x64 25 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86_64.Build.0 = Debug|x64 26 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86_32.ActiveCfg = Release|Win32 27 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86_32.Build.0 = Release|Win32 28 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86_64.ActiveCfg = Release|x64 29 | {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86_64.Build.0 = Release|x64 30 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Debug|x86_32.ActiveCfg = Debug|Win32 31 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Debug|x86_32.Build.0 = Debug|Win32 32 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Debug|x86_64.ActiveCfg = Debug|x64 33 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Debug|x86_64.Build.0 = Debug|x64 34 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Release|x86_32.ActiveCfg = Release|Win32 35 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Release|x86_32.Build.0 = Release|Win32 36 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Release|x86_64.ActiveCfg = Release|x64 37 | {5D64AF41-BDCF-4382-A6BD-8C08AA0FAA93}.Release|x86_64.Build.0 = Release|x64 38 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Debug|x86_32.ActiveCfg = Debug|Win32 39 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Debug|x86_32.Build.0 = Debug|Win32 40 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Debug|x86_64.ActiveCfg = Debug|x64 41 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Debug|x86_64.Build.0 = Debug|x64 42 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Release|x86_32.ActiveCfg = Release|Win32 43 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Release|x86_32.Build.0 = Release|Win32 44 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Release|x86_64.ActiveCfg = Release|x64 45 | {375A62EC-4108-4CFF-9CC7-7C49C3D7E2A2}.Release|x86_64.Build.0 = Release|x64 46 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Debug|x86_32.ActiveCfg = Debug|Win32 47 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Debug|x86_32.Build.0 = Debug|Win32 48 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Debug|x86_64.ActiveCfg = Debug|x64 49 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Debug|x86_64.Build.0 = Debug|x64 50 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Release|x86_32.ActiveCfg = Release|Win32 51 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Release|x86_32.Build.0 = Release|Win32 52 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Release|x86_64.ActiveCfg = Release|x64 53 | {8F5C5B08-807F-41A1-93D1-76439E8E1328}.Release|x86_64.Build.0 = Release|x64 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2012-10-14.11; # UTC 5 | 6 | # Copyright (C) 1999-2013 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*|MSYS*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*|msys/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([bled], [0.2.0], [https://github.com/pbatard/bled/issues], [bled], [https://github.com/pbatard/bled]) 2 | AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies]) 3 | AC_CONFIG_SRCDIR([src/bled.c]) 4 | AC_CONFIG_MACRO_DIR([m4]) 5 | AM_SILENT_RULES([yes]) 6 | 7 | AC_PREREQ([2.50]) 8 | AC_PROG_CC 9 | AC_PROG_RANLIB 10 | AC_PROG_SED 11 | AC_PATH_PROG(RM, rm, rm) 12 | AC_CHECK_TOOL(STRIP, strip, strip) 13 | AC_C_INLINE 14 | AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions]) 15 | 16 | # Clang needs an explicit WIN32_WINNT defined else it produces warnings 17 | # in msapi_utf8.h - including winver.h only doesn't work 18 | AM_CFLAGS="${AM_CFLAGS} -DWINVER=0x501 -D_WIN32_IE=0x501 -D_WIN32_WINNT=0x501" 19 | AM_LDFLAGS="${AM_LDFLAGS} -Wl,-no-undefined" 20 | 21 | # Debug symbols 22 | AC_ARG_ENABLE([debug], 23 | [AS_HELP_STRING([--enable-debug], 24 | [keep debug symbols for gdb (default=yes)])], 25 | [debug_enabled=$enableval], 26 | [debug_enabled='yes']) 27 | if test "x$debug_enabled" != "xno" ; then 28 | CFLAGS="-g -O0" 29 | else 30 | CFLAGS="-Os" 31 | LDFLAGS="-s" 32 | fi 33 | 34 | AC_MSG_RESULT([enabling Large File Support]) 35 | AM_CFLAGS="$AM_CFLAGS -D_FILE_OFFSET_BITS=64 -D_OFF_T_ -D_off_t=off64_t -Doff_t=off64_t -Doff32_t=long" 36 | 37 | # check for -Wno-pointer-sign compiler support (GCC >= 4) 38 | saved_CFLAGS="${CFLAGS}" 39 | CFLAGS="$CFLAGS -Wno-pointer-sign" 40 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], 41 | [nopointersign_cflags="-Wno-pointer-sign"], [nopointersign_cflags=""]) 42 | CFLAGS="${saved_CFLAGS}" 43 | 44 | AM_CFLAGS="$AM_CFLAGS -std=gnu99 -Wshadow -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags" 45 | 46 | AC_SUBST([VISIBILITY_CFLAGS]) 47 | AC_SUBST([AM_CFLAGS]) 48 | AC_SUBST([AM_LDFLAGS]) 49 | AC_SUBST([SUFFIX]) 50 | 51 | AC_CONFIG_FILES([Makefile]) 52 | AC_CONFIG_FILES([src/Makefile]) 53 | AC_CONFIG_FILES([test/Makefile]) 54 | AC_OUTPUT 55 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2013 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_LIBRARIES = libbled.a 2 | 3 | libbled_a_SOURCES = bled.c crc32.c data_align.c data_extract_all.c data_skip.c decompress_bunzip2.c \ 4 | decompress_gunzip.c decompress_uncompress.c decompress_unlzma.c decompress_unxz.c decompress_unzip.c \ 5 | decompress_unzstd.c decompress_vtsi.c filter_accept_all.c filter_accept_list.c filter_accept_reject_list.c \ 6 | find_list_entry.c fse_decompress.c header_list.c header_skip.c header_verbose_list.c huf_decompress.c \ 7 | init_handle.c open_transformer.c seek_by_jump.c seek_by_read.c xz_dec_bcj.c xz_dec_lzma2.c xz_dec_stream.c \ 8 | xxhash.c zstd_common.c zstd_ddict.c zstd_decompress.c zstd_decompress_block.c zstd_entropy_common.c \ 9 | zstd_error_private.c 10 | libbled_a_CFLAGS = $(AM_CFLAGS) -Wno-undef -Wno-strict-aliasing -------------------------------------------------------------------------------- /src/bled.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Bled (Base Library for Easy Decompression) 3 | * 4 | * Copyright © 2014-2024 Pete Batard 5 | * 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 | */ 8 | 9 | #ifdef _CRTDBG_MAP_ALLOC 10 | #include 11 | #include 12 | #endif 13 | 14 | #include "libbb.h" 15 | #include "bb_archive.h" 16 | #include "bled.h" 17 | 18 | typedef long long int(*unpacker_t)(transformer_state_t *xstate); 19 | 20 | /* Globals */ 21 | smallint bb_got_signal; 22 | uint64_t bb_total_rb; 23 | printf_t bled_printf = NULL; 24 | read_t bled_read = NULL; 25 | write_t bled_write = NULL; 26 | progress_t bled_progress = NULL; 27 | switch_t bled_switch = NULL; 28 | unsigned long* bled_cancel_request; 29 | static bool bled_initialized = 0; 30 | jmp_buf bb_error_jmp; 31 | char* bb_virtual_buf = NULL; 32 | size_t bb_virtual_len = 0, bb_virtual_pos = 0; 33 | int bb_virtual_fd = -1; 34 | // ZSTD has a minimal buffer size of (1 << ZSTD_BLOCKSIZELOG_MAX) + ZSTD_blockHeaderSize = 128 KB + 3 35 | // So we set our bufsize to 256 KB 36 | uint32_t BB_BUFSIZE = 0x40000; 37 | 38 | static long long int unpack_none(transformer_state_t *xstate) 39 | { 40 | bb_error_msg("This compression type is not supported"); 41 | return -1; 42 | } 43 | 44 | unpacker_t unpacker[BLED_COMPRESSION_MAX] = { 45 | unpack_none, 46 | unpack_zip_stream, 47 | unpack_Z_stream, 48 | unpack_gz_stream, 49 | unpack_lzma_stream, 50 | unpack_bz2_stream, 51 | unpack_xz_stream, 52 | unpack_none, 53 | unpack_vtsi_stream, 54 | unpack_zstd_stream, 55 | }; 56 | 57 | /* Uncompress file 'src', compressed using 'type', to file 'dst' */ 58 | int64_t bled_uncompress(const char* src, const char* dst, int type) 59 | { 60 | transformer_state_t xstate; 61 | int64_t ret = -1; 62 | 63 | if (!bled_initialized) { 64 | bb_error_msg("The library has not been initialized"); 65 | return -1; 66 | } 67 | 68 | bb_total_rb = 0; 69 | init_transformer_state(&xstate); 70 | xstate.src_fd = -1; 71 | xstate.dst_fd = -1; 72 | 73 | xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0); 74 | if (xstate.src_fd < 0) { 75 | bb_error_msg("Could not open '%s' (errno: %d)", src, errno); 76 | goto err; 77 | } 78 | 79 | xstate.dst_fd = _openU(dst, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, _S_IREAD | _S_IWRITE); 80 | if (xstate.dst_fd < 0) { 81 | bb_error_msg("Could not open '%s' (errno: %d)", dst, errno); 82 | goto err; 83 | } 84 | 85 | if ((type < 0) || (type >= BLED_COMPRESSION_MAX)) { 86 | bb_error_msg("Unsupported compression format"); 87 | goto err; 88 | } 89 | 90 | if (setjmp(bb_error_jmp)) 91 | goto err; 92 | 93 | ret = unpacker[type](&xstate); 94 | 95 | err: 96 | free(xstate.dst_name); 97 | if (xstate.src_fd > 0) 98 | _close(xstate.src_fd); 99 | if (xstate.dst_fd > 0) 100 | _close(xstate.dst_fd); 101 | return ret; 102 | } 103 | 104 | /* Uncompress using Windows handles */ 105 | int64_t bled_uncompress_with_handles(HANDLE hSrc, HANDLE hDst, int type) 106 | { 107 | transformer_state_t xstate; 108 | 109 | if (!bled_initialized) { 110 | bb_error_msg("The library has not been initialized"); 111 | return -1; 112 | } 113 | 114 | bb_total_rb = 0; 115 | init_transformer_state(&xstate); 116 | xstate.src_fd = -1; 117 | xstate.dst_fd = -1; 118 | 119 | xstate.src_fd = _open_osfhandle((intptr_t)hSrc, _O_RDONLY); 120 | if (xstate.src_fd < 0) { 121 | bb_error_msg("Could not get source descriptor (errno: %d)", errno); 122 | return -1; 123 | } 124 | 125 | xstate.dst_fd = _open_osfhandle((intptr_t)hDst, 0); 126 | if (xstate.dst_fd < 0) { 127 | bb_error_msg("Could not get target descriptor (errno: %d)", errno); 128 | return -1; 129 | } 130 | 131 | if ((type < 0) || (type >= BLED_COMPRESSION_MAX)) { 132 | bb_error_msg("Unsupported compression format"); 133 | return -1; 134 | } 135 | 136 | if (setjmp(bb_error_jmp)) 137 | return -1; 138 | 139 | return unpacker[type](&xstate); 140 | } 141 | 142 | /* Uncompress file 'src', compressed using 'type', to buffer 'buf' of size 'size' */ 143 | int64_t bled_uncompress_to_buffer(const char* src, char* buf, size_t size, int type) 144 | { 145 | transformer_state_t xstate; 146 | int64_t ret = -1; 147 | 148 | if (!bled_initialized) { 149 | bb_error_msg("The library has not been initialized"); 150 | return -1; 151 | } 152 | 153 | if ((src == NULL) || (buf == NULL)) { 154 | bb_error_msg("Invalid parameter"); 155 | return -1; 156 | } 157 | 158 | bb_total_rb = 0; 159 | init_transformer_state(&xstate); 160 | xstate.src_fd = -1; 161 | xstate.dst_fd = -1; 162 | 163 | if (src[0] == 0) { 164 | xstate.src_fd = bb_virtual_fd; 165 | } else { 166 | xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0); 167 | } 168 | if (xstate.src_fd < 0) { 169 | bb_error_msg("Could not open '%s' (errno: %d)", src, errno); 170 | goto err; 171 | } 172 | 173 | xstate.mem_output_buf = buf; 174 | xstate.mem_output_size = 0; 175 | xstate.mem_output_size_max = size; 176 | 177 | if ((type < 0) || (type >= BLED_COMPRESSION_MAX)) { 178 | bb_error_msg("Unsupported compression format"); 179 | goto err; 180 | } 181 | 182 | if (setjmp(bb_error_jmp)) 183 | goto err; 184 | 185 | ret = unpacker[type](&xstate); 186 | 187 | err: 188 | free(xstate.dst_name); 189 | if ((src[0] != 0) && (xstate.src_fd > 0)) 190 | _close(xstate.src_fd); 191 | return ret; 192 | } 193 | 194 | /* Uncompress all files from archive 'src', compressed using 'type', to destination dir 'dir' */ 195 | int64_t bled_uncompress_to_dir(const char* src, const char* dir, int type) 196 | { 197 | transformer_state_t xstate; 198 | int64_t ret = -1; 199 | 200 | if (!bled_initialized) { 201 | bb_error_msg("The library has not been initialized"); 202 | return -1; 203 | } 204 | 205 | bb_total_rb = 0; 206 | init_transformer_state(&xstate); 207 | xstate.src_fd = -1; 208 | xstate.dst_fd = -1; 209 | 210 | xstate.src_fd = _openU(src, _O_RDONLY | _O_BINARY, 0); 211 | if (xstate.src_fd < 0) { 212 | bb_error_msg("Could not open '%s' (errno: %d)", src, errno); 213 | goto err; 214 | } 215 | 216 | xstate.dst_dir = dir; 217 | 218 | // Only zip archives are supported for now 219 | if (type != BLED_COMPRESSION_ZIP) { 220 | bb_error_msg("This compression format is not supported for directory extraction"); 221 | goto err; 222 | } 223 | 224 | if (setjmp(bb_error_jmp)) 225 | goto err; 226 | 227 | ret = unpacker[type](&xstate); 228 | 229 | err: 230 | free(xstate.dst_name); 231 | if (xstate.src_fd > 0) 232 | _close(xstate.src_fd); 233 | if (xstate.dst_fd > 0) 234 | _close(xstate.dst_fd); 235 | return ret; 236 | } 237 | 238 | int64_t bled_uncompress_from_buffer_to_buffer(const char* src, const size_t src_len, char* dst, size_t dst_len, int type) 239 | { 240 | int64_t ret; 241 | 242 | if (!bled_initialized) { 243 | bb_error_msg("The library has not been initialized"); 244 | return -1; 245 | } 246 | 247 | if ((src == NULL) || (dst == NULL)) { 248 | bb_error_msg("Invalid parameter"); 249 | return -1; 250 | } 251 | 252 | if (bb_virtual_buf != NULL) { 253 | bb_error_msg("Can not decompress more than one buffer at once"); 254 | return -1; 255 | } 256 | 257 | bb_virtual_buf = (char*)src; 258 | bb_virtual_len = src_len; 259 | bb_virtual_pos = 0; 260 | bb_virtual_fd = 0; 261 | 262 | ret = bled_uncompress_to_buffer("", dst, dst_len, type); 263 | 264 | bb_virtual_buf = NULL; 265 | bb_virtual_len = 0; 266 | bb_virtual_fd = -1; 267 | 268 | return ret; 269 | } 270 | 271 | /* Initialize the library. 272 | * When the parameters are not NULL or zero you can: 273 | * - specify the buffer size to use (must be larger than 256KB and a power of two) 274 | * - specify the printf-like function you want to use to output message 275 | * void print_function(const char* format, ...); 276 | * - specify the read/write functions you want to use; 277 | * - specify the function you want to use to display progress, based on number of source archive bytes read 278 | * void progress_function(const uint64_t read_bytes); 279 | * - specify the function you want to use when switching files in an archive 280 | * void switch_function(const char* filename, const uint64_t filesize); 281 | * - point to an unsigned long variable, to be used to cancel operations when set to non zero 282 | */ 283 | int bled_init(uint32_t buffer_size, printf_t print_function, read_t read_function, write_t write_function, 284 | progress_t progress_function, switch_t switch_function, unsigned long* cancel_request) 285 | { 286 | if (bled_initialized) 287 | return -1; 288 | BB_BUFSIZE = buffer_size; 289 | /* buffer_size must be larger than 256 KB and a power of two */ 290 | if (buffer_size < 0x40000 || (buffer_size & (buffer_size - 1)) != 0) { 291 | if (buffer_size != 0 && print_function != NULL) 292 | print_function("bled_init: invalid buffer_size, defaulting to 64 KB"); 293 | BB_BUFSIZE = 0x40000; 294 | } 295 | bled_printf = print_function; 296 | bled_read = read_function; 297 | bled_write = write_function; 298 | bled_progress = progress_function; 299 | bled_switch = switch_function; 300 | bled_cancel_request = cancel_request; 301 | bled_initialized = true; 302 | return 0; 303 | } 304 | 305 | /* This call frees any resource used by the library */ 306 | void bled_exit(void) 307 | { 308 | bled_printf = NULL; 309 | bled_progress = NULL; 310 | bled_switch = NULL; 311 | bled_cancel_request = NULL; 312 | if (global_crc32_table) { 313 | free(global_crc32_table); 314 | global_crc32_table = NULL; 315 | } 316 | bled_initialized = false; 317 | } 318 | -------------------------------------------------------------------------------- /src/bled.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Bled (Base Library for Easy Decompression) 3 | * 4 | * Copyright © 2014-2024 Pete Batard 5 | * 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #pragma once 13 | 14 | #ifndef ARRAYSIZE 15 | #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 16 | #endif 17 | 18 | typedef void (*printf_t) (const char* format, ...); 19 | typedef void (*progress_t) (const uint64_t read_bytes); 20 | typedef int (*read_t)(int fd, void* buf, unsigned int count); 21 | typedef int (*write_t)(int fd, const void* buf, unsigned int count); 22 | typedef void (*switch_t)(const char* filename, const uint64_t size); 23 | 24 | typedef enum { 25 | BLED_COMPRESSION_NONE = 0, 26 | BLED_COMPRESSION_ZIP, // .zip 27 | BLED_COMPRESSION_LZW, // .Z 28 | BLED_COMPRESSION_GZIP, // .gz 29 | BLED_COMPRESSION_LZMA, // .lzma 30 | BLED_COMPRESSION_BZIP2, // .bz2 31 | BLED_COMPRESSION_XZ, // .xz 32 | BLED_COMPRESSION_7ZIP, // .7z 33 | BLED_COMPRESSION_VTSI, // .vtsi 34 | BLED_COMPRESSION_ZSTD, // .zst 35 | BLED_COMPRESSION_MAX 36 | } bled_compression_type; 37 | 38 | /* Uncompress file 'src', compressed using 'type', to file 'dst' */ 39 | int64_t bled_uncompress(const char* src, const char* dst, int type); 40 | 41 | /* Uncompress using Windows handles */ 42 | int64_t bled_uncompress_with_handles(HANDLE hSrc, HANDLE hDst, int type); 43 | 44 | /* Uncompress file 'src', compressed using 'type', to buffer 'buf' of size 'size' */ 45 | int64_t bled_uncompress_to_buffer(const char* src, char* buf, size_t size, int type); 46 | 47 | /* Uncompress all files from archive 'src', compressed using 'type', to destination dir 'dir' */ 48 | int64_t bled_uncompress_to_dir(const char* src, const char* dir, int type); 49 | 50 | /* Uncompress buffer 'src' of length 'src_len' to buffer 'dst' of size 'dst_len' */ 51 | int64_t bled_uncompress_from_buffer_to_buffer(const char* src, const size_t src_len, char* dst, size_t dst_len, int type); 52 | 53 | /* Initialize the library. 54 | * When the parameters are not NULL or zero you can: 55 | * - specify the buffer size to use (must be larger than 64KB and a power of two) 56 | * - specify the printf-like function you want to use to output message 57 | * void print_function(const char* format, ...); 58 | * - specify the read/write functions you want to use; 59 | * - specify the function you want to use to display progress, based on number of source archive bytes read 60 | * void progress_function(const uint64_t read_bytes); 61 | * - specify the function you want to use when switching files in an archive 62 | * void switch_function(const char* filename, const uint64_t filesize); 63 | * - point to an unsigned long variable, to be used to cancel operations when set to non zero 64 | */ 65 | int bled_init(uint32_t buffer_size, printf_t print_function, read_t read_function, write_t write_function, 66 | progress_t progress_function, switch_t switch_function, unsigned long* cancel_request); 67 | 68 | /* This call frees any resource used by the library */ 69 | void bled_exit(void); 70 | -------------------------------------------------------------------------------- /src/crc32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GPLv2+ CRC32 implementation for busybox 3 | * 4 | * Based on crc32.c from util-linux v2.17's partx v2.17 - Public Domain 5 | * Adjusted for busybox' by Pete Batard 6 | * 7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 | */ 9 | 10 | #include "libbb.h" 11 | 12 | #if __GNUC__ >= 3 /* 2.x has "attribute", but only 3.0 has "pure */ 13 | #define attribute(x) __attribute__(x) 14 | #else 15 | #define attribute(x) 16 | #endif 17 | 18 | /* Do NOT alter these */ 19 | #define CRC_LE_BITS 8 20 | #define CRC_BE_BITS 8 21 | 22 | /* 23 | * There are multiple 16-bit CRC polynomials in common use, but this is 24 | * *the* standard CRC-32 polynomial, first popularized by Ethernet. 25 | * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 26 | */ 27 | #define CRCPOLY_LE 0xedb88320 28 | #define CRCPOLY_BE 0x04c11db7 29 | 30 | /* This needs to be defined somewhere */ 31 | uint32_t *global_crc32_table; 32 | 33 | static void crc32init_le(uint32_t *crc32table_le) 34 | { 35 | unsigned i, j; 36 | uint32_t crc = 1; 37 | 38 | crc32table_le[0] = 0; 39 | 40 | for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) { 41 | // coverity[overflow_const] 42 | crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); 43 | for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i) 44 | crc32table_le[i + j] = crc ^ crc32table_le[j]; 45 | } 46 | } 47 | 48 | /** 49 | * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32 50 | * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for 51 | * other uses, or the previous crc32 value if computing incrementally. 52 | * @p - pointer to buffer over which CRC is run 53 | * @len - length of buffer @p 54 | * 55 | */ 56 | uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len, uint32_t *crc32table_le) 57 | { 58 | while (len--) { 59 | # if CRC_LE_BITS == 8 60 | crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255]; 61 | # elif CRC_LE_BITS == 4 62 | crc ^= *p++; 63 | crc = (crc >> 4) ^ crc32table_le[crc & 15]; 64 | crc = (crc >> 4) ^ crc32table_le[crc & 15]; 65 | # elif CRC_LE_BITS == 2 66 | crc ^= *p++; 67 | crc = (crc >> 2) ^ crc32table_le[crc & 3]; 68 | crc = (crc >> 2) ^ crc32table_le[crc & 3]; 69 | crc = (crc >> 2) ^ crc32table_le[crc & 3]; 70 | crc = (crc >> 2) ^ crc32table_le[crc & 3]; 71 | # endif 72 | } 73 | return crc; 74 | } 75 | 76 | /** 77 | * crc32init_be() - allocate and initialize BE table data 78 | */ 79 | static void crc32init_be(uint32_t *crc32table_be) 80 | { 81 | unsigned i, j; 82 | uint32_t crc = 0x80000000; 83 | 84 | for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) { 85 | // coverity[overflow_const] 86 | crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0); 87 | for (j = 0; j < i; j++) 88 | crc32table_be[i + j] = crc ^ crc32table_be[j]; 89 | } 90 | } 91 | 92 | /** 93 | * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32 94 | * @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for 95 | * other uses, or the previous crc32 value if computing incrementally. 96 | * @p - pointer to buffer over which CRC is run 97 | * @len - length of buffer @p 98 | * 99 | */ 100 | uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len, uint32_t *crc32table_be) 101 | { 102 | while (len--) { 103 | # if CRC_BE_BITS == 8 104 | crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++]; 105 | # elif CRC_BE_BITS == 4 106 | crc ^= *p++ << 24; 107 | crc = (crc << 4) ^ crc32table_be[crc >> 28]; 108 | crc = (crc << 4) ^ crc32table_be[crc >> 28]; 109 | # elif CRC_BE_BITS == 2 110 | crc ^= *p++ << 24; 111 | crc = (crc << 2) ^ crc32table_be[crc >> 30]; 112 | crc = (crc << 2) ^ crc32table_be[crc >> 30]; 113 | crc = (crc << 2) ^ crc32table_be[crc >> 30]; 114 | crc = (crc << 2) ^ crc32table_be[crc >> 30]; 115 | # endif 116 | } 117 | return crc; 118 | } 119 | 120 | uint32_t* crc32_filltable(uint32_t *crc_table, int endian) 121 | { 122 | /* Expects the caller to do the cleanup */ 123 | if (!crc_table) 124 | crc_table = calloc(1 << CRC_LE_BITS, sizeof(uint32_t)); 125 | if (crc_table) { 126 | if (endian) 127 | crc32init_be(crc_table); 128 | else 129 | crc32init_le(crc_table); 130 | } 131 | return crc_table; 132 | } 133 | 134 | /* 135 | * A brief CRC tutorial. 136 | * 137 | * A CRC is a long-division remainder. You add the CRC to the message, 138 | * and the whole thing (message+CRC) is a multiple of the given 139 | * CRC polynomial. To check the CRC, you can either check that the 140 | * CRC matches the recomputed value, *or* you can check that the 141 | * remainder computed on the message+CRC is 0. This latter approach 142 | * is used by a lot of hardware implementations, and is why so many 143 | * protocols put the end-of-frame flag after the CRC. 144 | * 145 | * It's actually the same long division you learned in school, except that 146 | * - We're working in binary, so the digits are only 0 and 1, and 147 | * - When dividing polynomials, there are no carries. Rather than add and 148 | * subtract, we just xor. Thus, we tend to get a bit sloppy about 149 | * the difference between adding and subtracting. 150 | * 151 | * A 32-bit CRC polynomial is actually 33 bits long. But since it's 152 | * 33 bits long, bit 32 is always going to be set, so usually the CRC 153 | * is written in hex with the most significant bit omitted. (If you're 154 | * familiar with the IEEE 754 floating-point format, it's the same idea.) 155 | * 156 | * Note that a CRC is computed over a string of *bits*, so you have 157 | * to decide on the endianness of the bits within each byte. To get 158 | * the best error-detecting properties, this should correspond to the 159 | * order they're actually sent. For example, standard RS-232 serial is 160 | * little-endian; the most significant bit (sometimes used for parity) 161 | * is sent last. And when appending a CRC word to a message, you should 162 | * do it in the right order, matching the endianness. 163 | * 164 | * Just like with ordinary division, the remainder is always smaller than 165 | * the divisor (the CRC polynomial) you're dividing by. Each step of the 166 | * division, you take one more digit (bit) of the dividend and append it 167 | * to the current remainder. Then you figure out the appropriate multiple 168 | * of the divisor to subtract to being the remainder back into range. 169 | * In binary, it's easy - it has to be either 0 or 1, and to make the 170 | * XOR cancel, it's just a copy of bit 32 of the remainder. 171 | * 172 | * When computing a CRC, we don't care about the quotient, so we can 173 | * throw the quotient bit away, but subtract the appropriate multiple of 174 | * the polynomial from the remainder and we're back to where we started, 175 | * ready to process the next bit. 176 | * 177 | * A big-endian CRC written this way would be coded like: 178 | * for (i = 0; i < input_bits; i++) { 179 | * multiple = remainder & 0x80000000 ? CRCPOLY : 0; 180 | * remainder = (remainder << 1 | next_input_bit()) ^ multiple; 181 | * } 182 | * Notice how, to get at bit 32 of the shifted remainder, we look 183 | * at bit 31 of the remainder *before* shifting it. 184 | * 185 | * But also notice how the next_input_bit() bits we're shifting into 186 | * the remainder don't actually affect any decision-making until 187 | * 32 bits later. Thus, the first 32 cycles of this are pretty boring. 188 | * Also, to add the CRC to a message, we need a 32-bit-long hole for it at 189 | * the end, so we have to add 32 extra cycles shifting in zeros at the 190 | * end of every message, 191 | * 192 | * So the standard trick is to rearrage merging in the next_input_bit() 193 | * until the moment it's needed. Then the first 32 cycles can be precomputed, 194 | * and merging in the final 32 zero bits to make room for the CRC can be 195 | * skipped entirely. 196 | * This changes the code to: 197 | * for (i = 0; i < input_bits; i++) { 198 | * remainder ^= next_input_bit() << 31; 199 | * multiple = (remainder & 0x80000000) ? CRCPOLY : 0; 200 | * remainder = (remainder << 1) ^ multiple; 201 | * } 202 | * With this optimization, the little-endian code is simpler: 203 | * for (i = 0; i < input_bits; i++) { 204 | * remainder ^= next_input_bit(); 205 | * multiple = (remainder & 1) ? CRCPOLY : 0; 206 | * remainder = (remainder >> 1) ^ multiple; 207 | * } 208 | * 209 | * Note that the other details of endianness have been hidden in CRCPOLY 210 | * (which must be bit-reversed) and next_input_bit(). 211 | * 212 | * However, as long as next_input_bit is returning the bits in a sensible 213 | * order, we can actually do the merging 8 or more bits at a time rather 214 | * than one bit at a time: 215 | * for (i = 0; i < input_bytes; i++) { 216 | * remainder ^= next_input_byte() << 24; 217 | * for (j = 0; j < 8; j++) { 218 | * multiple = (remainder & 0x80000000) ? CRCPOLY : 0; 219 | * remainder = (remainder << 1) ^ multiple; 220 | * } 221 | * } 222 | * Or in little-endian: 223 | * for (i = 0; i < input_bytes; i++) { 224 | * remainder ^= next_input_byte(); 225 | * for (j = 0; j < 8; j++) { 226 | * multiple = (remainder & 1) ? CRCPOLY : 0; 227 | * remainder = (remainder << 1) ^ multiple; 228 | * } 229 | * } 230 | * If the input is a multiple of 32 bits, you can even XOR in a 32-bit 231 | * word at a time and increase the inner loop count to 32. 232 | * 233 | * You can also mix and match the two loop styles, for example doing the 234 | * bulk of a message byte-at-a-time and adding bit-at-a-time processing 235 | * for any fractional bytes at the end. 236 | * 237 | * The only remaining optimization is to the byte-at-a-time table method. 238 | * Here, rather than just shifting one bit of the remainder to decide 239 | * in the correct multiple to subtract, we can shift a byte at a time. 240 | * This produces a 40-bit (rather than a 33-bit) intermediate remainder, 241 | * but again the multiple of the polynomial to subtract depends only on 242 | * the high bits, the high 8 bits in this case. 243 | * 244 | * The multile we need in that case is the low 32 bits of a 40-bit 245 | * value whose high 8 bits are given, and which is a multiple of the 246 | * generator polynomial. This is simply the CRC-32 of the given 247 | * one-byte message. 248 | * 249 | * Two more details: normally, appending zero bits to a message which 250 | * is already a multiple of a polynomial produces a larger multiple of that 251 | * polynomial. To enable a CRC to detect this condition, it's common to 252 | * invert the CRC before appending it. This makes the remainder of the 253 | * message+crc come out not as zero, but some fixed non-zero value. 254 | * 255 | * The same problem applies to zero bits prepended to the message, and 256 | * a similar solution is used. Instead of starting with a remainder of 257 | * 0, an initial remainder of all ones is used. As long as you start 258 | * the same way on decoding, it doesn't make a difference. 259 | */ 260 | -------------------------------------------------------------------------------- /src/data_align.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) 9 | { 10 | unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary; 11 | 12 | archive_handle->seek(archive_handle->src_fd, skip_amount); 13 | archive_handle->offset += skip_amount; 14 | } 15 | -------------------------------------------------------------------------------- /src/data_extract_all.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) 9 | { 10 | file_header_t *file_header = archive_handle->file_header; 11 | int dst_fd; 12 | int res; 13 | char *hard_link; 14 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS 15 | char *dst_name; 16 | #else 17 | # define dst_name (file_header->name) 18 | #endif 19 | 20 | #if ENABLE_FEATURE_TAR_SELINUX 21 | char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; 22 | if (!sctx) 23 | sctx = archive_handle->tar__sctx[PAX_GLOBAL]; 24 | if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ 25 | setfscreatecon(sctx); 26 | free(archive_handle->tar__sctx[PAX_NEXT_FILE]); 27 | archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; 28 | } 29 | #endif 30 | 31 | /* Hard links are encoded as regular files of size 0 32 | * with a nonempty link field */ 33 | hard_link = NULL; 34 | if (S_ISREG(file_header->mode) && file_header->size == 0) 35 | hard_link = file_header->link_target; 36 | 37 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS 38 | dst_name = file_header->name; 39 | if (archive_handle->tar__strip_components) { 40 | unsigned n = archive_handle->tar__strip_components; 41 | do { 42 | dst_name = strchr(dst_name, '/'); 43 | if (!dst_name || dst_name[1] == '\0') { 44 | data_skip(archive_handle); 45 | goto ret; 46 | } 47 | dst_name++; 48 | /* 49 | * Link target is shortened only for hardlinks: 50 | * softlinks restored unchanged. 51 | */ 52 | if (hard_link) { 53 | // GNU tar 1.26 does not check that we reached end of link name: 54 | // if "dir/hardlink" is hardlinked to "file", 55 | // tar xvf a.tar --strip-components=1 says: 56 | // tar: hardlink: Cannot hard link to '': No such file or directory 57 | // and continues processing. We silently skip such entries. 58 | hard_link = strchr(hard_link, '/'); 59 | if (!hard_link || hard_link[1] == '\0') { 60 | data_skip(archive_handle); 61 | goto ret; 62 | } 63 | hard_link++; 64 | } 65 | } while (--n != 0); 66 | } 67 | #endif 68 | 69 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { 70 | char *slash = strrchr(dst_name, '/'); 71 | if (slash) { 72 | *slash = '\0'; 73 | bb_make_directory(dst_name, -1, FILEUTILS_RECUR); 74 | *slash = '/'; 75 | } 76 | } 77 | 78 | if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { 79 | /* Remove the entry if it exists */ 80 | if (!S_ISDIR(file_header->mode)) { 81 | if (hard_link) { 82 | /* Ugly special case: 83 | * tar cf t.tar hardlink1 hardlink2 hardlink1 84 | * results in this tarball structure: 85 | * hardlink1 86 | * hardlink2 -> hardlink1 87 | * hardlink1 -> hardlink1 <== !!! 88 | */ 89 | if (strcmp(hard_link, dst_name) == 0) 90 | goto ret; 91 | } 92 | /* Proceed with deleting */ 93 | if (_unlink(dst_name) == -1 94 | && errno != ENOENT 95 | ) { 96 | bb_perror_msg_and_die("can't remove old file %s", 97 | dst_name); 98 | } 99 | } 100 | } 101 | else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { 102 | /* Remove the existing entry if its older than the extracted entry */ 103 | struct stat existing_sb; 104 | if (lstat(dst_name, &existing_sb) == -1) { 105 | if (errno != ENOENT) { 106 | bb_simple_perror_msg_and_die("can't stat old file"); 107 | } 108 | } 109 | else if (existing_sb.st_mtime >= file_header->mtime) { 110 | if (!S_ISDIR(file_header->mode)) { 111 | bb_error_msg("%s not created: newer or " 112 | "same age file exists", dst_name); 113 | } 114 | data_skip(archive_handle); 115 | goto ret; 116 | } 117 | else if ((_unlink(dst_name) == -1) && (errno != EISDIR)) { 118 | bb_perror_msg_and_die("can't remove old file %s", 119 | dst_name); 120 | } 121 | } 122 | 123 | /* Handle hard links separately */ 124 | if (hard_link) { 125 | create_or_remember_link(&archive_handle->link_placeholders, 126 | hard_link, 127 | dst_name, 128 | 1); 129 | /* Hardlinks have no separate mode/ownership, skip chown/chmod */ 130 | goto ret; 131 | } 132 | 133 | /* Create the filesystem entry */ 134 | switch (file_header->mode & S_IFMT) { 135 | case S_IFREG: { 136 | /* Regular file */ 137 | #ifdef ARCHIVE_REPLACE_VIA_RENAME 138 | char *dst_nameN; 139 | #endif 140 | int flags = O_WRONLY | O_CREAT | O_EXCL; 141 | if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) 142 | flags = O_WRONLY | O_CREAT | O_TRUNC; 143 | #ifdef ARCHIVE_REPLACE_VIA_RENAME 144 | dst_nameN = dst_name; 145 | if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) 146 | /* rpm-style temp file name */ 147 | dst_nameN = xasprintf("%s;%x", dst_name, (int)getpid()); 148 | #endif 149 | if (_sopen_s(&dst_fd, dst_name, flags, _SH_DENYNO, file_header->mode) != 0) { 150 | bb_perror_msg_and_die("can't open file %s", dst_name); 151 | } 152 | bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); 153 | _close(dst_fd); 154 | #ifdef ARCHIVE_REPLACE_VIA_RENAME 155 | if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { 156 | xrename(dst_nameN, dst_name); 157 | free(dst_nameN); 158 | } 159 | #endif 160 | break; 161 | } 162 | case S_IFDIR: 163 | //TODO: this causes problems if tarball contains a r-xr-xr-x directory: 164 | // we create this directory, and then fail to create files inside it 165 | // (if tar xf isn't run as root). 166 | // GNU tar works around this by chmod-ing directories *after* all files are extracted. 167 | res = mkdir(dst_name, file_header->mode); 168 | if ((res != 0) 169 | && (errno != EISDIR) /* btw, Linux doesn't return this */ 170 | && (errno != EEXIST) 171 | ) { 172 | bb_perror_msg("can't make dir %s", dst_name); 173 | } 174 | break; 175 | case S_IFLNK: 176 | /* Symlink */ 177 | //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) 178 | 179 | /* To avoid a directory traversal attack via symlinks, 180 | * do not restore symlinks with ".." components 181 | * or symlinks starting with "/", unless a magic 182 | * envvar is set. 183 | * 184 | * For example, consider a .tar created via: 185 | * $ tar cvf bug.tar anything.txt 186 | * $ ln -s /tmp symlink 187 | * $ tar --append -f bug.tar symlink 188 | * $ rm symlink 189 | * $ mkdir symlink 190 | * $ tar --append -f bug.tar symlink/evil.py 191 | * 192 | * This will result in an archive that contains: 193 | * $ tar --list -f bug.tar 194 | * anything.txt 195 | * symlink [-> /tmp] 196 | * symlink/evil.py 197 | * 198 | * Untarring bug.tar would otherwise place evil.py in '/tmp'. 199 | */ 200 | create_or_remember_link(&archive_handle->link_placeholders, 201 | file_header->link_target, 202 | dst_name, 203 | 0); 204 | break; 205 | case S_IFSOCK: 206 | case S_IFBLK: 207 | case S_IFCHR: 208 | case S_IFIFO: 209 | res = mknod(dst_name, file_header->mode, file_header->device); 210 | if (res != 0) { 211 | bb_perror_msg("can't create node %s", dst_name); 212 | } 213 | break; 214 | default: 215 | bb_simple_error_msg_and_die("unrecognized file type"); 216 | } 217 | 218 | if (!S_ISLNK(file_header->mode)) { 219 | if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { 220 | uid_t uid = file_header->uid; 221 | gid_t gid = file_header->gid; 222 | #if ENABLE_FEATURE_TAR_UNAME_GNAME 223 | if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { 224 | if (file_header->tar__uname) { 225 | //TODO: cache last name/id pair? 226 | struct passwd *pwd = getpwnam(file_header->tar__uname); 227 | if (pwd) uid = pwd->pw_uid; 228 | } 229 | if (file_header->tar__gname) { 230 | struct group *grp = getgrnam(file_header->tar__gname); 231 | if (grp) gid = grp->gr_gid; 232 | } 233 | } 234 | #endif 235 | /* GNU tar 1.15.1 uses chown, not lchown */ 236 | chown(file_header->name, uid, gid); 237 | } 238 | /* uclibc has no lchmod, glibc is even stranger - 239 | * it has lchmod which seems to do nothing! 240 | * so we use chmod... */ 241 | if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { 242 | // coverity[toctou] 243 | (void)_chmod(file_header->name, file_header->mode); 244 | } 245 | if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { 246 | struct timeval64 t[2]; 247 | 248 | t[1].tv_sec = t[0].tv_sec = file_header->mtime; 249 | t[1].tv_usec = t[0].tv_usec = 0; 250 | utimes64(dst_name, t); 251 | } 252 | } 253 | 254 | ret: ; 255 | #if ENABLE_FEATURE_TAR_SELINUX 256 | if (sctx) { 257 | /* reset the context after creating an entry */ 258 | setfscreatecon(NULL); 259 | } 260 | #endif 261 | } 262 | -------------------------------------------------------------------------------- /src/data_skip.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC data_skip(archive_handle_t *archive_handle) 9 | { 10 | archive_handle->seek(archive_handle->src_fd, archive_handle->file_header->size); 11 | } 12 | -------------------------------------------------------------------------------- /src/decompress_uncompress.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * uncompress for busybox -- (c) 2002 Robert Griebl 4 | * 5 | * based on the original compress42.c source 6 | * (see disclaimer below) 7 | */ 8 | /* (N)compress42.c - File compression ala IEEE Computer, Mar 1992. 9 | * 10 | * Authors: 11 | * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) 12 | * Jim McKie (decvax!mcvax!jim) 13 | * Steve Davies (decvax!vax135!petsd!peora!srd) 14 | * Ken Turkowski (decvax!decwrl!turtlevax!ken) 15 | * James A. Woods (decvax!ihnp4!ames!jaw) 16 | * Joe Orost (decvax!vax135!petsd!joe) 17 | * Dave Mack (csu@alembic.acs.com) 18 | * Peter Jannesen, Network Communication Systems 19 | * (peter@ncs.nl) 20 | * 21 | * marc@suse.de : a small security fix for a buffer overflow 22 | * 23 | * [... History snipped ...] 24 | */ 25 | #include "libbb.h" 26 | #include "bb_archive.h" 27 | 28 | 29 | /* Default input buffer size */ 30 | #define IBUFSIZ ((int)BB_BUFSIZE) 31 | 32 | /* Default output buffer size */ 33 | #define OBUFSIZ ((int)BB_BUFSIZE) 34 | 35 | /* Defines for third byte of header */ 36 | #define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ 37 | /* Masks 0x20 and 0x40 are free. */ 38 | /* I think 0x20 should mean that there is */ 39 | /* a fourth header byte (for expansion). */ 40 | #define BLOCK_MODE 0x80 /* Block compression if table is full and */ 41 | /* compression rate is dropping flush tables */ 42 | /* the next two codes should not be changed lightly, as they must not */ 43 | /* lie within the contiguous general code space. */ 44 | #define FIRST 257 /* first free entry */ 45 | #define CLEAR 256 /* table clear output code */ 46 | 47 | #define INIT_BITS 9 /* initial number of bits/code */ 48 | 49 | 50 | /* machine variants which require cc -Dmachine: pdp11, z8000, DOS */ 51 | #define HBITS 17 /* 50% occupancy */ 52 | #define HSIZE (1<src_fd, inbuf, 1) != 1) { 116 | bb_simple_error_msg("short read"); 117 | goto err; 118 | } 119 | 120 | maxbits = inbuf[0] & BIT_MASK; 121 | block_mode = inbuf[0] & BLOCK_MODE; 122 | maxmaxcode = MAXCODE(maxbits); 123 | 124 | if (maxbits > BITS) { 125 | bb_error_msg("compressed with %d bits, can only handle " 126 | BITS_STR" bits", maxbits); 127 | goto err; 128 | } 129 | 130 | n_bits = INIT_BITS; 131 | maxcode = MAXCODE(INIT_BITS) - 1; 132 | bitmask = (1 << INIT_BITS) - 1; 133 | oldcode = -1; 134 | finchar = 0; 135 | outpos = 0; 136 | posbits = 0 << 3; 137 | 138 | free_ent = ((block_mode) ? FIRST : 256); 139 | 140 | /* As above, initialize the first 256 entries in the table. */ 141 | /*clear_tab_prefixof(); - done by xzalloc */ 142 | 143 | { 144 | int i; 145 | for (i = 255; i >= 0; --i) 146 | tab_suffixof(i) = (unsigned char) i; 147 | } 148 | 149 | do { 150 | resetbuf: 151 | { 152 | int i; 153 | int e; 154 | int o; 155 | 156 | o = posbits >> 3; 157 | e = insize - o; 158 | 159 | for (i = 0; i < e; ++i) 160 | inbuf[i] = inbuf[i + o]; 161 | 162 | insize = e; 163 | posbits = 0; 164 | } 165 | 166 | if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { 167 | rsize = safe_read(xstate->src_fd, inbuf + insize, IBUFSIZ); 168 | if (rsize < 0) 169 | bb_simple_error_msg_and_die(bb_msg_read_error); 170 | insize += rsize; 171 | } 172 | 173 | inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : 174 | (insize << 3) - (n_bits - 1)); 175 | 176 | while (inbits > posbits) { 177 | long code; 178 | 179 | if (free_ent > maxcode) { 180 | posbits = 181 | ((posbits - 1) + 182 | ((n_bits << 3) - 183 | (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); 184 | ++n_bits; 185 | if (n_bits == maxbits) { 186 | maxcode = maxmaxcode; 187 | } else { 188 | maxcode = MAXCODE(n_bits) - 1; 189 | } 190 | bitmask = (1 << n_bits) - 1; 191 | goto resetbuf; 192 | } 193 | { 194 | unsigned char *p = &inbuf[posbits >> 3]; 195 | code = ((p[0] 196 | | ((long) (p[1]) << 8) 197 | | ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; 198 | } 199 | posbits += n_bits; 200 | 201 | if (oldcode == -1) { 202 | if (code >= 256) 203 | bb_simple_error_msg_and_die("corrupted data"); /* %ld", code); */ 204 | oldcode = code; 205 | finchar = (int) oldcode; 206 | outbuf[outpos++] = (unsigned char) finchar; 207 | continue; 208 | } 209 | 210 | if (code == CLEAR && block_mode) { 211 | clear_tab_prefixof(); 212 | free_ent = FIRST - 1; 213 | posbits = 214 | ((posbits - 1) + 215 | ((n_bits << 3) - 216 | (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); 217 | n_bits = INIT_BITS; 218 | maxcode = MAXCODE(INIT_BITS) - 1; 219 | bitmask = (1 << INIT_BITS) - 1; 220 | goto resetbuf; 221 | } 222 | 223 | incode = code; 224 | stackp = de_stack; 225 | 226 | /* Special case for KwKwK string. */ 227 | if (code >= free_ent) { 228 | if (code > free_ent) { 229 | /* 230 | unsigned char *p; 231 | 232 | posbits -= n_bits; 233 | p = &inbuf[posbits >> 3]; 234 | bb_error_msg 235 | ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)", 236 | insize, posbits, p[-1], p[0], p[1], p[2], p[3], 237 | (posbits & 07)); 238 | */ 239 | bb_simple_error_msg("corrupted data"); 240 | goto err; 241 | } 242 | 243 | *--stackp = (unsigned char) finchar; 244 | code = oldcode; 245 | } 246 | 247 | /* Generate output characters in reverse order */ 248 | while (code >= 256) { 249 | if (stackp <= &htabof(0)) 250 | bb_simple_error_msg_and_die("corrupted data"); 251 | *--stackp = tab_suffixof(code); 252 | code = tab_prefixof(code); 253 | } 254 | 255 | finchar = tab_suffixof(code); 256 | *--stackp = (unsigned char) finchar; 257 | 258 | /* And put them out in forward order */ 259 | { 260 | int i; 261 | 262 | i = (int)(de_stack - stackp); 263 | if (outpos + i >= OBUFSIZ) { 264 | do { 265 | if (i > OBUFSIZ - outpos) { 266 | i = OBUFSIZ - outpos; 267 | } 268 | 269 | if (i > 0) { 270 | memcpy(outbuf + outpos, stackp, i); 271 | outpos += i; 272 | } 273 | 274 | if (outpos >= OBUFSIZ) { 275 | retval = transformer_write(xstate, outbuf, outpos); 276 | if (retval != (ssize_t)outpos) { 277 | retval = (retval == -ENOSPC)?xstate->mem_output_size_max:-1; 278 | goto err; 279 | } 280 | IF_DESKTOP(total_written += outpos;) 281 | outpos = 0; 282 | } 283 | stackp += i; 284 | i = (int)(de_stack - stackp); 285 | } while (i > 0); 286 | } else { 287 | memcpy(outbuf + outpos, stackp, i); 288 | outpos += i; 289 | } 290 | } 291 | 292 | /* Generate the new entry. */ 293 | if (free_ent < maxmaxcode) { 294 | tab_prefixof(free_ent) = (unsigned short) oldcode; 295 | tab_suffixof(free_ent) = (unsigned char) finchar; 296 | free_ent++; 297 | } 298 | 299 | /* Remember previous code. */ 300 | oldcode = incode; 301 | } 302 | } while (rsize > 0); 303 | 304 | if (outpos > 0) { 305 | retval = transformer_write(xstate, outbuf, outpos); 306 | if (retval != (ssize_t)outpos) 307 | retval = (retval == -ENOSPC)?xstate->mem_output_size_max:-1; 308 | IF_DESKTOP(total_written += outpos;) 309 | } 310 | 311 | retval = IF_DESKTOP(total_written) + 0; 312 | err: 313 | free(inbuf); 314 | free(outbuf); 315 | free(htab); 316 | free(codetab); 317 | return retval; 318 | } 319 | -------------------------------------------------------------------------------- /src/decompress_unxz.c: -------------------------------------------------------------------------------- 1 | /* 2 | * unxz implementation for Bled/busybox 3 | * 4 | * Copyright © 2014-2020 Pete Batard 5 | * Based on xz-embedded © Lasse Collin - Public Domain 6 | * 7 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 | */ 9 | 10 | #include "libbb.h" 11 | #include "bb_archive.h" 12 | 13 | #define XZ_EXTERN static 14 | // We get XZ_OPTIONS_ERROR in xz_dec_stream if this is not defined 15 | #define XZ_DEC_ANY_CHECK 16 | 17 | #define XZ_BUFSIZE BB_BUFSIZE 18 | 19 | #include "xz_dec_bcj.c" 20 | #include "xz_dec_lzma2.c" 21 | #include "xz_dec_stream.c" 22 | 23 | static void XZ_FUNC xz_crc32_init(void) 24 | { 25 | if (!global_crc32_table) 26 | global_crc32_table = crc32_filltable(NULL, 0); 27 | } 28 | 29 | static uint32_t XZ_FUNC xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) 30 | { 31 | // The XZ CRC32 is INVERTED! 32 | return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); 33 | } 34 | 35 | IF_DESKTOP(long long) int FAST_FUNC unpack_xz_stream(transformer_state_t *xstate) 36 | { 37 | IF_DESKTOP(long long) int n = 0; 38 | struct xz_buf b; 39 | struct xz_dec *s; 40 | enum xz_ret ret = XZ_STREAM_END; 41 | uint8_t *in = NULL, *out = NULL; 42 | ssize_t nwrote; 43 | 44 | xz_crc32_init(); 45 | 46 | /* 47 | * Support up to 64 MiB dictionary. The actually needed memory 48 | * is allocated once the headers have been parsed. 49 | */ 50 | s = xz_dec_init(XZ_DYNALLOC, 1 << 26); 51 | if (!s) 52 | bb_error_msg_and_err("memory allocation error"); 53 | 54 | in = xmalloc(XZ_BUFSIZE); 55 | out = xmalloc(XZ_BUFSIZE); 56 | 57 | b.in = in; 58 | b.in_pos = 0; 59 | b.in_size = 0; 60 | b.out = out; 61 | b.out_pos = 0; 62 | b.out_size = XZ_BUFSIZE; 63 | 64 | while (true) { 65 | if (b.in_pos == b.in_size) { 66 | b.in_size = safe_read(xstate->src_fd, in, XZ_BUFSIZE); 67 | if ((int)b.in_size < 0) 68 | bb_error_msg_and_err("read error (errno: %d)", errno); 69 | b.in_pos = 0; 70 | } 71 | ret = xz_dec_run(s, &b); 72 | 73 | if (b.out_pos == XZ_BUFSIZE) { 74 | nwrote = transformer_write(xstate, b.out, b.out_pos); 75 | if (nwrote == -ENOSPC) { 76 | ret = XZ_BUF_FULL; 77 | goto out; 78 | } 79 | if (nwrote < 0) { 80 | ret = XZ_DATA_ERROR; 81 | bb_error_msg_and_err("write error (errno: %d)", errno); 82 | } 83 | IF_DESKTOP(n += nwrote;) 84 | b.out_pos = 0; 85 | } 86 | 87 | if (ret == XZ_OK) 88 | continue; 89 | 90 | #ifdef XZ_DEC_ANY_CHECK 91 | if (ret == XZ_UNSUPPORTED_CHECK) { 92 | bb_error_msg("unsupported check; not verifying file integrity"); 93 | continue; 94 | } 95 | #endif 96 | 97 | nwrote = transformer_write(xstate, b.out, b.out_pos); 98 | if (nwrote == -ENOSPC) { 99 | ret = XZ_BUF_FULL; 100 | goto out; 101 | } 102 | if (nwrote < 0) { 103 | ret = XZ_DATA_ERROR; 104 | bb_error_msg_and_err("write error (errno: %d)", errno); 105 | } 106 | IF_DESKTOP(n += nwrote;) 107 | 108 | switch (ret) { 109 | case XZ_STREAM_END: 110 | ret = XZ_OK; 111 | goto out; 112 | case XZ_MEM_ERROR: 113 | bb_error_msg_and_err("memory allocation error"); 114 | case XZ_MEMLIMIT_ERROR: 115 | bb_error_msg_and_err("memory usage limit error"); 116 | case XZ_FORMAT_ERROR: 117 | bb_error_msg_and_err("not a .xz file"); 118 | case XZ_OPTIONS_ERROR: 119 | bb_error_msg_and_err("unsupported XZ header option"); 120 | case XZ_DATA_ERROR: 121 | bb_error_msg_and_err("corrupted archive"); 122 | case XZ_BUF_ERROR: 123 | bb_error_msg_and_err("corrupted buffer"); 124 | case XZ_BUF_FULL: 125 | break; 126 | default: 127 | bb_error_msg_and_err("XZ decompression bug!"); 128 | } 129 | } 130 | 131 | out: 132 | err: 133 | xz_dec_end(s); 134 | free(in); 135 | free(out); 136 | if (ret == XZ_OK) 137 | return n; 138 | else if (ret == XZ_BUF_FULL) 139 | return xstate->mem_output_size_max; 140 | else 141 | return -ret; 142 | } 143 | -------------------------------------------------------------------------------- /src/decompress_unzstd.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Glue for zstd decompression 4 | * Copyright (c) 2021 Norbert Lange 5 | * Copyright (c) 2024 Pete Batard 6 | * 7 | * Based on compress.c from the systemd project, 8 | * provided by Norbert Lange . 9 | * Which originally was copied from the streaming_decompression.c 10 | * example from the zstd project, written by Yann Collet 11 | * 12 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 13 | */ 14 | 15 | #include "libbb.h" 16 | #include "bb_archive.h" 17 | #include "zstd_deps.h" 18 | #include "zstd_internal.h" 19 | 20 | ALWAYS_INLINE static size_t roundupsize(size_t size, size_t align) 21 | { 22 | return (size + align - 1U) & ~(align - 1); 23 | } 24 | 25 | ALWAYS_INLINE static IF_DESKTOP(long long) int 26 | unpack_zstd_stream_inner(transformer_state_t *xstate, 27 | ZSTD_DStream *dctx, void *out_buff) 28 | { 29 | const U32 zstd_magic = ZSTD_MAGIC; 30 | const size_t in_allocsize = roundupsize(ZSTD_DStreamInSize(), 1024), 31 | out_allocsize = roundupsize(ZSTD_DStreamOutSize(), 1024); 32 | 33 | IF_DESKTOP(long long int total = 0;) 34 | size_t last_result = ZSTD_error_maxCode + 1; 35 | ssize_t nwrote = 0; 36 | unsigned input_fixup; 37 | void *in_buff = (char *)out_buff + out_allocsize; 38 | 39 | memcpy(in_buff, &zstd_magic, 4); 40 | input_fixup = xstate->signature_skipped ? 4 : 0; 41 | 42 | /* This loop assumes that the input file is one or more concatenated 43 | * zstd streams. This example won't work if there is trailing non-zstd 44 | * data at the end, but streaming decompression in general handles this 45 | * case. ZSTD_decompressStream() returns 0 exactly when the frame is 46 | * completed, and doesn't consume input after the frame. 47 | */ 48 | for (;;) { 49 | bool has_error = false; 50 | ZSTD_inBuffer input; 51 | ssize_t red; 52 | 53 | red = safe_read(xstate->src_fd, (char *)in_buff + input_fixup, (unsigned int)(in_allocsize - input_fixup)); 54 | if (red < 0) { 55 | bb_perror_msg(bb_msg_read_error); 56 | return -1; 57 | } 58 | if (red == 0) { 59 | break; 60 | } 61 | 62 | input.src = in_buff; 63 | input.size = (size_t)red + input_fixup; 64 | input.pos = 0; 65 | input_fixup = 0; 66 | 67 | /* Given a valid frame, zstd won't consume the last byte of the 68 | * frame until it has flushed all of the decompressed data of 69 | * the frame. So input.pos < input.size means frame is not done 70 | * or there is still output available. 71 | */ 72 | while (input.pos < input.size) { 73 | ZSTD_outBuffer output = { out_buff, out_allocsize, 0 }; 74 | /* The return code is zero if the frame is complete, but 75 | * there may be multiple frames concatenated together. 76 | * Zstd will automatically reset the context when a 77 | * frame is complete. Still, calling ZSTD_DCtx_reset() 78 | * can be useful to reset the context to a clean state, 79 | * for instance if the last decompression call returned 80 | * an error. 81 | */ 82 | last_result = ZSTD_decompressStream(dctx, &output, &input); 83 | if (ZSTD_isError(last_result)) { 84 | has_error = true; 85 | break; 86 | } 87 | 88 | nwrote = transformer_write(xstate, output.dst, output.pos); 89 | if (nwrote < 0 && nwrote != -ENOSPC) { 90 | has_error = true; 91 | break; 92 | } 93 | IF_DESKTOP(total = (nwrote == -ENOSPC) ? xstate->mem_output_size_max : total + output.pos); 94 | } 95 | if (has_error) 96 | break; 97 | } 98 | 99 | if (last_result != 0) { 100 | /* The last return value from ZSTD_decompressStream did not end 101 | * on a frame, but we reached the end of the file! We assume 102 | * this is an error, and the input was truncated. 103 | */ 104 | if (last_result == ZSTD_error_maxCode + 1) { 105 | bb_simple_error_msg("could not read zstd data"); 106 | } else { 107 | #if defined(ZSTD_STRIP_ERROR_STRINGS) && ZSTD_STRIP_ERROR_STRINGS == 1 108 | bb_error_msg("zstd decoder error: %u", (unsigned)last_result); 109 | #else 110 | bb_error_msg("zstd decoder error: %s", ZSTD_getErrorName(last_result)); 111 | #endif 112 | } 113 | return -1; 114 | } 115 | 116 | return IF_DESKTOP(total) + 0; 117 | } 118 | 119 | IF_DESKTOP(long long) int FAST_FUNC 120 | unpack_zstd_stream(transformer_state_t *xstate) 121 | { 122 | const size_t in_allocsize = roundupsize(ZSTD_DStreamInSize(), 1024), 123 | out_allocsize = roundupsize(ZSTD_DStreamOutSize(), 1024); 124 | 125 | IF_DESKTOP(long long) int result; 126 | void *out_buff; 127 | ZSTD_DStream *dctx; 128 | 129 | dctx = ZSTD_createDStream(); 130 | if (!dctx) { 131 | /* should be the only possibly reason of failure */ 132 | bb_error_msg_and_die("memory exhausted"); 133 | } 134 | 135 | out_buff = xmalloc(in_allocsize + out_allocsize); 136 | 137 | result = unpack_zstd_stream_inner(xstate, dctx, out_buff); 138 | free(out_buff); 139 | ZSTD_freeDStream(dctx); 140 | return result; 141 | } 142 | -------------------------------------------------------------------------------- /src/decompress_vtsi.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * decompress_vtsi.c 3 | * 4 | * Copyright (c) 2021, longpanda 5 | * 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 | * 8 | */ 9 | 10 | #include "libbb.h" 11 | #include "bb_archive.h" 12 | 13 | /* 14 | * Structure of a Ventoy Sparse Image (VTSI) file: 15 | * 16 | +--------------------------------- 17 | + sector 0 ~ sector N-1 18 | + data area 19 | +--------------------------------- 20 | + sector N ~ sector M - 1 21 | + segment[0] 22 | + segment[1] 23 | + segment[2] 24 | + ..... 25 | + (may be some align data (segment data aligned with 512) ...) 26 | +--------------------------------- 27 | + sector M 28 | + footer 29 | +--------------------------------- 30 | * 31 | * All the integers are in little endian 32 | * The sector size is fixed 512 for ventoy image file. 33 | * 34 | */ 35 | 36 | #define VTSI_MAGIC 0x0000594F544E4556ULL // "VENTOY\0\0" 37 | 38 | #pragma pack(1) 39 | 40 | typedef struct { 41 | uint64_t disk_start_sector; 42 | uint64_t sector_num; 43 | uint64_t data_offset; 44 | } VTSI_SEGMENT; 45 | 46 | typedef struct { 47 | uint64_t magic; 48 | uint16_t version_major; 49 | uint16_t version_minor; 50 | uint64_t disk_size; 51 | uint32_t disk_signature; 52 | uint32_t foot_chksum; 53 | 54 | uint32_t segment_num; 55 | uint32_t segment_chksum; 56 | uint64_t segment_offset; 57 | 58 | uint8_t reserved[512 - 44]; 59 | } VTSI_FOOTER; 60 | 61 | #pragma pack() 62 | 63 | extern int __static_assert__[sizeof(VTSI_FOOTER) == 512 ? 1 : -1]; 64 | 65 | #define MAX_READ_BUF (8 * 1024 * 1024) 66 | 67 | static int check_vtsi_footer(VTSI_FOOTER* footer) 68 | { 69 | int valid = 0; 70 | uint32_t i, oldsum, calcsum; 71 | 72 | if (footer->magic != VTSI_MAGIC) 73 | bb_error_msg_and_err("invalid vtsi magic 0x%llX", footer->magic); 74 | 75 | /* check footer checksum */ 76 | oldsum = footer->foot_chksum; 77 | footer->foot_chksum = 0; 78 | for (i = 0, calcsum = 0; i < sizeof(VTSI_FOOTER); i++) 79 | calcsum += *((uint8_t*)footer + i); 80 | calcsum = ~calcsum; 81 | 82 | if (calcsum != oldsum) 83 | bb_error_msg_and_err("invalid vtsi footer chksum 0x%X 0x%X", calcsum, oldsum); 84 | 85 | /* check version (if the major doesn't match, we consider that a breaking change occurred) */ 86 | if (footer->version_major != 1) 87 | bb_error_msg_and_err("unsupported vtsi version %d.%d", footer->version_major, footer->version_minor); 88 | 89 | valid = 1; 90 | err: 91 | return valid; 92 | } 93 | 94 | static int check_vtsi_segment(VTSI_FOOTER* footer, VTSI_SEGMENT* segment) 95 | { 96 | int valid = 0; 97 | uint32_t i, oldsum, calcsum; 98 | 99 | /* check segment checksum */ 100 | oldsum = footer->segment_chksum; 101 | 102 | for (i = 0, calcsum = 0; i < sizeof(VTSI_SEGMENT) * footer->segment_num; i++) 103 | calcsum += *((uint8_t*)segment + i); 104 | calcsum = ~calcsum; 105 | 106 | if (calcsum != oldsum) 107 | bb_error_msg_and_err("invalid vtsi segment chksum 0x%X 0x%X", calcsum, oldsum); 108 | 109 | valid = 1; 110 | err: 111 | return valid; 112 | } 113 | 114 | IF_DESKTOP(long long) int FAST_FUNC unpack_vtsi_stream(transformer_state_t* xstate) 115 | { 116 | IF_DESKTOP(long long) int n = -EFAULT; 117 | long long tot = 0; 118 | off_t src_size; 119 | int src_fd = 0; 120 | size_t wsize = 0; 121 | ssize_t retval = 0; 122 | uint64_t seg = 0; 123 | int64_t datalen = 0; 124 | uint64_t phy_offset = 0; 125 | size_t max_buflen = MAX_READ_BUF; 126 | uint8_t* buf = NULL; 127 | VTSI_SEGMENT* segment = NULL; 128 | VTSI_SEGMENT* cur_seg = NULL; 129 | VTSI_FOOTER footer; 130 | 131 | if (xstate->dst_dir) 132 | bb_error_msg_and_err("decompress to dir is not supported"); 133 | 134 | src_fd = xstate->src_fd; 135 | src_size = lseek(src_fd, 0, SEEK_END); 136 | lseek(src_fd, src_size - sizeof(VTSI_FOOTER), SEEK_SET); 137 | 138 | safe_read(src_fd, &footer, sizeof(footer)); 139 | if (!check_vtsi_footer(&footer)) 140 | goto err; 141 | 142 | if (xstate->mem_output_size_max == 512) 143 | max_buflen = 1024; 144 | 145 | segment = xmalloc(footer.segment_num * sizeof(VTSI_SEGMENT) + max_buflen); 146 | if (!segment) 147 | bb_error_msg_and_err("Failed to alloc segment buffer %u", footer.segment_num); 148 | 149 | buf = (uint8_t*)segment + footer.segment_num * sizeof(VTSI_SEGMENT); 150 | 151 | lseek(src_fd, footer.segment_offset, SEEK_SET); 152 | safe_read(src_fd, segment, footer.segment_num * sizeof(VTSI_SEGMENT)); 153 | 154 | if (!check_vtsi_segment(&footer, segment)) 155 | goto err; 156 | 157 | /* read data */ 158 | lseek(src_fd, 0, SEEK_SET); 159 | for (seg = 0; seg < footer.segment_num; seg++) { 160 | cur_seg = segment + seg; 161 | datalen = (int64_t)cur_seg->sector_num * 512; 162 | phy_offset = cur_seg->disk_start_sector * 512; 163 | 164 | if (xstate->mem_output_size_max == 0 && xstate->dst_fd >= 0) 165 | lseek(xstate->dst_fd, phy_offset, SEEK_SET); 166 | 167 | while (datalen > 0) { 168 | wsize = MIN((size_t)datalen, max_buflen); 169 | safe_read(src_fd, buf, (unsigned int)wsize); 170 | 171 | retval = transformer_write(xstate, buf, wsize); 172 | if (retval != (ssize_t)wsize) { 173 | n = (retval == -ENOSPC) ? xstate->mem_output_size_max : -1; 174 | goto err; 175 | } 176 | 177 | tot += retval; 178 | datalen -= wsize; 179 | } 180 | } 181 | 182 | n = tot; 183 | 184 | err: 185 | if (segment) 186 | free(segment); 187 | 188 | return n; 189 | } 190 | -------------------------------------------------------------------------------- /src/filter_accept_all.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Copyright (C) 2002 by Glenn McGrath 4 | * 5 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 | */ 7 | #include "libbb.h" 8 | #include "bb_archive.h" 9 | 10 | /* Accept any non-null name, its not really a filter at all */ 11 | char FAST_FUNC filter_accept_all(archive_handle_t *archive_handle) 12 | { 13 | if (archive_handle->file_header->name) 14 | return EXIT_SUCCESS; 15 | return EXIT_FAILURE; 16 | } 17 | -------------------------------------------------------------------------------- /src/filter_accept_list.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Copyright (C) 2002 by Glenn McGrath 4 | * 5 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 | */ 7 | #include "libbb.h" 8 | #include "bb_archive.h" 9 | 10 | /* 11 | * Accept names that are in the accept list, ignoring reject list. 12 | */ 13 | char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle) 14 | { 15 | if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) 16 | return EXIT_SUCCESS; 17 | return EXIT_FAILURE; 18 | } 19 | -------------------------------------------------------------------------------- /src/filter_accept_reject_list.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Copyright (C) 2002 by Glenn McGrath 4 | * 5 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 | */ 7 | 8 | #include "libbb.h" 9 | #include "bb_archive.h" 10 | 11 | /* 12 | * Accept names that are in the accept list and not in the reject list 13 | */ 14 | char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle) 15 | { 16 | const char *key; 17 | const llist_t *reject_entry; 18 | const llist_t *accept_entry; 19 | 20 | key = archive_handle->file_header->name; 21 | 22 | /* If the key is in a reject list fail */ 23 | reject_entry = find_list_entry2(archive_handle->reject, key); 24 | if (reject_entry) { 25 | return EXIT_FAILURE; 26 | } 27 | 28 | /* Fail if an accept list was specified and the key wasnt in there */ 29 | if (archive_handle->accept) { 30 | accept_entry = find_list_entry2(archive_handle->accept, key); 31 | if (!accept_entry) { 32 | return EXIT_FAILURE; 33 | } 34 | } 35 | 36 | /* Accepted */ 37 | return EXIT_SUCCESS; 38 | } 39 | -------------------------------------------------------------------------------- /src/find_list_entry.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Copyright (C) 2002 by Glenn McGrath 4 | * 5 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 6 | */ 7 | 8 | #include "libbb.h" 9 | #include "bb_archive.h" 10 | 11 | /* Find a string in a shell pattern list */ 12 | const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) 13 | { 14 | while (list) { 15 | if (fnmatch(list->data, filename, 0) == 0) { 16 | return list; 17 | } 18 | list = list->link; 19 | } 20 | return NULL; 21 | } 22 | 23 | /* Same, but compares only path components present in pattern 24 | * (extra trailing path components in filename are assumed to match) 25 | */ 26 | const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename) 27 | { 28 | char buf[PATH_MAX]; 29 | int pattern_slash_cnt; 30 | const char *c; 31 | char *d; 32 | 33 | while (list) { 34 | c = list->data; 35 | pattern_slash_cnt = 0; 36 | while (*c) 37 | if (*c++ == '/') pattern_slash_cnt++; 38 | c = filename; 39 | d = buf; 40 | /* paranoia is better than buffer overflows */ 41 | while (*c && d != buf + sizeof(buf)-1) { 42 | if (*c == '/' && --pattern_slash_cnt < 0) 43 | break; 44 | *d++ = *c++; 45 | } 46 | *d = '\0'; 47 | if (fnmatch(list->data, buf, 0) == 0) { 48 | return list; 49 | } 50 | list = list->link; 51 | } 52 | return NULL; 53 | } 54 | -------------------------------------------------------------------------------- /src/header_list.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC header_list(const file_header_t *file_header) 9 | { 10 | //TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */ 11 | puts(file_header->name); 12 | } 13 | -------------------------------------------------------------------------------- /src/header_skip.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /src/header_verbose_list.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC header_verbose_list(const file_header_t *file_header) 9 | { 10 | struct tm tm_time; 11 | struct tm *ptm = &tm_time; //localtime(&file_header->mtime); 12 | char modestr[12]; 13 | 14 | #if ENABLE_FEATURE_TAR_UNAME_GNAME 15 | char uid[sizeof(int)*3 + 2]; 16 | /*char gid[sizeof(int)*3 + 2];*/ 17 | char *user; 18 | char *group; 19 | 20 | localtime_r(&file_header->mtime, ptm); 21 | 22 | user = file_header->tar__uname; 23 | if (user == NULL) { 24 | sprintf(uid, "%u", (unsigned)file_header->uid); 25 | user = uid; 26 | } 27 | group = file_header->tar__gname; 28 | if (group == NULL) { 29 | /*sprintf(gid, "%u", (unsigned)file_header->gid);*/ 30 | group = utoa(file_header->gid); 31 | } 32 | printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", 33 | bb_mode_string(modestr, file_header->mode), 34 | user, 35 | group, 36 | file_header->size, 37 | 1900 + ptm->tm_year, 38 | 1 + ptm->tm_mon, 39 | ptm->tm_mday, 40 | ptm->tm_hour, 41 | ptm->tm_min, 42 | ptm->tm_sec, 43 | file_header->name); 44 | 45 | #else /* !FEATURE_TAR_UNAME_GNAME */ 46 | 47 | localtime_r(&file_header->mtime, ptm); 48 | 49 | printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", 50 | bb_mode_string(modestr, file_header->mode), 51 | (unsigned)file_header->uid, 52 | (unsigned)file_header->gid, 53 | file_header->size, 54 | 1900 + ptm->tm_year, 55 | 1 + ptm->tm_mon, 56 | ptm->tm_mday, 57 | ptm->tm_hour, 58 | ptm->tm_min, 59 | ptm->tm_sec, 60 | file_header->name); 61 | 62 | #endif /* FEATURE_TAR_UNAME_GNAME */ 63 | 64 | /* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */ 65 | if (file_header->link_target) { 66 | printf(" -> %s", file_header->link_target); 67 | } 68 | bb_putchar('\n'); 69 | } 70 | -------------------------------------------------------------------------------- /src/init_handle.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | archive_handle_t* FAST_FUNC init_handle(void) 9 | { 10 | archive_handle_t *archive_handle; 11 | 12 | /* Initialize default values */ 13 | archive_handle = xzalloc(sizeof(archive_handle_t)); 14 | if (archive_handle == NULL) 15 | return NULL; 16 | archive_handle->file_header = xzalloc(sizeof(file_header_t)); 17 | archive_handle->action_header = header_skip; 18 | archive_handle->action_data = data_skip; 19 | archive_handle->filter = filter_accept_all; 20 | archive_handle->seek = seek_by_jump; 21 | #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM 22 | archive_handle->cpio__owner.uid = (uid_t)-1L; 23 | archive_handle->cpio__owner.gid = (gid_t)-1L; 24 | #endif 25 | 26 | return archive_handle; 27 | } 28 | -------------------------------------------------------------------------------- /src/seek_by_jump.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | void FAST_FUNC seek_by_jump(int fd, off_t amount) 9 | { 10 | if (amount 11 | && lseek(fd, amount, SEEK_CUR) == (off_t) -1 12 | ) { 13 | if (errno == ESPIPE) 14 | seek_by_read(fd, amount); 15 | else 16 | bb_perror_msg_and_die("seek failure"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/seek_by_read.c: -------------------------------------------------------------------------------- 1 | /* vi: set sw=4 ts=4: */ 2 | /* 3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 4 | */ 5 | #include "libbb.h" 6 | #include "bb_archive.h" 7 | 8 | /* If we are reading through a pipe, or from stdin then we can't lseek, 9 | * we must read and discard the data to skip over it. 10 | */ 11 | void FAST_FUNC seek_by_read(int fd, off_t amount) 12 | { 13 | if (amount) 14 | bb_copyfd_exact_size(fd, -1, amount); 15 | } 16 | -------------------------------------------------------------------------------- /src/xxhash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xxHash - Extremely Fast Hash algorithm 3 | * Copyright (c) Yann Collet - Meta Platforms, Inc 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | /* 12 | * xxhash.c instantiates functions defined in xxhash.h 13 | */ 14 | 15 | #define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ 16 | #define XXH_IMPLEMENTATION /* access definitions */ 17 | 18 | #include "xxhash.h" 19 | -------------------------------------------------------------------------------- /src/xz_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Private includes and definitions for userspace use of XZ Embedded 3 | * 4 | * Author: Lasse Collin 5 | * 6 | * This file has been put into the public domain. 7 | * You can do whatever you want with this file. 8 | */ 9 | 10 | #ifndef XZ_CONFIG_H 11 | #define XZ_CONFIG_H 12 | 13 | /* Uncomment as needed to enable BCJ filter decoders. */ 14 | #define XZ_DEC_X86 15 | /* #define XZ_DEC_POWERPC */ 16 | /* #define XZ_DEC_IA64 */ 17 | /* #define XZ_DEC_ARM */ 18 | /* #define XZ_DEC_ARMTHUMB */ 19 | /* #define XZ_DEC_SPARC */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "xz.h" 26 | 27 | #define kmalloc(size, flags) malloc(size) 28 | #define kfree(ptr) free(ptr) 29 | #define vmalloc(size) malloc(size) 30 | #define vfree(ptr) free(ptr) 31 | 32 | #define memeq(a, b, size) (memcmp(a, b, size) == 0) 33 | #define memzero(buf, size) memset(buf, 0, size) 34 | 35 | #undef min 36 | #undef min_t 37 | #define min(x, y) ((x) < (y) ? (x) : (y)) 38 | #define min_t(type, x, y) min(x, y) 39 | 40 | /* 41 | * Some functions have been marked with __always_inline to keep the 42 | * performance reasonable even when the compiler is optimizing for 43 | * small code size. You may be able to save a few bytes by #defining 44 | * __always_inline to plain inline, but don't complain if the code 45 | * becomes slow. 46 | * 47 | * NOTE: System headers on GNU/Linux may #define this macro already, 48 | * so if you want to change it, you need to #undef it first. 49 | */ 50 | #ifndef __always_inline 51 | # ifdef __GNUC__ 52 | # define __always_inline \ 53 | inline __attribute__((__always_inline__)) 54 | # else 55 | # define __always_inline inline 56 | # endif 57 | #endif 58 | 59 | /* 60 | * Some functions are marked to never be inlined to reduce stack usage. 61 | * If you don't care about stack usage, you may want to modify this so 62 | * that noinline_for_stack is #defined to be empty even when using GCC. 63 | * Doing so may save a few bytes in binary size. 64 | */ 65 | #ifndef noinline_for_stack 66 | # ifdef __GNUC__ 67 | # define noinline_for_stack __attribute__((__noinline__)) 68 | # else 69 | # define noinline_for_stack 70 | # endif 71 | #endif 72 | 73 | /* Inline functions to access unaligned unsigned 32-bit integers */ 74 | #ifndef get_unaligned_le32 75 | static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf) 76 | { 77 | return (uint32_t)buf[0] 78 | | ((uint32_t)buf[1] << 8) 79 | | ((uint32_t)buf[2] << 16) 80 | | ((uint32_t)buf[3] << 24); 81 | } 82 | #endif 83 | 84 | #ifndef get_unaligned_be32 85 | static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf) 86 | { 87 | return (uint32_t)(buf[0] << 24) 88 | | ((uint32_t)buf[1] << 16) 89 | | ((uint32_t)buf[2] << 8) 90 | | (uint32_t)buf[3]; 91 | } 92 | #endif 93 | 94 | #ifndef put_unaligned_le32 95 | static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf) 96 | { 97 | buf[0] = (uint8_t)val; 98 | buf[1] = (uint8_t)(val >> 8); 99 | buf[2] = (uint8_t)(val >> 16); 100 | buf[3] = (uint8_t)(val >> 24); 101 | } 102 | #endif 103 | 104 | #ifndef put_unaligned_be32 105 | static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf) 106 | { 107 | buf[0] = (uint8_t)(val >> 24); 108 | buf[1] = (uint8_t)(val >> 16); 109 | buf[2] = (uint8_t)(val >> 8); 110 | buf[3] = (uint8_t)val; 111 | } 112 | #endif 113 | 114 | /* 115 | * Use get_unaligned_le32() also for aligned access for simplicity. On 116 | * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr)) 117 | * could save a few bytes in code size. 118 | */ 119 | #ifndef get_le32 120 | # define get_le32 get_unaligned_le32 121 | #endif 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/xz_lzma2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LZMA2 definitions 3 | * 4 | * Authors: Lasse Collin 5 | * Igor Pavlov 6 | * 7 | * This file has been put into the public domain. 8 | * You can do whatever you want with this file. 9 | */ 10 | 11 | #ifndef XZ_LZMA2_H 12 | #define XZ_LZMA2_H 13 | 14 | /* Range coder constants */ 15 | #define RC_SHIFT_BITS 8 16 | #define RC_TOP_BITS 24 17 | #define RC_TOP_VALUE (1 << RC_TOP_BITS) 18 | #define RC_BIT_MODEL_TOTAL_BITS 11 19 | #define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) 20 | #define RC_MOVE_BITS 5 21 | 22 | /* 23 | * Maximum number of position states. A position state is the lowest pb 24 | * number of bits of the current uncompressed offset. In some places there 25 | * are different sets of probabilities for different position states. 26 | */ 27 | #define POS_STATES_MAX (1 << 4) 28 | 29 | /* 30 | * This enum is used to track which LZMA symbols have occurred most recently 31 | * and in which order. This information is used to predict the next symbol. 32 | * 33 | * Symbols: 34 | * - Literal: One 8-bit byte 35 | * - Match: Repeat a chunk of data at some distance 36 | * - Long repeat: Multi-byte match at a recently seen distance 37 | * - Short repeat: One-byte repeat at a recently seen distance 38 | * 39 | * The symbol names are in from STATE_oldest_older_previous. REP means 40 | * either short or long repeated match, and NONLIT means any non-literal. 41 | */ 42 | enum lzma_state { 43 | STATE_LIT_LIT, 44 | STATE_MATCH_LIT_LIT, 45 | STATE_REP_LIT_LIT, 46 | STATE_SHORTREP_LIT_LIT, 47 | STATE_MATCH_LIT, 48 | STATE_REP_LIT, 49 | STATE_SHORTREP_LIT, 50 | STATE_LIT_MATCH, 51 | STATE_LIT_LONGREP, 52 | STATE_LIT_SHORTREP, 53 | STATE_NONLIT_MATCH, 54 | STATE_NONLIT_REP 55 | }; 56 | 57 | /* Total number of states */ 58 | #define STATES 12 59 | 60 | /* The lowest 7 states indicate that the previous state was a literal. */ 61 | #define LIT_STATES 7 62 | 63 | /* Indicate that the latest symbol was a literal. */ 64 | static inline void XZ_FUNC lzma_state_literal(enum lzma_state *state) 65 | { 66 | if (*state <= STATE_SHORTREP_LIT_LIT) 67 | *state = STATE_LIT_LIT; 68 | else if (*state <= STATE_LIT_SHORTREP) 69 | *state -= 3; 70 | else 71 | *state -= 6; 72 | } 73 | 74 | /* Indicate that the latest symbol was a match. */ 75 | static inline void XZ_FUNC lzma_state_match(enum lzma_state *state) 76 | { 77 | *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; 78 | } 79 | 80 | /* Indicate that the latest state was a long repeated match. */ 81 | static inline void XZ_FUNC lzma_state_long_rep(enum lzma_state *state) 82 | { 83 | *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; 84 | } 85 | 86 | /* Indicate that the latest symbol was a short match. */ 87 | static inline void XZ_FUNC lzma_state_short_rep(enum lzma_state *state) 88 | { 89 | *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; 90 | } 91 | 92 | /* Test if the previous symbol was a literal. */ 93 | static inline bool XZ_FUNC lzma_state_is_literal(enum lzma_state state) 94 | { 95 | return state < LIT_STATES; 96 | } 97 | 98 | /* Each literal coder is divided in three sections: 99 | * - 0x001-0x0FF: Without match byte 100 | * - 0x101-0x1FF: With match byte; match bit is 0 101 | * - 0x201-0x2FF: With match byte; match bit is 1 102 | * 103 | * Match byte is used when the previous LZMA symbol was something else than 104 | * a literal (that is, it was some kind of match). 105 | */ 106 | #define LITERAL_CODER_SIZE 0x300 107 | 108 | /* Maximum number of literal coders */ 109 | #define LITERAL_CODERS_MAX (1 << 4) 110 | 111 | /* Minimum length of a match is two bytes. */ 112 | #define MATCH_LEN_MIN 2 113 | 114 | /* Match length is encoded with 4, 5, or 10 bits. 115 | * 116 | * Length Bits 117 | * 2-9 4 = Choice=0 + 3 bits 118 | * 10-17 5 = Choice=1 + Choice2=0 + 3 bits 119 | * 18-273 10 = Choice=1 + Choice2=1 + 8 bits 120 | */ 121 | #define LEN_LOW_BITS 3 122 | #define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) 123 | #define LEN_MID_BITS 3 124 | #define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) 125 | #define LEN_HIGH_BITS 8 126 | #define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) 127 | #define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) 128 | 129 | /* 130 | * Maximum length of a match is 273 which is a result of the encoding 131 | * described above. 132 | */ 133 | #define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) 134 | 135 | /* 136 | * Different sets of probabilities are used for match distances that have 137 | * very short match length: Lengths of 2, 3, and 4 bytes have a separate 138 | * set of probabilities for each length. The matches with longer length 139 | * use a shared set of probabilities. 140 | */ 141 | #define DIST_STATES 4 142 | 143 | /* 144 | * Get the index of the appropriate probability array for decoding 145 | * the distance slot. 146 | */ 147 | static inline uint32_t XZ_FUNC lzma_get_dist_state(uint32_t len) 148 | { 149 | return len < DIST_STATES + MATCH_LEN_MIN 150 | ? len - MATCH_LEN_MIN : DIST_STATES - 1; 151 | } 152 | 153 | /* 154 | * The highest two bits of a 32-bit match distance are encoded using six bits. 155 | * This six-bit value is called a distance slot. This way encoding a 32-bit 156 | * value takes 6-36 bits, larger values taking more bits. 157 | */ 158 | #define DIST_SLOT_BITS 6 159 | #define DIST_SLOTS (1 << DIST_SLOT_BITS) 160 | 161 | /* Match distances up to 127 are fully encoded using probabilities. Since 162 | * the highest two bits (distance slot) are always encoded using six bits, 163 | * the distances 0-3 don't need any additional bits to encode, since the 164 | * distance slot itself is the same as the actual distance. DIST_MODEL_START 165 | * indicates the first distance slot where at least one additional bit is 166 | * needed. 167 | */ 168 | #define DIST_MODEL_START 4 169 | 170 | /* 171 | * Match distances greater than 127 are encoded in three pieces: 172 | * - distance slot: the highest two bits 173 | * - direct bits: 2-26 bits below the highest two bits 174 | * - alignment bits: four lowest bits 175 | * 176 | * Direct bits don't use any probabilities. 177 | * 178 | * The distance slot value of 14 is for distances 128-191. 179 | */ 180 | #define DIST_MODEL_END 14 181 | 182 | /* Distance slots that indicate a distance <= 127. */ 183 | #define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) 184 | #define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) 185 | 186 | /* 187 | * For match distances greater than 127, only the highest two bits and the 188 | * lowest four bits (alignment) is encoded using probabilities. 189 | */ 190 | #define ALIGN_BITS 4 191 | #define ALIGN_SIZE (1 << ALIGN_BITS) 192 | #define ALIGN_MASK (ALIGN_SIZE - 1) 193 | 194 | /* Total number of all probability variables */ 195 | #define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) 196 | 197 | /* 198 | * LZMA remembers the four most recent match distances. Reusing these 199 | * distances tends to take less space than re-encoding the actual 200 | * distance value. 201 | */ 202 | #define REPS 4 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /src/xz_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Private includes and definitions 3 | * 4 | * Author: Lasse Collin 5 | * 6 | * This file has been put into the public domain. 7 | * You can do whatever you want with this file. 8 | */ 9 | 10 | #ifndef XZ_PRIVATE_H 11 | #define XZ_PRIVATE_H 12 | 13 | #ifdef __KERNEL__ 14 | /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ 15 | # ifndef XZ_PREBOOT 16 | # include 17 | # include 18 | # include 19 | # define memeq(a, b, size) (memcmp(a, b, size) == 0) 20 | # define memzero(buf, size) memset(buf, 0, size) 21 | # endif 22 | # include 23 | # include 24 | # define get_le32(p) le32_to_cpup((const uint32_t *)(p)) 25 | /* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */ 26 | # ifndef XZ_IGNORE_KCONFIG 27 | # ifdef CONFIG_XZ_DEC_X86 28 | # define XZ_DEC_X86 29 | # endif 30 | # ifdef CONFIG_XZ_DEC_POWERPC 31 | # define XZ_DEC_POWERPC 32 | # endif 33 | # ifdef CONFIG_XZ_DEC_IA64 34 | # define XZ_DEC_IA64 35 | # endif 36 | # ifdef CONFIG_XZ_DEC_ARM 37 | # define XZ_DEC_ARM 38 | # endif 39 | # ifdef CONFIG_XZ_DEC_ARMTHUMB 40 | # define XZ_DEC_ARMTHUMB 41 | # endif 42 | # ifdef CONFIG_XZ_DEC_SPARC 43 | # define XZ_DEC_SPARC 44 | # endif 45 | # endif 46 | # include 47 | #else 48 | /* 49 | * For userspace builds, use a separate header to define the required 50 | * macros and functions. This makes it easier to adapt the code into 51 | * different environments and avoids clutter in the Linux kernel tree. 52 | */ 53 | # include "xz_config.h" 54 | #endif 55 | 56 | /* If no specific decoding mode is requested, enable support for all modes. */ 57 | #if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ 58 | && !defined(XZ_DEC_DYNALLOC) 59 | # define XZ_DEC_SINGLE 60 | # define XZ_DEC_PREALLOC 61 | # define XZ_DEC_DYNALLOC 62 | #endif 63 | 64 | /* 65 | * The DEC_IS_foo(mode) macros are used in "if" statements. If only some 66 | * of the supported modes are enabled, these macros will evaluate to true or 67 | * false at compile time and thus allow the compiler to omit unneeded code. 68 | */ 69 | #ifdef XZ_DEC_SINGLE 70 | # define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) 71 | #else 72 | # define DEC_IS_SINGLE(mode) (false) 73 | #endif 74 | 75 | #ifdef XZ_DEC_PREALLOC 76 | # define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) 77 | #else 78 | # define DEC_IS_PREALLOC(mode) (false) 79 | #endif 80 | 81 | #ifdef XZ_DEC_DYNALLOC 82 | # define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) 83 | #else 84 | # define DEC_IS_DYNALLOC(mode) (false) 85 | #endif 86 | 87 | #if !defined(XZ_DEC_SINGLE) 88 | # define DEC_IS_MULTI(mode) (true) 89 | #elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) 90 | # define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) 91 | #else 92 | # define DEC_IS_MULTI(mode) (false) 93 | #endif 94 | 95 | /* 96 | * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. 97 | * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. 98 | */ 99 | #ifndef XZ_DEC_BCJ 100 | # if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ 101 | || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ 102 | || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ 103 | || defined(XZ_DEC_SPARC) 104 | # define XZ_DEC_BCJ 105 | # endif 106 | #endif 107 | 108 | /* 109 | * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used 110 | * before calling xz_dec_lzma2_run(). 111 | */ 112 | XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( 113 | enum xz_mode mode, uint32_t dict_max); 114 | 115 | /* 116 | * Decode the LZMA2 properties (one byte) and reset the decoder. Return 117 | * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not 118 | * big enough, and XZ_OPTIONS_ERROR if props indicates something that this 119 | * decoder doesn't support. 120 | */ 121 | XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( 122 | struct xz_dec_lzma2 *s, uint8_t props); 123 | 124 | /* Decode raw LZMA2 stream from b->in to b->out. */ 125 | XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run( 126 | struct xz_dec_lzma2 *s, struct xz_buf *b); 127 | 128 | /* Free the memory allocated for the LZMA2 decoder. */ 129 | XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s); 130 | 131 | #ifdef XZ_DEC_BCJ 132 | /* 133 | * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before 134 | * calling xz_dec_bcj_run(). 135 | */ 136 | XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call); 137 | 138 | /* 139 | * Decode the Filter ID of a BCJ filter. This implementation doesn't 140 | * support custom start offsets, so no decoding of Filter Properties 141 | * is needed. Returns XZ_OK if the given Filter ID is supported. 142 | * Otherwise XZ_OPTIONS_ERROR is returned. 143 | */ 144 | XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( 145 | struct xz_dec_bcj *s, uint8_t id); 146 | 147 | /* 148 | * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is 149 | * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() 150 | * must be called directly. 151 | */ 152 | XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, 153 | struct xz_dec_lzma2 *lzma2, struct xz_buf *b); 154 | 155 | /* Free the memory allocated for the BCJ filters. */ 156 | #define xz_dec_bcj_end(s) kfree(s) 157 | #endif 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /src/xz_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Definitions for handling the .xz file format 3 | * 4 | * Author: Lasse Collin 5 | * 6 | * This file has been put into the public domain. 7 | * You can do whatever you want with this file. 8 | */ 9 | 10 | #ifndef XZ_STREAM_H 11 | #define XZ_STREAM_H 12 | 13 | #if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 14 | # include 15 | # undef crc32 16 | # define xz_crc32(buf, size, crc) \ 17 | (~crc32_le(~(uint32_t)(crc), buf, size)) 18 | #endif 19 | 20 | /* 21 | * See the .xz file format specification at 22 | * http://tukaani.org/xz/xz-file-format.txt 23 | * to understand the container format. 24 | */ 25 | 26 | #define STREAM_HEADER_SIZE 12 27 | 28 | #define HEADER_MAGIC "\xFD" "7zXZ" 29 | #define HEADER_MAGIC_SIZE 6 30 | 31 | #define FOOTER_MAGIC "YZ" 32 | #define FOOTER_MAGIC_SIZE 2 33 | 34 | /* 35 | * Variable-length integer can hold a 63-bit unsigned integer or a special 36 | * value indicating that the value is unknown. 37 | * 38 | * Experimental: vli_type can be defined to uint32_t to save a few bytes 39 | * in code size (no effect on speed). Doing so limits the uncompressed and 40 | * compressed size of the file to less than 256 MiB and may also weaken 41 | * error detection slightly. 42 | */ 43 | typedef uint64_t vli_type; 44 | 45 | #define VLI_MAX ((vli_type)-1 / 2) 46 | #define VLI_UNKNOWN ((vli_type)-1) 47 | 48 | /* Maximum encoded size of a VLI */ 49 | #define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) 50 | 51 | /* Integrity Check types */ 52 | enum xz_check { 53 | XZ_CHECK_NONE = 0, 54 | XZ_CHECK_CRC32 = 1, 55 | XZ_CHECK_CRC64 = 4, 56 | XZ_CHECK_SHA256 = 10 57 | }; 58 | 59 | /* Maximum possible Check ID */ 60 | #define XZ_CHECK_MAX 15 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/zstd_bits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | #ifndef ZSTD_BITS_H 12 | #define ZSTD_BITS_H 13 | 14 | #include "zstd_mem.h" 15 | 16 | MEM_STATIC unsigned ZSTD_countTrailingZeros32_fallback(U32 val) 17 | { 18 | assert(val != 0); 19 | { 20 | static const U32 DeBruijnBytePos[32] = {0, 1, 28, 2, 29, 14, 24, 3, 21 | 30, 22, 20, 15, 25, 17, 4, 8, 22 | 31, 27, 13, 23, 21, 19, 16, 7, 23 | 26, 12, 18, 6, 11, 5, 10, 9}; 24 | return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; 25 | } 26 | } 27 | 28 | MEM_STATIC unsigned ZSTD_countTrailingZeros32(U32 val) 29 | { 30 | assert(val != 0); 31 | # if defined(_MSC_VER) 32 | # if STATIC_BMI2 == 1 33 | return (unsigned)_tzcnt_u32(val); 34 | # else 35 | if (val != 0) { 36 | unsigned long r; 37 | _BitScanForward(&r, val); 38 | return (unsigned)r; 39 | } else { 40 | /* Should not reach this code path */ 41 | __assume(0); 42 | } 43 | # endif 44 | # elif defined(__GNUC__) && (__GNUC__ >= 4) 45 | return (unsigned)__builtin_ctz(val); 46 | # elif defined(__ICCARM__) 47 | return (unsigned)__builtin_ctz(val); 48 | # else 49 | return ZSTD_countTrailingZeros32_fallback(val); 50 | # endif 51 | } 52 | 53 | MEM_STATIC unsigned ZSTD_countLeadingZeros32_fallback(U32 val) { 54 | assert(val != 0); 55 | { 56 | static const U32 DeBruijnClz[32] = {0, 9, 1, 10, 13, 21, 2, 29, 57 | 11, 14, 16, 18, 22, 25, 3, 30, 58 | 8, 12, 20, 28, 15, 17, 24, 7, 59 | 19, 27, 23, 6, 26, 5, 4, 31}; 60 | val |= val >> 1; 61 | val |= val >> 2; 62 | val |= val >> 4; 63 | val |= val >> 8; 64 | val |= val >> 16; 65 | return 31 - DeBruijnClz[(val * 0x07C4ACDDU) >> 27]; 66 | } 67 | } 68 | 69 | MEM_STATIC unsigned ZSTD_countLeadingZeros32(U32 val) 70 | { 71 | assert(val != 0); 72 | # if defined(_MSC_VER) 73 | # if STATIC_BMI2 == 1 74 | return (unsigned)_lzcnt_u32(val); 75 | # else 76 | if (val != 0) { 77 | unsigned long r; 78 | _BitScanReverse(&r, val); 79 | return (unsigned)(31 - r); 80 | } else { 81 | /* Should not reach this code path */ 82 | __assume(0); 83 | } 84 | # endif 85 | # elif defined(__GNUC__) && (__GNUC__ >= 4) 86 | return (unsigned)__builtin_clz(val); 87 | # elif defined(__ICCARM__) 88 | return (unsigned)__builtin_clz(val); 89 | # else 90 | return ZSTD_countLeadingZeros32_fallback(val); 91 | # endif 92 | } 93 | 94 | MEM_STATIC unsigned ZSTD_countTrailingZeros64(U64 val) 95 | { 96 | assert(val != 0); 97 | # if defined(_MSC_VER) && defined(_WIN64) 98 | # if STATIC_BMI2 == 1 99 | return (unsigned)_tzcnt_u64(val); 100 | # else 101 | if (val != 0) { 102 | unsigned long r; 103 | _BitScanForward64(&r, val); 104 | return (unsigned)r; 105 | } else { 106 | /* Should not reach this code path */ 107 | __assume(0); 108 | } 109 | # endif 110 | # elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(__LP64__) 111 | return (unsigned)__builtin_ctzll(val); 112 | # elif defined(__ICCARM__) 113 | return (unsigned)__builtin_ctzll(val); 114 | # else 115 | { 116 | U32 mostSignificantWord = (U32)(val >> 32); 117 | U32 leastSignificantWord = (U32)val; 118 | if (leastSignificantWord == 0) { 119 | return 32 + ZSTD_countTrailingZeros32(mostSignificantWord); 120 | } else { 121 | return ZSTD_countTrailingZeros32(leastSignificantWord); 122 | } 123 | } 124 | # endif 125 | } 126 | 127 | MEM_STATIC unsigned ZSTD_countLeadingZeros64(U64 val) 128 | { 129 | assert(val != 0); 130 | # if defined(_MSC_VER) && defined(_WIN64) 131 | # if STATIC_BMI2 == 1 132 | return (unsigned)_lzcnt_u64(val); 133 | # else 134 | if (val != 0) { 135 | unsigned long r; 136 | _BitScanReverse64(&r, val); 137 | return (unsigned)(63 - r); 138 | } else { 139 | /* Should not reach this code path */ 140 | __assume(0); 141 | } 142 | # endif 143 | # elif defined(__GNUC__) && (__GNUC__ >= 4) 144 | return (unsigned)(__builtin_clzll(val)); 145 | # elif defined(__ICCARM__) 146 | return (unsigned)(__builtin_clzll(val)); 147 | # else 148 | { 149 | U32 mostSignificantWord = (U32)(val >> 32); 150 | U32 leastSignificantWord = (U32)val; 151 | if (mostSignificantWord == 0) { 152 | return 32 + ZSTD_countLeadingZeros32(leastSignificantWord); 153 | } else { 154 | return ZSTD_countLeadingZeros32(mostSignificantWord); 155 | } 156 | } 157 | # endif 158 | } 159 | 160 | MEM_STATIC unsigned ZSTD_NbCommonBytes(size_t val) 161 | { 162 | if (MEM_isLittleEndian()) { 163 | if (MEM_64bits()) { 164 | return ZSTD_countTrailingZeros64((U64)val) >> 3; 165 | } else { 166 | return ZSTD_countTrailingZeros32((U32)val) >> 3; 167 | } 168 | } else { /* Big Endian CPU */ 169 | if (MEM_64bits()) { 170 | return ZSTD_countLeadingZeros64((U64)val) >> 3; 171 | } else { 172 | return ZSTD_countLeadingZeros32((U32)val) >> 3; 173 | } 174 | } 175 | } 176 | 177 | MEM_STATIC unsigned ZSTD_highbit32(U32 val) /* compress, dictBuilder, decodeCorpus */ 178 | { 179 | assert(val != 0); 180 | return 31 - ZSTD_countLeadingZeros32(val); 181 | } 182 | 183 | /* ZSTD_rotateRight_*(): 184 | * Rotates a bitfield to the right by "count" bits. 185 | * https://en.wikipedia.org/w/index.php?title=Circular_shift&oldid=991635599#Implementing_circular_shifts 186 | */ 187 | MEM_STATIC 188 | U64 ZSTD_rotateRight_U64(U64 const value, U32 count) { 189 | assert(count < 64); 190 | count &= 0x3F; /* for fickle pattern recognition */ 191 | return (value >> count) | (U64)(value << ((0U - count) & 0x3F)); 192 | } 193 | 194 | MEM_STATIC 195 | U32 ZSTD_rotateRight_U32(U32 const value, U32 count) { 196 | assert(count < 32); 197 | count &= 0x1F; /* for fickle pattern recognition */ 198 | return (value >> count) | (U32)(value << ((0U - count) & 0x1F)); 199 | } 200 | 201 | MEM_STATIC 202 | U16 ZSTD_rotateRight_U16(U16 const value, U32 count) { 203 | assert(count < 16); 204 | count &= 0x0F; /* for fickle pattern recognition */ 205 | return (value >> count) | (U16)(value << ((0U - count) & 0x0F)); 206 | } 207 | 208 | #endif /* ZSTD_BITS_H */ 209 | -------------------------------------------------------------------------------- /src/zstd_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | 12 | 13 | /*-************************************* 14 | * Dependencies 15 | ***************************************/ 16 | #define ZSTD_DEPS_NEED_MALLOC 17 | #include "zstd_error_private.h" 18 | #include "zstd_internal.h" 19 | 20 | 21 | /*-**************************************** 22 | * Version 23 | ******************************************/ 24 | unsigned ZSTD_versionNumber(void) { return ZSTD_VERSION_NUMBER; } 25 | 26 | const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; } 27 | 28 | 29 | /*-**************************************** 30 | * ZSTD Error Management 31 | ******************************************/ 32 | #undef ZSTD_isError /* defined within zstd_internal.h */ 33 | /*! ZSTD_isError() : 34 | * tells if a return value is an error code 35 | * symbol is required for external callers */ 36 | unsigned ZSTD_isError(size_t code) { return ERR_isError(code); } 37 | 38 | /*! ZSTD_getErrorName() : 39 | * provides error code string from function result (useful for debugging) */ 40 | const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } 41 | 42 | /*! ZSTD_getError() : 43 | * convert a `size_t` function result into a proper ZSTD_errorCode enum */ 44 | ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); } 45 | 46 | /*! ZSTD_getErrorString() : 47 | * provides error code string from enum */ 48 | const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorString(code); } 49 | -------------------------------------------------------------------------------- /src/zstd_config.h: -------------------------------------------------------------------------------- 1 | #ifndef ZSTD_CONFIG 2 | #define ZSTD_CONFIG 3 | 4 | #define ZSTD_DEBUGLEVEL 0 5 | #define ZSTD_LEGACY_SUPPORT 0 6 | #define ZSTD_LIB_DEPRECATED 0 7 | #define ZSTD_NO_UNUSED_FUNCTIONS 1 8 | #define ZSTD_STRIP_ERROR_STRINGS 0 9 | #define ZSTD_TRACE 0 10 | #define ZSTD_DECOMPRESS_DICTIONARY 0 11 | #define ZSTD_DECOMPRESS_MULTIFRAME 0 12 | #define ZSTD_NO_TRACE 1 13 | 14 | #if CONFIG_FEATURE_ZSTD_SMALL >= 9 15 | #define ZSTD_NO_INLINE 1 16 | #endif 17 | 18 | #if CONFIG_FEATURE_ZSTD_SMALL >= 7 19 | #define HUF_FORCE_DECOMPRESS_X1 1 20 | #define ZSTD_FORCE_DECOMPRESS_SEQUENCES_SHORT 1 21 | #elif CONFIG_FEATURE_ZSTD_SMALL >= 5 22 | #define HUF_FORCE_DECOMPRESS_X1 1 23 | #endif 24 | 25 | #if CONFIG_FEATURE_ZSTD_SMALL <= 7 26 | /* doesnt blow up code too much, -O3 is horrible */ 27 | #ifdef __GNUC__ 28 | #pragma GCC optimize ("O2") 29 | #endif 30 | #endif 31 | 32 | #if CONFIG_FEATURE_ZSTD_SMALL > 0 33 | /* no dynamic detection of bmi2 instruction, 34 | * prefer using CFLAGS setting to -march=haswell or similar */ 35 | # if !defined(__BMI2__) 36 | # define DYNAMIC_BMI2 0 37 | # endif 38 | #endif 39 | 40 | #ifdef __GNUC__ 41 | #pragma GCC diagnostic push 42 | #pragma GCC diagnostic ignored "-Wunused-function" 43 | #endif 44 | 45 | #ifndef __has_attribute 46 | #define __has_attribute(x) 0 47 | #endif 48 | #ifndef __has_builtin 49 | #define __has_builtin(x) 0 50 | #endif 51 | #ifndef __has_feature 52 | #define __has_feature(x) 0 53 | #endif 54 | 55 | /* Include zstd_deps.h first with all the options we need enabled. */ 56 | #define ZSTD_DEPS_NEED_MALLOC 57 | #define ZSTD_DEPS_NEED_MATH64 58 | #define ZSTD_DEPS_NEED_STDINT 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/zstd_cpu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | #ifndef ZSTD_COMMON_CPU_H 12 | #define ZSTD_COMMON_CPU_H 13 | 14 | /** 15 | * Implementation taken from folly/CpuId.h 16 | * https://github.com/facebook/folly/blob/master/folly/CpuId.h 17 | */ 18 | 19 | #include "zstd_mem.h" 20 | 21 | #ifdef _MSC_VER 22 | #include 23 | #endif 24 | 25 | typedef struct { 26 | U32 f1c; 27 | U32 f1d; 28 | U32 f7b; 29 | U32 f7c; 30 | } ZSTD_cpuid_t; 31 | 32 | MEM_STATIC ZSTD_cpuid_t ZSTD_cpuid(void) { 33 | U32 f1c = 0; 34 | U32 f1d = 0; 35 | U32 f7b = 0; 36 | U32 f7c = 0; 37 | #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) 38 | #if !defined(__clang__) || __clang_major__ >= 16 39 | int reg[4]; 40 | __cpuid((int*)reg, 0); 41 | { 42 | int const n = reg[0]; 43 | if (n >= 1) { 44 | __cpuid((int*)reg, 1); 45 | f1c = (U32)reg[2]; 46 | f1d = (U32)reg[3]; 47 | } 48 | if (n >= 7) { 49 | __cpuidex((int*)reg, 7, 0); 50 | f7b = (U32)reg[1]; 51 | f7c = (U32)reg[2]; 52 | } 53 | } 54 | #else 55 | /* Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in 56 | * which the `__cpuid` intrinsic does not save and restore `rbx` as it needs 57 | * to due to being a reserved register. So in that case, do the `cpuid` 58 | * ourselves. Clang supports inline assembly anyway. 59 | */ 60 | U32 n; 61 | __asm__( 62 | "pushq %%rbx\n\t" 63 | "cpuid\n\t" 64 | "popq %%rbx\n\t" 65 | : "=a"(n) 66 | : "a"(0) 67 | : "rcx", "rdx"); 68 | if (n >= 1) { 69 | U32 f1a; 70 | __asm__( 71 | "pushq %%rbx\n\t" 72 | "cpuid\n\t" 73 | "popq %%rbx\n\t" 74 | : "=a"(f1a), "=c"(f1c), "=d"(f1d) 75 | : "a"(1) 76 | :); 77 | } 78 | if (n >= 7) { 79 | __asm__( 80 | "pushq %%rbx\n\t" 81 | "cpuid\n\t" 82 | "movq %%rbx, %%rax\n\t" 83 | "popq %%rbx" 84 | : "=a"(f7b), "=c"(f7c) 85 | : "a"(7), "c"(0) 86 | : "rdx"); 87 | } 88 | #endif 89 | #elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && defined(__GNUC__) 90 | /* The following block like the normal cpuid branch below, but gcc 91 | * reserves ebx for use of its pic register so we must specially 92 | * handle the save and restore to avoid clobbering the register 93 | */ 94 | U32 n; 95 | __asm__( 96 | "pushl %%ebx\n\t" 97 | "cpuid\n\t" 98 | "popl %%ebx\n\t" 99 | : "=a"(n) 100 | : "a"(0) 101 | : "ecx", "edx"); 102 | if (n >= 1) { 103 | U32 f1a; 104 | __asm__( 105 | "pushl %%ebx\n\t" 106 | "cpuid\n\t" 107 | "popl %%ebx\n\t" 108 | : "=a"(f1a), "=c"(f1c), "=d"(f1d) 109 | : "a"(1)); 110 | } 111 | if (n >= 7) { 112 | __asm__( 113 | "pushl %%ebx\n\t" 114 | "cpuid\n\t" 115 | "movl %%ebx, %%eax\n\t" 116 | "popl %%ebx" 117 | : "=a"(f7b), "=c"(f7c) 118 | : "a"(7), "c"(0) 119 | : "edx"); 120 | } 121 | #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386__) 122 | U32 n; 123 | __asm__("cpuid" : "=a"(n) : "a"(0) : "ebx", "ecx", "edx"); 124 | if (n >= 1) { 125 | U32 f1a; 126 | __asm__("cpuid" : "=a"(f1a), "=c"(f1c), "=d"(f1d) : "a"(1) : "ebx"); 127 | } 128 | if (n >= 7) { 129 | U32 f7a; 130 | __asm__("cpuid" 131 | : "=a"(f7a), "=b"(f7b), "=c"(f7c) 132 | : "a"(7), "c"(0) 133 | : "edx"); 134 | } 135 | #endif 136 | { 137 | ZSTD_cpuid_t cpuid; 138 | cpuid.f1c = f1c; 139 | cpuid.f1d = f1d; 140 | cpuid.f7b = f7b; 141 | cpuid.f7c = f7c; 142 | return cpuid; 143 | } 144 | } 145 | 146 | #define X(name, r, bit) \ 147 | MEM_STATIC int ZSTD_cpuid_##name(ZSTD_cpuid_t const cpuid) { \ 148 | return ((cpuid.r) & (1U << bit)) != 0; \ 149 | } 150 | 151 | /* cpuid(1): Processor Info and Feature Bits. */ 152 | #define C(name, bit) X(name, f1c, bit) 153 | C(sse3, 0) 154 | C(pclmuldq, 1) 155 | C(dtes64, 2) 156 | C(monitor, 3) 157 | C(dscpl, 4) 158 | C(vmx, 5) 159 | C(smx, 6) 160 | C(eist, 7) 161 | C(tm2, 8) 162 | C(ssse3, 9) 163 | C(cnxtid, 10) 164 | C(fma, 12) 165 | C(cx16, 13) 166 | C(xtpr, 14) 167 | C(pdcm, 15) 168 | C(pcid, 17) 169 | C(dca, 18) 170 | C(sse41, 19) 171 | C(sse42, 20) 172 | C(x2apic, 21) 173 | C(movbe, 22) 174 | C(popcnt, 23) 175 | C(tscdeadline, 24) 176 | C(aes, 25) 177 | C(xsave, 26) 178 | C(osxsave, 27) 179 | C(avx, 28) 180 | C(f16c, 29) 181 | C(rdrand, 30) 182 | #undef C 183 | #define D(name, bit) X(name, f1d, bit) 184 | D(fpu, 0) 185 | D(vme, 1) 186 | D(de, 2) 187 | D(pse, 3) 188 | D(tsc, 4) 189 | D(msr, 5) 190 | D(pae, 6) 191 | D(mce, 7) 192 | D(cx8, 8) 193 | D(apic, 9) 194 | D(sep, 11) 195 | D(mtrr, 12) 196 | D(pge, 13) 197 | D(mca, 14) 198 | D(cmov, 15) 199 | D(pat, 16) 200 | D(pse36, 17) 201 | D(psn, 18) 202 | D(clfsh, 19) 203 | D(ds, 21) 204 | D(acpi, 22) 205 | D(mmx, 23) 206 | D(fxsr, 24) 207 | D(sse, 25) 208 | D(sse2, 26) 209 | D(ss, 27) 210 | D(htt, 28) 211 | D(tm, 29) 212 | D(pbe, 31) 213 | #undef D 214 | 215 | /* cpuid(7): Extended Features. */ 216 | #define B(name, bit) X(name, f7b, bit) 217 | B(bmi1, 3) 218 | B(hle, 4) 219 | B(avx2, 5) 220 | B(smep, 7) 221 | B(bmi2, 8) 222 | B(erms, 9) 223 | B(invpcid, 10) 224 | B(rtm, 11) 225 | B(mpx, 14) 226 | B(avx512f, 16) 227 | B(avx512dq, 17) 228 | B(rdseed, 18) 229 | B(adx, 19) 230 | B(smap, 20) 231 | B(avx512ifma, 21) 232 | B(pcommit, 22) 233 | B(clflushopt, 23) 234 | B(clwb, 24) 235 | B(avx512pf, 26) 236 | B(avx512er, 27) 237 | B(avx512cd, 28) 238 | B(sha, 29) 239 | B(avx512bw, 30) 240 | B(avx512vl, 31) 241 | #undef B 242 | #define C(name, bit) X(name, f7c, bit) 243 | C(prefetchwt1, 0) 244 | C(avx512vbmi, 1) 245 | #undef C 246 | 247 | #undef X 248 | 249 | #endif /* ZSTD_COMMON_CPU_H */ 250 | -------------------------------------------------------------------------------- /src/zstd_ddict.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | /* zstd_ddict.c : 12 | * concentrates all logic that needs to know the internals of ZSTD_DDict object */ 13 | 14 | /*-******************************************************* 15 | * Dependencies 16 | *********************************************************/ 17 | //#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */ 18 | #include "zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */ 19 | #include "zstd_cpu.h" /* bmi2 */ 20 | #include "zstd_mem.h" /* low level memory routines */ 21 | #define FSE_STATIC_LINKING_ONLY 22 | #include "fse.h" 23 | #include "huf.h" 24 | #include "zstd_decompress_internal.h" 25 | #include "zstd_ddict.h" 26 | 27 | #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) 28 | # include "../legacy/zstd_legacy.h" 29 | #endif 30 | 31 | 32 | 33 | /*-******************************************************* 34 | * Types 35 | *********************************************************/ 36 | struct ZSTD_DDict_s { 37 | void* dictBuffer; 38 | const void* dictContent; 39 | size_t dictSize; 40 | ZSTD_entropyDTables_t entropy; 41 | U32 dictID; 42 | U32 entropyPresent; 43 | ZSTD_customMem cMem; 44 | }; /* typedef'd to ZSTD_DDict within "zstd.h" */ 45 | 46 | const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict) 47 | { 48 | assert(ddict != NULL); 49 | return ddict->dictContent; 50 | } 51 | 52 | size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict) 53 | { 54 | assert(ddict != NULL); 55 | return ddict->dictSize; 56 | } 57 | 58 | void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict) 59 | { 60 | DEBUGLOG(4, "ZSTD_copyDDictParameters"); 61 | assert(dctx != NULL); 62 | assert(ddict != NULL); 63 | dctx->dictID = ddict->dictID; 64 | dctx->prefixStart = ddict->dictContent; 65 | dctx->virtualStart = ddict->dictContent; 66 | dctx->dictEnd = (const BYTE*)ddict->dictContent + ddict->dictSize; 67 | dctx->previousDstEnd = dctx->dictEnd; 68 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 69 | dctx->dictContentBeginForFuzzing = dctx->prefixStart; 70 | dctx->dictContentEndForFuzzing = dctx->previousDstEnd; 71 | #endif 72 | if (ddict->entropyPresent) { 73 | dctx->litEntropy = 1; 74 | dctx->fseEntropy = 1; 75 | dctx->LLTptr = ddict->entropy.LLTable; 76 | dctx->MLTptr = ddict->entropy.MLTable; 77 | dctx->OFTptr = ddict->entropy.OFTable; 78 | dctx->HUFptr = ddict->entropy.hufTable; 79 | dctx->entropy.rep[0] = ddict->entropy.rep[0]; 80 | dctx->entropy.rep[1] = ddict->entropy.rep[1]; 81 | dctx->entropy.rep[2] = ddict->entropy.rep[2]; 82 | } else { 83 | dctx->litEntropy = 0; 84 | dctx->fseEntropy = 0; 85 | } 86 | } 87 | 88 | 89 | static size_t 90 | ZSTD_loadEntropy_intoDDict(ZSTD_DDict* ddict, 91 | ZSTD_dictContentType_e dictContentType) 92 | { 93 | ddict->dictID = 0; 94 | ddict->entropyPresent = 0; 95 | if (dictContentType == ZSTD_dct_rawContent) return 0; 96 | 97 | if (ddict->dictSize < 8) { 98 | if (dictContentType == ZSTD_dct_fullDict) 99 | return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ 100 | return 0; /* pure content mode */ 101 | } 102 | { U32 const magic = MEM_readLE32(ddict->dictContent); 103 | if (magic != ZSTD_MAGIC_DICTIONARY) { 104 | if (dictContentType == ZSTD_dct_fullDict) 105 | return ERROR(dictionary_corrupted); /* only accept specified dictionaries */ 106 | return 0; /* pure content mode */ 107 | } 108 | } 109 | ddict->dictID = MEM_readLE32((const char*)ddict->dictContent + ZSTD_FRAMEIDSIZE); 110 | 111 | /* load entropy tables */ 112 | RETURN_ERROR_IF(ZSTD_isError(ZSTD_loadDEntropy( 113 | &ddict->entropy, ddict->dictContent, ddict->dictSize)), 114 | dictionary_corrupted, ""); 115 | ddict->entropyPresent = 1; 116 | return 0; 117 | } 118 | 119 | 120 | static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, 121 | const void* dict, size_t dictSize, 122 | ZSTD_dictLoadMethod_e dictLoadMethod, 123 | ZSTD_dictContentType_e dictContentType) 124 | { 125 | if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dict) || (!dictSize)) { 126 | ddict->dictBuffer = NULL; 127 | ddict->dictContent = dict; 128 | if (!dict) dictSize = 0; 129 | } else { 130 | void* const internalBuffer = ZSTD_customMalloc(dictSize, ddict->cMem); 131 | ddict->dictBuffer = internalBuffer; 132 | ddict->dictContent = internalBuffer; 133 | if (!internalBuffer) return ERROR(memory_allocation); 134 | ZSTD_memcpy(internalBuffer, dict, dictSize); 135 | } 136 | ddict->dictSize = dictSize; 137 | ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ 138 | 139 | /* parse dictionary content */ 140 | FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); 141 | 142 | return 0; 143 | } 144 | 145 | ZSTD_DDict* ZSTD_createDDict_advanced(const void* dict, size_t dictSize, 146 | ZSTD_dictLoadMethod_e dictLoadMethod, 147 | ZSTD_dictContentType_e dictContentType, 148 | ZSTD_customMem customMem) 149 | { 150 | if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 151 | 152 | { ZSTD_DDict* const ddict = (ZSTD_DDict*) ZSTD_customMalloc(sizeof(ZSTD_DDict), customMem); 153 | if (ddict == NULL) return NULL; 154 | ddict->cMem = customMem; 155 | { size_t const initResult = ZSTD_initDDict_internal(ddict, 156 | dict, dictSize, 157 | dictLoadMethod, dictContentType); 158 | if (ZSTD_isError(initResult)) { 159 | ZSTD_freeDDict(ddict); 160 | return NULL; 161 | } } 162 | return ddict; 163 | } 164 | } 165 | 166 | /*! ZSTD_createDDict() : 167 | * Create a digested dictionary, to start decompression without startup delay. 168 | * `dict` content is copied inside DDict. 169 | * Consequently, `dict` can be released after `ZSTD_DDict` creation */ 170 | ZSTD_DDict* ZSTD_createDDict(const void* dict, size_t dictSize) 171 | { 172 | ZSTD_customMem const allocator = { NULL, NULL, NULL }; 173 | return ZSTD_createDDict_advanced(dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto, allocator); 174 | } 175 | 176 | /*! ZSTD_createDDict_byReference() : 177 | * Create a digested dictionary, to start decompression without startup delay. 178 | * Dictionary content is simply referenced, it will be accessed during decompression. 179 | * Warning : dictBuffer must outlive DDict (DDict must be freed before dictBuffer) */ 180 | ZSTD_DDict* ZSTD_createDDict_byReference(const void* dictBuffer, size_t dictSize) 181 | { 182 | ZSTD_customMem const allocator = { NULL, NULL, NULL }; 183 | return ZSTD_createDDict_advanced(dictBuffer, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto, allocator); 184 | } 185 | 186 | 187 | const ZSTD_DDict* ZSTD_initStaticDDict( 188 | void* sBuffer, size_t sBufferSize, 189 | const void* dict, size_t dictSize, 190 | ZSTD_dictLoadMethod_e dictLoadMethod, 191 | ZSTD_dictContentType_e dictContentType) 192 | { 193 | size_t const neededSpace = sizeof(ZSTD_DDict) 194 | + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); 195 | ZSTD_DDict* const ddict = (ZSTD_DDict*)sBuffer; 196 | assert(sBuffer != NULL); 197 | assert(dict != NULL); 198 | if ((size_t)sBuffer & 7) return NULL; /* 8-aligned */ 199 | if (sBufferSize < neededSpace) return NULL; 200 | if (dictLoadMethod == ZSTD_dlm_byCopy) { 201 | ZSTD_memcpy(ddict+1, dict, dictSize); /* local copy */ 202 | dict = ddict+1; 203 | } 204 | if (ZSTD_isError( ZSTD_initDDict_internal(ddict, 205 | dict, dictSize, 206 | ZSTD_dlm_byRef, dictContentType) )) 207 | return NULL; 208 | return ddict; 209 | } 210 | 211 | 212 | size_t ZSTD_freeDDict(ZSTD_DDict* ddict) 213 | { 214 | if (ddict==NULL) return 0; /* support free on NULL */ 215 | { ZSTD_customMem const cMem = ddict->cMem; 216 | ZSTD_customFree(ddict->dictBuffer, cMem); 217 | ZSTD_customFree(ddict, cMem); 218 | return 0; 219 | } 220 | } 221 | 222 | /*! ZSTD_estimateDDictSize() : 223 | * Estimate amount of memory that will be needed to create a dictionary for decompression. 224 | * Note : dictionary created by reference using ZSTD_dlm_byRef are smaller */ 225 | size_t ZSTD_estimateDDictSize(size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod) 226 | { 227 | return sizeof(ZSTD_DDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); 228 | } 229 | 230 | size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict) 231 | { 232 | if (ddict==NULL) return 0; /* support sizeof on NULL */ 233 | return sizeof(*ddict) + (ddict->dictBuffer ? ddict->dictSize : 0) ; 234 | } 235 | 236 | /*! ZSTD_getDictID_fromDDict() : 237 | * Provides the dictID of the dictionary loaded into `ddict`. 238 | * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. 239 | * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ 240 | unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict) 241 | { 242 | if (ddict==NULL) return 0; 243 | return ddict->dictID; 244 | } 245 | -------------------------------------------------------------------------------- /src/zstd_ddict.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | 12 | #ifndef ZSTD_DDICT_H 13 | #define ZSTD_DDICT_H 14 | 15 | /*-******************************************************* 16 | * Dependencies 17 | *********************************************************/ 18 | #include "zstd_deps.h" /* size_t */ 19 | #include "zstd.h" /* ZSTD_DDict, and several public functions */ 20 | 21 | 22 | /*-******************************************************* 23 | * Interface 24 | *********************************************************/ 25 | 26 | /* note: several prototypes are already published in `zstd.h` : 27 | * ZSTD_createDDict() 28 | * ZSTD_createDDict_byReference() 29 | * ZSTD_createDDict_advanced() 30 | * ZSTD_freeDDict() 31 | * ZSTD_initStaticDDict() 32 | * ZSTD_sizeof_DDict() 33 | * ZSTD_estimateDDictSize() 34 | * ZSTD_getDictID_fromDict() 35 | */ 36 | 37 | const void* ZSTD_DDict_dictContent(const ZSTD_DDict* ddict); 38 | size_t ZSTD_DDict_dictSize(const ZSTD_DDict* ddict); 39 | 40 | void ZSTD_copyDDictParameters(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict); 41 | 42 | 43 | 44 | #endif /* ZSTD_DDICT_H */ 45 | -------------------------------------------------------------------------------- /src/zstd_decompress_block.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | 12 | #ifndef ZSTD_DEC_BLOCK_H 13 | #define ZSTD_DEC_BLOCK_H 14 | 15 | /*-******************************************************* 16 | * Dependencies 17 | *********************************************************/ 18 | #include "zstd_deps.h" /* size_t */ 19 | #include "zstd.h" /* DCtx, and some public functions */ 20 | #include "zstd_internal.h" /* blockProperties_t, and some public functions */ 21 | #include "zstd_decompress_internal.h" /* ZSTD_seqSymbol */ 22 | 23 | 24 | /* === Prototypes === */ 25 | 26 | /* note: prototypes already published within `zstd.h` : 27 | * ZSTD_decompressBlock() 28 | */ 29 | 30 | /* note: prototypes already published within `zstd_internal.h` : 31 | * ZSTD_getcBlockSize() 32 | * ZSTD_decodeSeqHeaders() 33 | */ 34 | 35 | 36 | /* Streaming state is used to inform allocation of the literal buffer */ 37 | typedef enum { 38 | not_streaming = 0, 39 | is_streaming = 1 40 | } streaming_operation; 41 | 42 | /* ZSTD_decompressBlock_internal() : 43 | * decompress block, starting at `src`, 44 | * into destination buffer `dst`. 45 | * @return : decompressed block size, 46 | * or an error code (which can be tested using ZSTD_isError()) 47 | */ 48 | size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, 49 | void* dst, size_t dstCapacity, 50 | const void* src, size_t srcSize, const streaming_operation streaming); 51 | 52 | /* ZSTD_buildFSETable() : 53 | * generate FSE decoding table for one symbol (ll, ml or off) 54 | * this function must be called with valid parameters only 55 | * (dt is large enough, normalizedCounter distribution total is a power of 2, max is within range, etc.) 56 | * in which case it cannot fail. 57 | * The workspace must be 4-byte aligned and at least ZSTD_BUILD_FSE_TABLE_WKSP_SIZE bytes, which is 58 | * defined in zstd_decompress_internal.h. 59 | * Internal use only. 60 | */ 61 | void ZSTD_buildFSETable(ZSTD_seqSymbol* dt, 62 | const short* normalizedCounter, unsigned maxSymbolValue, 63 | const U32* baseValue, const U8* nbAdditionalBits, 64 | unsigned tableLog, void* wksp, size_t wkspSize, 65 | int bmi2); 66 | 67 | /* Internal definition of ZSTD_decompressBlock() to avoid deprecation warnings. */ 68 | size_t ZSTD_decompressBlock_deprecated(ZSTD_DCtx* dctx, 69 | void* dst, size_t dstCapacity, 70 | const void* src, size_t srcSize); 71 | 72 | 73 | #endif /* ZSTD_DEC_BLOCK_H */ 74 | -------------------------------------------------------------------------------- /src/zstd_decompress_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | 12 | /* zstd_decompress_internal: 13 | * objects and definitions shared within lib/decompress modules */ 14 | 15 | #ifndef ZSTD_DECOMPRESS_INTERNAL_H 16 | #define ZSTD_DECOMPRESS_INTERNAL_H 17 | 18 | 19 | /*-******************************************************* 20 | * Dependencies 21 | *********************************************************/ 22 | #include "zstd_mem.h" /* BYTE, U16, U32 */ 23 | #include "zstd_internal.h" /* constants : MaxLL, MaxML, MaxOff, LLFSELog, etc. */ 24 | 25 | 26 | 27 | /*-******************************************************* 28 | * Constants 29 | *********************************************************/ 30 | static UNUSED_ATTR const U32 LL_base[MaxLL+1] = { 31 | 0, 1, 2, 3, 4, 5, 6, 7, 32 | 8, 9, 10, 11, 12, 13, 14, 15, 33 | 16, 18, 20, 22, 24, 28, 32, 40, 34 | 48, 64, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 35 | 0x2000, 0x4000, 0x8000, 0x10000 }; 36 | 37 | static UNUSED_ATTR const U32 OF_base[MaxOff+1] = { 38 | 0, 1, 1, 5, 0xD, 0x1D, 0x3D, 0x7D, 39 | 0xFD, 0x1FD, 0x3FD, 0x7FD, 0xFFD, 0x1FFD, 0x3FFD, 0x7FFD, 40 | 0xFFFD, 0x1FFFD, 0x3FFFD, 0x7FFFD, 0xFFFFD, 0x1FFFFD, 0x3FFFFD, 0x7FFFFD, 41 | 0xFFFFFD, 0x1FFFFFD, 0x3FFFFFD, 0x7FFFFFD, 0xFFFFFFD, 0x1FFFFFFD, 0x3FFFFFFD, 0x7FFFFFFD }; 42 | 43 | static UNUSED_ATTR const U8 OF_bits[MaxOff+1] = { 44 | 0, 1, 2, 3, 4, 5, 6, 7, 45 | 8, 9, 10, 11, 12, 13, 14, 15, 46 | 16, 17, 18, 19, 20, 21, 22, 23, 47 | 24, 25, 26, 27, 28, 29, 30, 31 }; 48 | 49 | static UNUSED_ATTR const U32 ML_base[MaxML+1] = { 50 | 3, 4, 5, 6, 7, 8, 9, 10, 51 | 11, 12, 13, 14, 15, 16, 17, 18, 52 | 19, 20, 21, 22, 23, 24, 25, 26, 53 | 27, 28, 29, 30, 31, 32, 33, 34, 54 | 35, 37, 39, 41, 43, 47, 51, 59, 55 | 67, 83, 99, 0x83, 0x103, 0x203, 0x403, 0x803, 56 | 0x1003, 0x2003, 0x4003, 0x8003, 0x10003 }; 57 | 58 | 59 | /*-******************************************************* 60 | * Decompression types 61 | *********************************************************/ 62 | typedef struct { 63 | U32 fastMode; 64 | U32 tableLog; 65 | } ZSTD_seqSymbol_header; 66 | 67 | typedef struct { 68 | U16 nextState; 69 | BYTE nbAdditionalBits; 70 | BYTE nbBits; 71 | U32 baseValue; 72 | } ZSTD_seqSymbol; 73 | 74 | #define SEQSYMBOL_TABLE_SIZE(log) (1 + (1 << (log))) 75 | 76 | #define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) 77 | #define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) 78 | #define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 79 | 80 | typedef struct { 81 | ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ 82 | ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ 83 | ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ 84 | HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ 85 | U32 rep[ZSTD_REP_NUM]; 86 | U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; 87 | } ZSTD_entropyDTables_t; 88 | 89 | typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, 90 | ZSTDds_decodeBlockHeader, ZSTDds_decompressBlock, 91 | ZSTDds_decompressLastBlock, ZSTDds_checkChecksum, 92 | ZSTDds_decodeSkippableHeader, ZSTDds_skipFrame } ZSTD_dStage; 93 | 94 | typedef enum { zdss_init=0, zdss_loadHeader, 95 | zdss_read, zdss_load, zdss_flush } ZSTD_dStreamStage; 96 | 97 | typedef enum { 98 | ZSTD_use_indefinitely = -1, /* Use the dictionary indefinitely */ 99 | ZSTD_dont_use = 0, /* Do not use the dictionary (if one exists free it) */ 100 | ZSTD_use_once = 1 /* Use the dictionary once and set to ZSTD_dont_use */ 101 | } ZSTD_dictUses_e; 102 | 103 | /* Hashset for storing references to multiple ZSTD_DDict within ZSTD_DCtx */ 104 | typedef struct { 105 | const ZSTD_DDict** ddictPtrTable; 106 | size_t ddictPtrTableSize; 107 | size_t ddictPtrCount; 108 | } ZSTD_DDictHashSet; 109 | 110 | #ifndef ZSTD_DECODER_INTERNAL_BUFFER 111 | # define ZSTD_DECODER_INTERNAL_BUFFER (1 << 16) 112 | #endif 113 | 114 | #define ZSTD_LBMIN 64 115 | #define ZSTD_LBMAX (128 << 10) 116 | 117 | /* extra buffer, compensates when dst is not large enough to store litBuffer */ 118 | #define ZSTD_LITBUFFEREXTRASIZE BOUNDED(ZSTD_LBMIN, ZSTD_DECODER_INTERNAL_BUFFER, ZSTD_LBMAX) 119 | 120 | typedef enum { 121 | ZSTD_not_in_dst = 0, /* Stored entirely within litExtraBuffer */ 122 | ZSTD_in_dst = 1, /* Stored entirely within dst (in memory after current output write) */ 123 | ZSTD_split = 2 /* Split between litExtraBuffer and dst */ 124 | } ZSTD_litLocation_e; 125 | 126 | struct ZSTD_DCtx_s 127 | { 128 | const ZSTD_seqSymbol* LLTptr; 129 | const ZSTD_seqSymbol* MLTptr; 130 | const ZSTD_seqSymbol* OFTptr; 131 | const HUF_DTable* HUFptr; 132 | ZSTD_entropyDTables_t entropy; 133 | U32 workspace[HUF_DECOMPRESS_WORKSPACE_SIZE_U32]; /* space needed when building huffman tables */ 134 | const void* previousDstEnd; /* detect continuity */ 135 | const void* prefixStart; /* start of current segment */ 136 | const void* virtualStart; /* virtual start of previous segment if it was just before current one */ 137 | const void* dictEnd; /* end of previous segment */ 138 | size_t expected; 139 | ZSTD_frameHeader fParams; 140 | U64 processedCSize; 141 | U64 decodedSize; 142 | blockType_e bType; /* used in ZSTD_decompressContinue(), store blockType between block header decoding and block decompression stages */ 143 | ZSTD_dStage stage; 144 | U32 litEntropy; 145 | U32 fseEntropy; 146 | XXH64_state_t xxhState; 147 | size_t headerSize; 148 | ZSTD_format_e format; 149 | ZSTD_forceIgnoreChecksum_e forceIgnoreChecksum; /* User specified: if == 1, will ignore checksums in compressed frame. Default == 0 */ 150 | U32 validateChecksum; /* if == 1, will validate checksum. Is == 1 if (fParams.checksumFlag == 1) and (forceIgnoreChecksum == 0). */ 151 | const BYTE* litPtr; 152 | ZSTD_customMem customMem; 153 | size_t litSize; 154 | size_t rleSize; 155 | size_t staticSize; 156 | int isFrameDecompression; 157 | #if DYNAMIC_BMI2 != 0 158 | int bmi2; /* == 1 if the CPU supports BMI2 and 0 otherwise. CPU support is determined dynamically once per context lifetime. */ 159 | #endif 160 | 161 | /* dictionary */ 162 | ZSTD_DDict* ddictLocal; 163 | const ZSTD_DDict* ddict; /* set by ZSTD_initDStream_usingDDict(), or ZSTD_DCtx_refDDict() */ 164 | U32 dictID; 165 | int ddictIsCold; /* if == 1 : dictionary is "new" for working context, and presumed "cold" (not in cpu cache) */ 166 | ZSTD_dictUses_e dictUses; 167 | ZSTD_DDictHashSet* ddictSet; /* Hash set for multiple ddicts */ 168 | ZSTD_refMultipleDDicts_e refMultipleDDicts; /* User specified: if == 1, will allow references to multiple DDicts. Default == 0 (disabled) */ 169 | int disableHufAsm; 170 | int maxBlockSizeParam; 171 | 172 | /* streaming */ 173 | ZSTD_dStreamStage streamStage; 174 | char* inBuff; 175 | size_t inBuffSize; 176 | size_t inPos; 177 | size_t maxWindowSize; 178 | char* outBuff; 179 | size_t outBuffSize; 180 | size_t outStart; 181 | size_t outEnd; 182 | size_t lhSize; 183 | #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1) 184 | void* legacyContext; 185 | U32 previousLegacyVersion; 186 | U32 legacyVersion; 187 | #endif 188 | U32 hostageByte; 189 | int noForwardProgress; 190 | ZSTD_bufferMode_e outBufferMode; 191 | ZSTD_outBuffer expectedOutBuffer; 192 | 193 | /* workspace */ 194 | BYTE* litBuffer; 195 | const BYTE* litBufferEnd; 196 | ZSTD_litLocation_e litBufferLocation; 197 | BYTE litExtraBuffer[ZSTD_LITBUFFEREXTRASIZE + WILDCOPY_OVERLENGTH]; /* literal buffer can be split between storage within dst and within this scratch buffer */ 198 | BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; 199 | 200 | size_t oversizedDuration; 201 | 202 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 203 | void const* dictContentBeginForFuzzing; 204 | void const* dictContentEndForFuzzing; 205 | #endif 206 | 207 | /* Tracing */ 208 | #if ZSTD_TRACE 209 | ZSTD_TraceCtx traceCtx; 210 | #endif 211 | }; /* typedef'd to ZSTD_DCtx within "zstd.h" */ 212 | 213 | MEM_STATIC int ZSTD_DCtx_get_bmi2(const struct ZSTD_DCtx_s *dctx) { 214 | #if DYNAMIC_BMI2 != 0 215 | return dctx->bmi2; 216 | #else 217 | (void)dctx; 218 | return 0; 219 | #endif 220 | } 221 | 222 | /*-******************************************************* 223 | * Shared internal functions 224 | *********************************************************/ 225 | 226 | /*! ZSTD_loadDEntropy() : 227 | * dict : must point at beginning of a valid zstd dictionary. 228 | * @return : size of dictionary header (size of magic number + dict ID + entropy tables) */ 229 | size_t ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy, 230 | const void* const dict, size_t const dictSize); 231 | 232 | /*! ZSTD_checkContinuity() : 233 | * check if next `dst` follows previous position, where decompression ended. 234 | * If yes, do nothing (continue on current segment). 235 | * If not, classify previous segment as "external dictionary", and start a new segment. 236 | * This function cannot fail. */ 237 | void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst, size_t dstSize); 238 | 239 | 240 | #endif /* ZSTD_DECOMPRESS_INTERNAL_H */ 241 | -------------------------------------------------------------------------------- /src/zstd_deps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | /* This file provides common libc dependencies that zstd requires. 12 | * The purpose is to allow replacing this file with a custom implementation 13 | * to compile zstd without libc support. 14 | */ 15 | 16 | /* Need: 17 | * NULL 18 | * INT_MAX 19 | * UINT_MAX 20 | * ZSTD_memcpy() 21 | * ZSTD_memset() 22 | * ZSTD_memmove() 23 | */ 24 | #ifndef ZSTD_DEPS_COMMON 25 | #define ZSTD_DEPS_COMMON 26 | 27 | /* Even though we use qsort_r only for the dictionary builder, the macro 28 | * _GNU_SOURCE has to be declared *before* the inclusion of any standard 29 | * header and the script 'combine.sh' combines the whole zstd source code 30 | * in a single file. 31 | */ 32 | #if defined(__linux) || defined(__linux__) || defined(linux) || defined(__gnu_linux__) || \ 33 | defined(__CYGWIN__) || defined(__MSYS__) 34 | #if !defined(_GNU_SOURCE) && !defined(__ANDROID__) /* NDK doesn't ship qsort_r(). */ 35 | #define _GNU_SOURCE 36 | #endif 37 | #endif 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include "zstd_config.h" 44 | 45 | #if defined(__GNUC__) && __GNUC__ >= 4 46 | # define ZSTD_memcpy(d,s,l) __builtin_memcpy((d),(s),(l)) 47 | # define ZSTD_memmove(d,s,l) __builtin_memmove((d),(s),(l)) 48 | # define ZSTD_memset(p,v,l) __builtin_memset((p),(v),(l)) 49 | #else 50 | # define ZSTD_memcpy(d,s,l) memcpy((d),(s),(l)) 51 | # define ZSTD_memmove(d,s,l) memmove((d),(s),(l)) 52 | # define ZSTD_memset(p,v,l) memset((p),(v),(l)) 53 | #endif 54 | 55 | #endif /* ZSTD_DEPS_COMMON */ 56 | 57 | /* Need: 58 | * ZSTD_malloc() 59 | * ZSTD_free() 60 | * ZSTD_calloc() 61 | */ 62 | #ifdef ZSTD_DEPS_NEED_MALLOC 63 | #ifndef ZSTD_DEPS_MALLOC 64 | #define ZSTD_DEPS_MALLOC 65 | 66 | #include 67 | 68 | #define ZSTD_malloc(s) malloc(s) 69 | #define ZSTD_calloc(n,s) calloc((n), (s)) 70 | #define ZSTD_free(p) free((p)) 71 | 72 | #endif /* ZSTD_DEPS_MALLOC */ 73 | #endif /* ZSTD_DEPS_NEED_MALLOC */ 74 | 75 | /* 76 | * Provides 64-bit math support. 77 | * Need: 78 | * U64 ZSTD_div64(U64 dividend, U32 divisor) 79 | */ 80 | #ifdef ZSTD_DEPS_NEED_MATH64 81 | #ifndef ZSTD_DEPS_MATH64 82 | #define ZSTD_DEPS_MATH64 83 | 84 | #define ZSTD_div64(dividend, divisor) ((dividend) / (divisor)) 85 | 86 | #endif /* ZSTD_DEPS_MATH64 */ 87 | #endif /* ZSTD_DEPS_NEED_MATH64 */ 88 | 89 | /* Need: 90 | * assert() 91 | */ 92 | #ifdef ZSTD_DEPS_NEED_ASSERT 93 | #ifndef ZSTD_DEPS_ASSERT 94 | #define ZSTD_DEPS_ASSERT 95 | 96 | #include 97 | 98 | #endif /* ZSTD_DEPS_ASSERT */ 99 | 100 | #else 101 | 102 | #ifndef assert 103 | #define assert(condition) ((void)0) 104 | #endif 105 | 106 | #endif /* ZSTD_DEPS_NEED_ASSERT */ 107 | 108 | /* Need: 109 | * ZSTD_DEBUG_PRINT() 110 | */ 111 | #ifdef ZSTD_DEPS_NEED_IO 112 | #ifndef ZSTD_DEPS_IO 113 | #define ZSTD_DEPS_IO 114 | 115 | #include 116 | #define ZSTD_DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__) 117 | 118 | #endif /* ZSTD_DEPS_IO */ 119 | #endif /* ZSTD_DEPS_NEED_IO */ 120 | 121 | /* Only requested when is known to be present. 122 | * Need: 123 | * intptr_t 124 | */ 125 | #ifdef ZSTD_DEPS_NEED_STDINT 126 | #ifndef ZSTD_DEPS_STDINT 127 | #define ZSTD_DEPS_STDINT 128 | 129 | #include 130 | 131 | #endif /* ZSTD_DEPS_STDINT */ 132 | #endif /* ZSTD_DEPS_NEED_STDINT */ 133 | 134 | #define DEBUG_STATIC_ASSERT(c) (void)sizeof(char[(c) ? 1 : -1]) 135 | 136 | #include "libbb.h" 137 | 138 | #if (DEBUGLEVEL >= 1) 139 | #define RAWLOG(l, ...) { if (l <= ZSTD_DEBUGLEVEL) bb_printf(__VA_ARGS__); } 140 | #define DEBUGLOG(l, ...) { if (l <= ZSTD_DEBUGLEVEL) bb_printf(__VA_ARGS__); } 141 | #else 142 | #define RAWLOG(l, ...) do { } while (0) 143 | #define DEBUGLOG(l, ...) do { } while (0) 144 | #endif 145 | -------------------------------------------------------------------------------- /src/zstd_error_private.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | /* The purpose of this file is to have a single list of error strings embedded in binary */ 12 | 13 | #include "zstd_error_private.h" 14 | 15 | const char* ERR_getErrorString(ERR_enum code) 16 | { 17 | #ifdef ZSTD_STRIP_ERROR_STRINGS 18 | (void)code; 19 | return "Error strings stripped"; 20 | #else 21 | static const char* const notErrorCode = "Unspecified error code"; 22 | switch( code ) 23 | { 24 | case PREFIX(no_error): return "No error detected"; 25 | case PREFIX(GENERIC): return "Error (generic)"; 26 | case PREFIX(prefix_unknown): return "Unknown frame descriptor"; 27 | case PREFIX(version_unsupported): return "Version not supported"; 28 | case PREFIX(frameParameter_unsupported): return "Unsupported frame parameter"; 29 | case PREFIX(frameParameter_windowTooLarge): return "Frame requires too much memory for decoding"; 30 | case PREFIX(corruption_detected): return "Data corruption detected"; 31 | case PREFIX(checksum_wrong): return "Restored data doesn't match checksum"; 32 | case PREFIX(literals_headerWrong): return "Header of Literals' block doesn't respect format specification"; 33 | case PREFIX(parameter_unsupported): return "Unsupported parameter"; 34 | case PREFIX(parameter_combination_unsupported): return "Unsupported combination of parameters"; 35 | case PREFIX(parameter_outOfBound): return "Parameter is out of bound"; 36 | case PREFIX(init_missing): return "Context should be init first"; 37 | case PREFIX(memory_allocation): return "Allocation error : not enough memory"; 38 | case PREFIX(workSpace_tooSmall): return "workSpace buffer is not large enough"; 39 | case PREFIX(stage_wrong): return "Operation not authorized at current processing stage"; 40 | case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; 41 | case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; 42 | case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; 43 | case PREFIX(stabilityCondition_notRespected): return "pledged buffer stability condition is not respected"; 44 | case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; 45 | case PREFIX(dictionary_wrong): return "Dictionary mismatch"; 46 | case PREFIX(dictionaryCreation_failed): return "Cannot create Dictionary from provided samples"; 47 | case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; 48 | case PREFIX(srcSize_wrong): return "Src size is incorrect"; 49 | case PREFIX(dstBuffer_null): return "Operation on NULL destination buffer"; 50 | case PREFIX(noForwardProgress_destFull): return "Operation made no progress over multiple calls, due to output buffer being full"; 51 | case PREFIX(noForwardProgress_inputEmpty): return "Operation made no progress over multiple calls, due to input being empty"; 52 | /* following error codes are not stable and may be removed or changed in a future version */ 53 | case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; 54 | case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; 55 | case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; 56 | case PREFIX(srcBuffer_wrong): return "Source buffer is wrong"; 57 | case PREFIX(sequenceProducer_failed): return "Block-level external sequence producer returned an error code"; 58 | case PREFIX(externalSequences_invalid): return "External sequences are not valid"; 59 | case PREFIX(maxCode): 60 | default: return notErrorCode; 61 | } 62 | #endif 63 | } 64 | -------------------------------------------------------------------------------- /src/zstd_error_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | /* Note : this module is expected to remain private, do not expose it */ 12 | 13 | #ifndef ERROR_H_MODULE 14 | #define ERROR_H_MODULE 15 | 16 | #if defined (__cplusplus) 17 | extern "C" { 18 | #endif 19 | 20 | 21 | /* **************************************** 22 | * Dependencies 23 | ******************************************/ 24 | #include "zstd_errors.h" /* enum list */ 25 | #include "zstd_compiler.h" 26 | #include "zstd_deps.h" /* size_t */ 27 | 28 | 29 | /* **************************************** 30 | * Compiler-specific 31 | ******************************************/ 32 | #if defined(__GNUC__) 33 | # define ERR_STATIC static __attribute__((unused)) 34 | #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) 35 | # define ERR_STATIC static inline 36 | #elif defined(_MSC_VER) 37 | # define ERR_STATIC static __inline 38 | #else 39 | # define ERR_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ 40 | #endif 41 | 42 | 43 | /*-**************************************** 44 | * Customization (error_public.h) 45 | ******************************************/ 46 | typedef ZSTD_ErrorCode ERR_enum; 47 | #define PREFIX(name) ZSTD_error_##name 48 | 49 | 50 | /*-**************************************** 51 | * Error codes handling 52 | ******************************************/ 53 | #undef ERROR /* already defined on Visual Studio */ 54 | #define ERROR(name) ZSTD_ERROR(name) 55 | #define ZSTD_ERROR(name) ((size_t)-PREFIX(name)) 56 | 57 | ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } 58 | 59 | ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); } 60 | 61 | /* check and forward error code */ 62 | #define CHECK_V_F(e, f) \ 63 | size_t const e = f; \ 64 | do { \ 65 | if (ERR_isError(e)) \ 66 | return e; \ 67 | } while (0) 68 | #define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0) 69 | 70 | 71 | /*-**************************************** 72 | * Error Strings 73 | ******************************************/ 74 | 75 | const char* ERR_getErrorString(ERR_enum code); /* error_private.c */ 76 | 77 | ERR_STATIC const char* ERR_getErrorName(size_t code) 78 | { 79 | return ERR_getErrorString(ERR_getErrorCode(code)); 80 | } 81 | 82 | /** 83 | * Ignore: this is an internal helper. 84 | * 85 | * This is a helper function to help force C99-correctness during compilation. 86 | * Under strict compilation modes, variadic macro arguments can't be empty. 87 | * However, variadic function arguments can be. Using a function therefore lets 88 | * us statically check that at least one (string) argument was passed, 89 | * independent of the compilation flags. 90 | */ 91 | static INLINE_KEYWORD UNUSED_ATTR 92 | void _force_has_format_string(const char *format, ...) { 93 | (void)format; 94 | } 95 | 96 | /** 97 | * Ignore: this is an internal helper. 98 | * 99 | * We want to force this function invocation to be syntactically correct, but 100 | * we don't want to force runtime evaluation of its arguments. 101 | */ 102 | #define _FORCE_HAS_FORMAT_STRING(...) \ 103 | do { \ 104 | if (0) { \ 105 | _force_has_format_string(__VA_ARGS__); \ 106 | } \ 107 | } while (0) 108 | 109 | #define ERR_QUOTE(str) #str 110 | 111 | /** 112 | * Return the specified error if the condition evaluates to true. 113 | * 114 | * In debug modes, prints additional information. 115 | * In order to do that (particularly, printing the conditional that failed), 116 | * this can't just wrap RETURN_ERROR(). 117 | */ 118 | #define RETURN_ERROR_IF(cond, err, ...) \ 119 | do { \ 120 | if (cond) { \ 121 | RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \ 122 | __FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \ 123 | _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ 124 | RAWLOG(3, ": " __VA_ARGS__); \ 125 | RAWLOG(3, "\n"); \ 126 | return ERROR(err); \ 127 | } \ 128 | } while (0) 129 | 130 | /** 131 | * Unconditionally return the specified error. 132 | * 133 | * In debug modes, prints additional information. 134 | */ 135 | #define RETURN_ERROR(err, ...) \ 136 | do { \ 137 | RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \ 138 | __FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \ 139 | _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ 140 | RAWLOG(3, ": " __VA_ARGS__); \ 141 | RAWLOG(3, "\n"); \ 142 | return ERROR(err); \ 143 | } while(0) 144 | 145 | /** 146 | * If the provided expression evaluates to an error code, returns that error code. 147 | * 148 | * In debug modes, prints additional information. 149 | */ 150 | #define FORWARD_IF_ERROR(err, ...) \ 151 | do { \ 152 | size_t const err_code = (err); \ 153 | if (ERR_isError(err_code)) { \ 154 | RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \ 155 | __FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \ 156 | _FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \ 157 | RAWLOG(3, ": " __VA_ARGS__); \ 158 | RAWLOG(3, "\n"); \ 159 | return err_code; \ 160 | } \ 161 | } while(0) 162 | 163 | #if defined (__cplusplus) 164 | } 165 | #endif 166 | 167 | #endif /* ERROR_H_MODULE */ 168 | -------------------------------------------------------------------------------- /src/zstd_errors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | #ifndef ZSTD_ERRORS_H_398273423 12 | #define ZSTD_ERRORS_H_398273423 13 | 14 | #if defined (__cplusplus) 15 | extern "C" { 16 | #endif 17 | 18 | /* ===== ZSTDERRORLIB_API : control library symbols visibility ===== */ 19 | #ifndef ZSTDERRORLIB_VISIBLE 20 | /* Backwards compatibility with old macro name */ 21 | # ifdef ZSTDERRORLIB_VISIBILITY 22 | # define ZSTDERRORLIB_VISIBLE ZSTDERRORLIB_VISIBILITY 23 | # elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) 24 | # define ZSTDERRORLIB_VISIBLE __attribute__ ((visibility ("default"))) 25 | # else 26 | # define ZSTDERRORLIB_VISIBLE 27 | # endif 28 | #endif 29 | 30 | #ifndef ZSTDERRORLIB_HIDDEN 31 | # if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) 32 | # define ZSTDERRORLIB_HIDDEN __attribute__ ((visibility ("hidden"))) 33 | # else 34 | # define ZSTDERRORLIB_HIDDEN 35 | # endif 36 | #endif 37 | 38 | #if defined(ZSTD_DLL_EXPORT) && (ZSTD_DLL_EXPORT==1) 39 | # define ZSTDERRORLIB_API __declspec(dllexport) ZSTDERRORLIB_VISIBLE 40 | #elif defined(ZSTD_DLL_IMPORT) && (ZSTD_DLL_IMPORT==1) 41 | # define ZSTDERRORLIB_API __declspec(dllimport) ZSTDERRORLIB_VISIBLE /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ 42 | #else 43 | # define ZSTDERRORLIB_API ZSTDERRORLIB_VISIBLE 44 | #endif 45 | 46 | /*-********************************************* 47 | * Error codes list 48 | *-********************************************* 49 | * Error codes _values_ are pinned down since v1.3.1 only. 50 | * Therefore, don't rely on values if you may link to any version < v1.3.1. 51 | * 52 | * Only values < 100 are considered stable. 53 | * 54 | * note 1 : this API shall be used with static linking only. 55 | * dynamic linking is not yet officially supported. 56 | * note 2 : Prefer relying on the enum than on its value whenever possible 57 | * This is the only supported way to use the error list < v1.3.1 58 | * note 3 : ZSTD_isError() is always correct, whatever the library version. 59 | **********************************************/ 60 | typedef enum { 61 | ZSTD_error_no_error = 0, 62 | ZSTD_error_GENERIC = 1, 63 | ZSTD_error_prefix_unknown = 10, 64 | ZSTD_error_version_unsupported = 12, 65 | ZSTD_error_frameParameter_unsupported = 14, 66 | ZSTD_error_frameParameter_windowTooLarge = 16, 67 | ZSTD_error_corruption_detected = 20, 68 | ZSTD_error_checksum_wrong = 22, 69 | ZSTD_error_literals_headerWrong = 24, 70 | ZSTD_error_dictionary_corrupted = 30, 71 | ZSTD_error_dictionary_wrong = 32, 72 | ZSTD_error_dictionaryCreation_failed = 34, 73 | ZSTD_error_parameter_unsupported = 40, 74 | ZSTD_error_parameter_combination_unsupported = 41, 75 | ZSTD_error_parameter_outOfBound = 42, 76 | ZSTD_error_tableLog_tooLarge = 44, 77 | ZSTD_error_maxSymbolValue_tooLarge = 46, 78 | ZSTD_error_maxSymbolValue_tooSmall = 48, 79 | ZSTD_error_stabilityCondition_notRespected = 50, 80 | ZSTD_error_stage_wrong = 60, 81 | ZSTD_error_init_missing = 62, 82 | ZSTD_error_memory_allocation = 64, 83 | ZSTD_error_workSpace_tooSmall= 66, 84 | ZSTD_error_dstSize_tooSmall = 70, 85 | ZSTD_error_srcSize_wrong = 72, 86 | ZSTD_error_dstBuffer_null = 74, 87 | ZSTD_error_noForwardProgress_destFull = 80, 88 | ZSTD_error_noForwardProgress_inputEmpty = 82, 89 | /* following error codes are __NOT STABLE__, they can be removed or changed in future versions */ 90 | ZSTD_error_frameIndex_tooLarge = 100, 91 | ZSTD_error_seekableIO = 102, 92 | ZSTD_error_dstBuffer_wrong = 104, 93 | ZSTD_error_srcBuffer_wrong = 105, 94 | ZSTD_error_sequenceProducer_failed = 106, 95 | ZSTD_error_externalSequences_invalid = 107, 96 | ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ 97 | } ZSTD_ErrorCode; 98 | 99 | ZSTDERRORLIB_API const char* ZSTD_getErrorString(ZSTD_ErrorCode code); /**< Same as ZSTD_getErrorName, but using a `ZSTD_ErrorCode` enum argument */ 100 | 101 | 102 | #if defined (__cplusplus) 103 | } 104 | #endif 105 | 106 | #endif /* ZSTD_ERRORS_H_398273423 */ 107 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = cmp test uncompress 2 | 3 | cmp_SOURCES = cmp.c 4 | cmp_CFLAGS = $(AM_CFLAGS) 5 | cmp_LDFLAGS = $(AM_LDFLAGS) 6 | cmp_LDADD = ../src/libbled.a 7 | 8 | test_SOURCES = test.c 9 | test_CFLAGS = $(AM_CFLAGS) 10 | test_LDFLAGS = $(AM_LDFLAGS) 11 | test_LDADD = ../src/libbled.a 12 | 13 | uncompress_SOURCES = uncompress.c 14 | uncompress_CFLAGS = $(AM_CFLAGS) 15 | uncompress_LDFLAGS = $(AM_LDFLAGS) 16 | uncompress_LDADD = ../src/libbled.a 17 | -------------------------------------------------------------------------------- /test/cmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Bled (Base Library for Easy Decompression) - large image comparison test 3 | * The following decompresses a large zipped Raspbian image, and compares it 4 | * with its uncompressed version to detect potential decompression errors. 5 | * 6 | * Copyright © 2016-2023 Pete Batard 7 | * 8 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "../src/bled.h" 15 | 16 | #define BUFSIZE 65536 17 | 18 | #define SRC_NAME "D:\\Imgs\\2015-02-16-raspbian-wheezy.zip" 19 | #define DST_NAME "C:\\Downloads\\test.img" 20 | #define REF_NAME "C:\\Downloads\\2015-02-16-raspbian-wheezy.img" 21 | 22 | int main(int argc, char** argv) 23 | { 24 | int ret = 1; 25 | static char *src = SRC_NAME, *dst = DST_NAME, *ref = REF_NAME; 26 | int64_t rb, ref_size; 27 | DWORD rSize[2]; 28 | uint8_t buffer[2][BUFSIZE]; 29 | HANDLE hSrc = NULL, hDst = NULL, hRef = NULL; 30 | LARGE_INTEGER li; 31 | 32 | // Needed to prevent stdout buffering with MinGW 33 | setbuf(stdout, NULL); 34 | 35 | hSrc = CreateFileA(src, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 36 | if (hSrc == INVALID_HANDLE_VALUE) { 37 | printf("Could not open source file '%s' - Error %ld\n", src, GetLastError()); 38 | goto out; 39 | } 40 | hDst = CreateFileA(dst, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 41 | if (hDst == INVALID_HANDLE_VALUE) { 42 | printf("Could not create destination file '%s' - Error %ld\n", dst, GetLastError()); 43 | goto out; 44 | } 45 | hRef = CreateFileA(ref, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 46 | if (hRef == INVALID_HANDLE_VALUE) { 47 | printf("Could not open reference file '%s' - Error %ld\n", ref, GetLastError()); 48 | goto out; 49 | } 50 | li.QuadPart = 0; 51 | if (!SetFilePointerEx(hRef, li, &li, FILE_END)) { 52 | printf("Could not get reference file size - Error %ld\n", GetLastError()); 53 | goto out; 54 | } 55 | ref_size = li.QuadPart; 56 | li.QuadPart = 0; 57 | if (!SetFilePointerEx(hRef, li, NULL, FILE_BEGIN)) { 58 | printf("Could not reset cmp file - Error %ld\n", GetLastError()); 59 | goto out; 60 | } 61 | 62 | bled_init(0, NULL, NULL, NULL, NULL, NULL, NULL); 63 | printf("Decompressing...\n"); 64 | bled_uncompress_with_handles(hSrc, hDst, BLED_COMPRESSION_ZIP); 65 | bled_exit(); 66 | CloseHandle(hSrc); 67 | hSrc = NULL; 68 | li.QuadPart = 0; 69 | if (!SetFilePointerEx(hDst, li, NULL, FILE_BEGIN)) { 70 | printf("Could not reset dst file - Error %ld\n", GetLastError()); 71 | goto out; 72 | } 73 | 74 | printf("Comparing...\n"); 75 | for (rb = 0; rb < ref_size; rb += rSize[0]) { 76 | #ifdef _DEBUG 77 | if ((rb != 0LL) && (rb % (1024 * 1024 * 1024LL) == 0)) 78 | printf("Processed %" PRIi64 " bytes\n", rb); 79 | #endif 80 | if (!ReadFile(hDst, buffer[0], BUFSIZE, &rSize[0], NULL)) { 81 | printf("Could not read dst file - Error %ld\n", GetLastError()); 82 | goto out; 83 | } 84 | if (!ReadFile(hRef, buffer[1], BUFSIZE, &rSize[1], NULL)) { 85 | printf("Could not read comparison file - Error %ld\n", GetLastError()); 86 | goto out; 87 | } 88 | if ((rSize[0] == 0) || (rSize[1] == 0)) { 89 | printf("Error - Zero size buffer\n"); 90 | goto out; 91 | } 92 | // Ideally, we should consider partial reads as an ever present possibility 93 | // but in practice the only partial read we get is with the last block, so... 94 | if (rSize[0] != rSize[1]) { 95 | printf("Error - Size mismatch (%ld vs %ld)\n", rSize[0], rSize[1]); 96 | goto out; 97 | } 98 | if (memcmp(buffer[0], buffer[1], rSize[0]) != 0) { 99 | printf("Error - data mismatch at position %" PRIi64 "\n", rb); 100 | goto out; 101 | } 102 | } 103 | ret = 0; 104 | printf("Match\n"); 105 | 106 | out: 107 | if (hSrc != NULL) 108 | CloseHandle(hSrc); 109 | if (hDst != NULL) 110 | CloseHandle(hDst); 111 | if (hRef != NULL) 112 | CloseHandle(hRef); 113 | 114 | return ret; 115 | } 116 | -------------------------------------------------------------------------------- /test/data/xz.Z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.Z -------------------------------------------------------------------------------- /test/data/xz.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.bz2 -------------------------------------------------------------------------------- /test/data/xz.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.gz -------------------------------------------------------------------------------- /test/data/xz.lzma: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.lzma -------------------------------------------------------------------------------- /test/data/xz.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.xz -------------------------------------------------------------------------------- /test/data/xz.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.zip -------------------------------------------------------------------------------- /test/data/xz.zst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pbatard/bled/56654eb4facde8de5da54d0f9e8be86a6450b474/test/data/xz.zst -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Bled (Base Library for Easy Decompression) - test function 3 | * 4 | * Copyright © 2014-2024 Pete Batard 5 | * 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 | */ 8 | 9 | /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ 10 | #ifdef _CRTDBG_MAP_ALLOC 11 | #include 12 | #include 13 | #endif 14 | 15 | #include 16 | #include 17 | #include "../src/bled.h" 18 | 19 | printf_t print_function = NULL; 20 | 21 | // It's a unit test, not a sample, so I'll hardcode whatever the hell I want 22 | #define BASE_PATH "C:\\Projects\\bled\\test\\data\\" 23 | #define BASE_FILE "xz" 24 | 25 | struct { 26 | const char* ext; 27 | int type; 28 | } test_files[] = { 29 | { "zip", BLED_COMPRESSION_ZIP}, 30 | { "Z", BLED_COMPRESSION_LZW}, 31 | { "gz", BLED_COMPRESSION_GZIP}, 32 | { "lzma", BLED_COMPRESSION_LZMA}, 33 | { "bz2", BLED_COMPRESSION_BZIP2}, 34 | { "xz", BLED_COMPRESSION_XZ}, 35 | { "zst", BLED_COMPRESSION_ZSTD}, 36 | // { "7z", BLED_COMPRESSION_7ZIP}, // Not implemented 37 | }; 38 | 39 | // With a 9044 size, the last word in the buffer should resolve to "ready" on success 40 | #define BUFSIZE 9044 41 | int main(int argc, char** argv) 42 | { 43 | int i; 44 | int64_t r; 45 | char src[256], dst[256], *buffer = NULL; 46 | 47 | bled_init(0, NULL, NULL, NULL, NULL, NULL, NULL); 48 | 49 | printf("DECOMPRESS TO BUFFER:\n"); 50 | buffer = malloc(BUFSIZE); 51 | for (i = 0; i < ARRAYSIZE(test_files); i++) { 52 | sprintf_s(src, sizeof(src), "%s%s.%s", BASE_PATH, BASE_FILE, test_files[i].ext); 53 | r = bled_uncompress_to_buffer(src, buffer, BUFSIZE, test_files[i].type); 54 | buffer[BUFSIZE - 1] = 0; 55 | printf(" %s:\t%" PRIi64 " - \"%s\"\n", test_files[i].ext, r, &buffer[BUFSIZE - 6]); 56 | if (r < 0) 57 | goto out; 58 | } 59 | 60 | printf("\nDECOMPRESS TO FILE:\n"); 61 | for (i = 0; i < ARRAYSIZE(test_files); i++) { 62 | sprintf_s(src, sizeof(src), "%s%s.%s", BASE_PATH, BASE_FILE, test_files[i].ext); 63 | sprintf_s(dst, sizeof(dst), "%s!%s.txt", BASE_PATH, test_files[i].ext); 64 | r = bled_uncompress(src, dst, test_files[i].type); 65 | printf(" %s:\t%" PRIi64 "\n", test_files[i].ext, r); 66 | if (r < 0) 67 | goto out; 68 | } 69 | 70 | out: 71 | free(buffer); 72 | bled_exit(); 73 | 74 | #ifdef _CRTDBG_MAP_ALLOC 75 | _CrtDumpMemoryLeaks(); 76 | #endif 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /test/uncompress.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Bled (Base Library for Easy Decompression) - simple uncompress app 3 | * 4 | * Copyright © 2015-2024 Pete Batard 5 | * 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 | */ 8 | 9 | /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ 10 | #ifdef _CRTDBG_MAP_ALLOC 11 | #include 12 | #include 13 | #endif 14 | 15 | #if defined(_MSC_VER) 16 | #pragma warning(disable: 4996) // Ignore deprecated 17 | #pragma warning(disable: 28159) // Code analysis warning for GetTickCount vs GetTickCount64 18 | #endif 19 | 20 | #include 21 | #include 22 | #include "../src/bled.h" 23 | 24 | #define IS_DIRECTORY(x) ((x != INVALID_FILE_ATTRIBUTES) && (x & FILE_ATTRIBUTE_DIRECTORY)) 25 | 26 | typedef struct { 27 | const char* ext; 28 | bled_compression_type type; 29 | } comp_assoc; 30 | 31 | static comp_assoc file_assoc[] = { 32 | { ".zip", BLED_COMPRESSION_ZIP }, 33 | { ".Z", BLED_COMPRESSION_LZW }, 34 | { ".gz", BLED_COMPRESSION_GZIP }, 35 | { ".lzma", BLED_COMPRESSION_LZMA }, 36 | { ".bz2", BLED_COMPRESSION_BZIP2 }, 37 | { ".xz", BLED_COMPRESSION_XZ }, 38 | { ".zst", BLED_COMPRESSION_ZSTD }, 39 | }; 40 | 41 | static DWORD LastRefresh; 42 | static uint64_t src_size; 43 | 44 | void switch_func(const char* filename, const uint64_t filesize) 45 | { 46 | printf("Extracting '%s' (%lld bytes)\n", filename, filesize); 47 | } 48 | 49 | void progress_func(const uint64_t read_bytes) 50 | { 51 | CONSOLE_SCREEN_BUFFER_INFO csbi; 52 | HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 53 | float progress; 54 | 55 | if ((GetTickCount() < (LastRefresh + 100)) && (read_bytes != src_size)) 56 | return; 57 | LastRefresh = GetTickCount(); 58 | 59 | progress = (100.0f*read_bytes) / (1.0f*src_size); 60 | GetConsoleScreenBufferInfo(hConsole, &csbi); 61 | csbi.dwCursorPosition.X = 0; 62 | SetConsoleCursorPosition(hConsole, csbi.dwCursorPosition); 63 | printf("Uncompressing: %3.2f%%", progress); 64 | } 65 | 66 | int main(int argc, char** argv) 67 | { 68 | char *p; 69 | int r = 1; 70 | size_t i = 0; 71 | int64_t wb = 0; 72 | LARGE_INTEGER li; 73 | HANDLE hSrc = INVALID_HANDLE_VALUE, hDst = INVALID_HANDLE_VALUE; 74 | DWORD dwAttrib; 75 | 76 | if (argc != 3) { 77 | fprintf(stderr, "Uncompress an archive to a file or a directory\n"); 78 | fprintf(stderr, "Usage: %s \n", argv[0]); 79 | goto out; 80 | } 81 | 82 | for (p = (char*)&argv[1][strlen(argv[1])-1]; (*p != '.') && (p != argv[1]); p--); 83 | if (p == argv[1]) { 84 | fprintf(stderr, "Input file must have an extension\n"); 85 | goto out; 86 | } 87 | 88 | dwAttrib = GetFileAttributesA(argv[2]); 89 | for (i = 0; i 0) { 126 | printf("Uncompressed size: %" PRIi64 "d bytes\n", wb); 127 | r = 0; 128 | } else { 129 | fprintf(stderr, "Decompression error: %d\n", (int)wb); 130 | } 131 | } 132 | break; 133 | } 134 | } 135 | 136 | if (i >= ARRAYSIZE(file_assoc)) 137 | fprintf(stderr, "Unsupported compression type '%s'\n", p); 138 | 139 | out: 140 | if (hSrc != INVALID_HANDLE_VALUE) 141 | CloseHandle(hSrc); 142 | if (hDst != INVALID_HANDLE_VALUE) 143 | CloseHandle(hDst); 144 | 145 | #ifdef _CRTDBG_MAP_ALLOC 146 | _CrtDumpMemoryLeaks(); 147 | #endif 148 | return r; 149 | } 150 | --------------------------------------------------------------------------------