Skip to content
API Documentation
BastionGuard™
anonymous_namespace{archive_worker.cpp} Namespace Reference

Classes

struct  ZipEntryInfo

Functions

uint16_t read_u16_le (std::ifstream &f)
uint32_t read_u32_le (std::ifstream &f)
bool read_exact (std::ifstream &f, char *buf, std::size_t len)
std::string read_string (std::ifstream &f, std::size_t len)
bool contains_dotdot_path (const std::string &name)
bool is_absolute_or_weird_path (const std::string &name)
bool looks_like_nested_archive_name (const std::string &name)
void print_json_bool (const char *key, bool value, bool comma=true)
void print_json_int (const char *key, int value, bool comma=true)
void print_json_str (const char *key, const std::string &value, bool comma=true)
bool find_eocd (std::ifstream &f, std::uint64_t file_size, std::uint64_t &eocd_offset)
bool parse_zip64_extra (const std::vector< unsigned char > &extra, bool uncomp_is_sentinel, bool comp_is_sentinel, bool offset_is_sentinel, std::uint64_t *out_uncomp, std::uint64_t *out_comp, std::uint64_t *out_offset)
bool read_local_entry (std::ifstream &f, std::uint64_t file_size, std::uint64_t local_offset, uint16_t &method, uint32_t &compressed_size, uint32_t &uncompressed_size, uint16_t &gp_flags_out, std::string &filename, std::uint64_t &data_offset, std::uint64_t &data_end, std::uint64_t &zip64_comp_size, std::uint64_t &zip64_uncomp_size, bool &has_zip64_extra)

Variables

constexpr uint32_t SIG_LOCAL_FILE_HEADER = 0x04034b50
constexpr uint32_t SIG_CENTRAL_DIR_HEADER = 0x02014b50
constexpr uint32_t SIG_END_OF_CENTRAL_DIR = 0x06054b50

Function Documentation

◆ contains_dotdot_path()

bool anonymous_namespace{archive_worker.cpp}::contains_dotdot_path ( const std::string & name)

Definition at line 82 of file archive_worker.cpp.

82 {
83 if (name.find("..") == std::string::npos) {
84 return false;
85 }
86 return name.find("../") != std::string::npos ||
87 name.find("..\\") != std::string::npos ||
88 name == "..";
89}

References contains_dotdot_path().

Referenced by contains_dotdot_path(), and main().

◆ find_eocd()

bool anonymous_namespace{archive_worker.cpp}::find_eocd ( std::ifstream & f,
std::uint64_t file_size,
std::uint64_t & eocd_offset )

Definition at line 147 of file archive_worker.cpp.

147 {
148 if (file_size < 22) {
149 return false;
150 }
151
152 const std::uint64_t max_comment = 65535;
153 const std::uint64_t window = std::min<std::uint64_t>(file_size, 22 + max_comment);
154 const std::uint64_t start = file_size - window;
155
156 f.seekg(static_cast<std::streamoff>(start), std::ios::beg);
157 std::vector<char> buf(static_cast<std::size_t>(window));
158 if (!buf.empty()) {
159 f.read(buf.data(), static_cast<std::streamsize>(buf.size()));
160 if (static_cast<std::size_t>(f.gcount()) != buf.size()) {
161 return false;
162 }
163 }
164
165 for (std::int64_t i = static_cast<std::int64_t>(buf.size()) - 4; i >= 0; --i) {
166 const unsigned char* p =
167 reinterpret_cast<const unsigned char*>(buf.data() + i);
168 const uint32_t sig =
169 static_cast<uint32_t>(p[0]) |
170 (static_cast<uint32_t>(p[1]) << 8) |
171 (static_cast<uint32_t>(p[2]) << 16) |
172 (static_cast<uint32_t>(p[3]) << 24);
173
174 if (sig == SIG_END_OF_CENTRAL_DIR) {
175 eocd_offset = start + static_cast<std::uint64_t>(i);
176 return true;
177 }
178 }
179
180 return false;
181}

References find_eocd(), and SIG_END_OF_CENTRAL_DIR.

Referenced by find_eocd(), and main().

◆ is_absolute_or_weird_path()

bool anonymous_namespace{archive_worker.cpp}::is_absolute_or_weird_path ( const std::string & name)

Definition at line 91 of file archive_worker.cpp.

91 {
92 if (name.empty()) {
93 return false;
94 }
95 if (name[0] == '/' || name[0] == '\\') {
96 return true;
97 }
98 if (name.size() >= 2 && std::isalpha(static_cast<unsigned char>(name[0])) && name[1] == ':') {
99 return true;
100 }
101 return false;
102}

References is_absolute_or_weird_path().

Referenced by is_absolute_or_weird_path(), and main().

◆ looks_like_nested_archive_name()

bool anonymous_namespace{archive_worker.cpp}::looks_like_nested_archive_name ( const std::string & name)

Definition at line 104 of file archive_worker.cpp.

104 {
105 std::string lower = name;
106 std::transform(lower.begin(), lower.end(), lower.begin(),
107 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
108
109 return lower.ends_with(".zip") ||
110 lower.ends_with(".7z") ||
111 lower.ends_with(".rar") ||
112 lower.ends_with(".tar") ||
113 lower.ends_with(".gz") ||
114 lower.ends_with(".tgz") ||
115 lower.ends_with(".bz2") ||
116 lower.ends_with(".xz");
117}

References looks_like_nested_archive_name().

Referenced by looks_like_nested_archive_name(), and main().

◆ parse_zip64_extra()

bool anonymous_namespace{archive_worker.cpp}::parse_zip64_extra ( const std::vector< unsigned char > & extra,
bool uncomp_is_sentinel,
bool comp_is_sentinel,
bool offset_is_sentinel,
std::uint64_t * out_uncomp,
std::uint64_t * out_comp,
std::uint64_t * out_offset )

Definition at line 186 of file archive_worker.cpp.

194{
195 std::size_t i = 0;
196 while (i + 4 <= extra.size()) {
197 const uint16_t hid = static_cast<uint16_t>(extra[i] | (extra[i + 1] << 8));
198 const uint16_t hlen = static_cast<uint16_t>(extra[i + 2] | (extra[i + 3] << 8));
199 i += 4;
200 if (i + hlen > extra.size()) {
201 return false;
202 }
203 if (hid == 0x0001) {
204 std::size_t j = i;
205 auto read_u64 = [&](std::uint64_t& dst) {
206 if (j + 8 > i + hlen) return false;
207 std::uint64_t v = 0;
208 for (int k = 0; k < 8; ++k) {
209 v |= static_cast<std::uint64_t>(extra[j + k]) << (8 * k);
210 }
211 dst = v;
212 j += 8;
213 return true;
214 };
215 // Ordine: Uncompressed, Compressed, LocalHeaderOffset, DiskStart.
216 // Solo i campi "sentinella" sono presenti.
217 if (uncomp_is_sentinel && out_uncomp) {
218 if (!read_u64(*out_uncomp)) return true;
219 }
220 if (comp_is_sentinel && out_comp) {
221 if (!read_u64(*out_comp)) return true;
222 }
223 if (offset_is_sentinel && out_offset) {
224 if (!read_u64(*out_offset)) return true;
225 }
226 return true;
227 }
228 i += hlen;
229 }
230 return false;
231}

References parse_zip64_extra().

Referenced by main(), parse_zip64_extra(), and read_local_entry().

◆ print_json_bool()

void anonymous_namespace{archive_worker.cpp}::print_json_bool ( const char * key,
bool value,
bool comma = true )

Definition at line 119 of file archive_worker.cpp.

119 {
120 std::cout << "\"" << key << "\":" << (value ? "true" : "false");
121 if (comma) {
122 std::cout << ",";
123 }
124}

References print_json_bool().

Referenced by main(), and print_json_bool().

◆ print_json_int()

void anonymous_namespace{archive_worker.cpp}::print_json_int ( const char * key,
int value,
bool comma = true )

Definition at line 126 of file archive_worker.cpp.

126 {
127 std::cout << "\"" << key << "\":" << value;
128 if (comma) {
129 std::cout << ",";
130 }
131}

References print_json_int().

Referenced by main(), and print_json_int().

◆ print_json_str()

void anonymous_namespace{archive_worker.cpp}::print_json_str ( const char * key,
const std::string & value,
bool comma = true )

Definition at line 133 of file archive_worker.cpp.

133 {
134 std::cout << "\"" << key << "\":\"";
135 for (const char c : value) {
136 if (c == '"' || c == '\\') {
137 std::cout << '\\';
138 }
139 std::cout << c;
140 }
141 std::cout << "\"";
142 if (comma) {
143 std::cout << ",";
144 }
145}

References print_json_str().

Referenced by main(), and print_json_str().

◆ read_exact()

bool anonymous_namespace{archive_worker.cpp}::read_exact ( std::ifstream & f,
char * buf,
std::size_t len )

Definition at line 65 of file archive_worker.cpp.

65 {
66 f.read(buf, static_cast<std::streamsize>(len));
67 return static_cast<std::size_t>(f.gcount()) == len;
68}

References read_exact().

Referenced by read_exact().

◆ read_local_entry()

bool anonymous_namespace{archive_worker.cpp}::read_local_entry ( std::ifstream & f,
std::uint64_t file_size,
std::uint64_t local_offset,
uint16_t & method,
uint32_t & compressed_size,
uint32_t & uncompressed_size,
uint16_t & gp_flags_out,
std::string & filename,
std::uint64_t & data_offset,
std::uint64_t & data_end,
std::uint64_t & zip64_comp_size,
std::uint64_t & zip64_uncomp_size,
bool & has_zip64_extra )

Definition at line 233 of file archive_worker.cpp.

247{
248 zip64_comp_size = 0;
249 zip64_uncomp_size = 0;
250 has_zip64_extra = false;
251
252 if (local_offset + 30 > file_size) {
253 return false;
254 }
255
256 f.seekg(static_cast<std::streamoff>(local_offset), std::ios::beg);
257 const uint32_t sig = read_u32_le(f);
258 if (sig != SIG_LOCAL_FILE_HEADER) {
259 return false;
260 }
261
262 (void)read_u16_le(f); // version needed
263 const uint16_t gp_flags = read_u16_le(f);
264 gp_flags_out = gp_flags;
265 method = read_u16_le(f);
266 (void)read_u16_le(f); // time
267 (void)read_u16_le(f); // date
268 (void)read_u32_le(f); // crc
269 compressed_size = read_u32_le(f);
270 uncompressed_size = read_u32_le(f);
271 const uint16_t name_len = read_u16_le(f);
272 const uint16_t extra_len = read_u16_le(f);
273
274 filename = read_string(f, name_len);
275 if (filename.size() != name_len) {
276 return false;
277 }
278
279 std::vector<unsigned char> extra(extra_len);
280 if (extra_len > 0) {
281 f.read(reinterpret_cast<char*>(extra.data()), extra_len);
282 if (static_cast<std::size_t>(f.gcount()) != extra_len) {
283 return false;
284 }
285 }
286
287 // ZIP64: se comp/uncomp size == 0xFFFFFFFF, i valori veri stanno nell'extra field 0x0001.
288 const bool comp_is_sentinel = (compressed_size == 0xFFFFFFFFu);
289 const bool uncomp_is_sentinel = (uncompressed_size == 0xFFFFFFFFu);
290
291 if (comp_is_sentinel || uncomp_is_sentinel) {
292 has_zip64_extra = parse_zip64_extra(
293 extra,
294 uncomp_is_sentinel,
295 comp_is_sentinel,
296 /*offset_is_sentinel=*/false,
297 &zip64_uncomp_size,
298 &zip64_comp_size,
299 nullptr);
300 }
301
302 data_offset = local_offset + 30ULL + name_len + extra_len;
303
304 // Dimensione affidabile per controllare se i dati escono dal file:
305 // - ZIP64 con extra valido → usa zip64_comp_size
306 // - data descriptor (bit 3) → non nota qui: usa 0 (bypassa il check di overflow)
307 // - altrimenti → compressed_size
308 const bool has_data_descriptor = (gp_flags & 0x08) != 0;
309 std::uint64_t effective_comp = compressed_size;
310 if (comp_is_sentinel && has_zip64_extra) {
311 effective_comp = zip64_comp_size;
312 } else if (has_data_descriptor && compressed_size == 0) {
313 // Dati con data descriptor: la dimensione vera sta dopo i dati, skippiamo il check.
314 effective_comp = 0;
315 }
316
317 data_end = data_offset + effective_comp;
318 if (data_offset > file_size || data_end > file_size) {
319 return false;
320 }
321
322 return true;
323}
bool parse_zip64_extra(const std::vector< unsigned char > &extra, bool uncomp_is_sentinel, bool comp_is_sentinel, bool offset_is_sentinel, std::uint64_t *out_uncomp, std::uint64_t *out_comp, std::uint64_t *out_offset)
std::string read_string(std::ifstream &f, std::size_t len)
uint16_t read_u16_le(std::ifstream &f)
uint32_t read_u32_le(std::ifstream &f)

References parse_zip64_extra(), read_local_entry(), read_string(), read_u16_le(), read_u32_le(), and SIG_LOCAL_FILE_HEADER.

Referenced by main(), and read_local_entry().

◆ read_string()

std::string anonymous_namespace{archive_worker.cpp}::read_string ( std::ifstream & f,
std::size_t len )

Definition at line 70 of file archive_worker.cpp.

70 {
71 std::string s(len, '\0');
72 if (!len) {
73 return s;
74 }
75 f.read(&s[0], static_cast<std::streamsize>(len));
76 if (static_cast<std::size_t>(f.gcount()) != len) {
77 return {};
78 }
79 return s;
80}

References read_string().

Referenced by main(), read_local_entry(), and read_string().

◆ read_u16_le()

uint16_t anonymous_namespace{archive_worker.cpp}::read_u16_le ( std::ifstream & f)

Definition at line 48 of file archive_worker.cpp.

48 {
49 unsigned char b[2] = {0, 0};
50 f.read(reinterpret_cast<char*>(b), 2);
51 return static_cast<uint16_t>(b[0] | (b[1] << 8));
52}

References read_u16_le().

Referenced by main(), read_local_entry(), and read_u16_le().

◆ read_u32_le()

uint32_t anonymous_namespace{archive_worker.cpp}::read_u32_le ( std::ifstream & f)

Definition at line 54 of file archive_worker.cpp.

54 {
55 unsigned char b[4] = {0, 0, 0, 0};
56 f.read(reinterpret_cast<char*>(b), 4);
57 return static_cast<uint32_t>(
58 static_cast<uint32_t>(b[0]) |
59 (static_cast<uint32_t>(b[1]) << 8) |
60 (static_cast<uint32_t>(b[2]) << 16) |
61 (static_cast<uint32_t>(b[3]) << 24)
62 );
63}

References read_u32_le().

Referenced by main(), read_local_entry(), and read_u32_le().

Variable Documentation

◆ SIG_CENTRAL_DIR_HEADER

uint32_t anonymous_namespace{archive_worker.cpp}::SIG_CENTRAL_DIR_HEADER = 0x02014b50
constexpr

Definition at line 45 of file archive_worker.cpp.

Referenced by main().

◆ SIG_END_OF_CENTRAL_DIR

uint32_t anonymous_namespace{archive_worker.cpp}::SIG_END_OF_CENTRAL_DIR = 0x06054b50
constexpr

Definition at line 46 of file archive_worker.cpp.

Referenced by find_eocd(), and main().

◆ SIG_LOCAL_FILE_HEADER

uint32_t anonymous_namespace{archive_worker.cpp}::SIG_LOCAL_FILE_HEADER = 0x04034b50
constexpr

Definition at line 44 of file archive_worker.cpp.

Referenced by main(), and read_local_entry().