ohmu
·
2026-10-15
1#pragma once
2
3#include "fastfetch.h"
4
5// Locating an entry inside a zip, which is what both the jar reader and the app label reader need:
6// one looks for `classesN.dex`, the other for the resource table of an APK.
7//
8// The entry is found through the central directory rather than by scanning for its local header,
9// and that is not a micro-optimisation. A local header is preceded by everything that came before
10// it, so scanning costs a pass over all of it, once per lookup: `framework.jar` is 52 MB and its
11// `classes2.dex` starts 9.6 MB in. Measured on the test device, where the sound module resolves
12// seven codes, looking the entries up by scanning was the difference between 30 ms and 2 seconds.
13//
14// The sizes and the compression method are read from the directory rather than from the entry's own
15// local header, which is the more reliable of the two: a local header is allowed to leave its sizes
16// at zero and put them in a data descriptor behind the payload, and an archive writer is free to
17// choose that. Only the local header's two length fields are used, because they are what says where
18// the payload begins -- the local extra field does not have to match the central one.
19
20// The zip local file header, from APPNOTE.TXT 4.3.7.
21#define FF_ZIP_LOCAL_HEADER_SIZE 30
22#define FF_ZIP_OFF_NAME_LENGTH 26
23#define FF_ZIP_OFF_EXTRA_LENGTH 28
24
25// The central directory.
26#define FF_ZIP_CENTRAL_MAGIC "PK\x01\x02"
27#define FF_ZIP_CENTRAL_SIZE 46
28#define FF_ZIP_OFF_CENTRAL_METHOD 10
29#define FF_ZIP_OFF_CENTRAL_COMPRESSED_SIZE 20
30#define FF_ZIP_OFF_CENTRAL_UNCOMPRESSED_SIZE 24
31#define FF_ZIP_OFF_CENTRAL_NAME_LENGTH 28
32#define FF_ZIP_OFF_CENTRAL_EXTRA_LENGTH 30
33#define FF_ZIP_OFF_CENTRAL_COMMENT_LENGTH 32
34#define FF_ZIP_OFF_CENTRAL_LOCAL_OFFSET 42
35
36// The end of central directory record, which points at the directory. It is the last thing in the
37// file, behind a comment of at most 64 KiB, so it is searched for backwards over that much.
38#define FF_ZIP_EOCD_MAGIC "PK\x05\x06"
39#define FF_ZIP_EOCD_SIZE 22
40#define FF_ZIP_EOCD_MAX_COMMENT 0xffffu
41#define FF_ZIP_OFF_EOCD_DIRECTORY_SIZE 12
42#define FF_ZIP_OFF_EOCD_DIRECTORY 16
43
44// A size or offset of 0xFFFFFFFF means the real one is in a zip64 extra field. AOSP's framework jars
45// and the APKs measured so far are orders of magnitude below that, and carrying the extra field
46// reader for them is not worth it.
47#define FF_ZIP_ZIP64_SENTINEL 0xffffffffu
48
49#define FF_ZIP_METHOD_STORED 0
50#define FF_ZIP_METHOD_DEFLATED 8
51
52// One entry, as the archive describes it. `payload` points into the mapping the caller passed in and
53// is not a copy: for a STORED entry it is the file's own bytes, and for a DEFLATED one it is the raw
54// deflate stream, which the caller inflates with `uncompressedSize` as the bound.
55typedef struct FFAndroidZipEntry {
56 const uint8_t* payload;
57 size_t payloadSize;
58 uint32_t uncompressedSize;
59 uint16_t method;
60} FFAndroidZipEntry;
61
62// Resolves `entry` through the archive's central directory, writing where its payload is into
63// `result`. Returns nullptr on success, a static message otherwise -- an archive that is not a zip,
64// a directory that is out of range, an entry that is not there and an entry stored as zip64 are all
65// reported rather than answered with a pointer into nothing.
66[[gnu::nonnull(1, 3, 4), nodiscard]] const char* ffAndroidZipFindEntry(const uint8_t* archive, size_t archiveSize, const char* entry, FFAndroidZipEntry* result);