├── .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 |
--------------------------------------------------------------------------------