Skip to main content

Module procreate

Module procreate 

Source
Expand description

Reading Procreate .brush and .brushset archives: the guarded zip and plist readers, the Shape.png decoder and the two name/member lookups the preview API needs.

Every entry here parses untrusted bytes, so each size, count and dimension is checked against a ceiling before anything is allocated.

Enums§

ShapePngError
Why a Shape.png did not decode.

Constants§

MAX_ENTRY_BYTES
Defensive ceilings for untrusted archives: anything above them is treated as malformed rather than allocated from.
MAX_PLIST_BYTES
MAX_PLIST_DEPTH
MAX_PNG_DIMENSION

Functions§

archive_objects_and_main
The NSKeyedArchiver settings dictionary lives at $objects[1], and every non-scalar field of it is a UID into the same $objects array — so a caller needs the pair, not just the dictionary.
brush_name
The display name stored in a Brush.archive ($objects[1].name), None when the archive has no readable name.
decode_tip_png
Decode a Procreate Shape.png into a grayscale tip. White is stamp coverage, so the luminance is taken as-is.
members_in_zip_order
Members of a set that has no brushset.plist: every top-level directory d with an entry named exactly d/Brush.archive, in first-appearance zip order. d/Reset/Brush.archive does not make d/Reset a member.
parse_brushset_plist
The set name and the member uuids a brushset.plist declares, in its order.
parse_plist_guarded
The streaming depth pre-check builds no tree, so it bails early: without it a deeply nested plist produces a Value whose recursive Drop overflows the call stack. The bytes are parsed twice, stream then tree.
read_zip_entry
The declared uncompressed size is an attacker-controlled zip-header field, so it is only a clamped pre-allocation hint and the read is capped independently — a small declared size can hide a huge inflate.
resolve_string
Follow a UID-valued field of the settings dictionary to the string it names, treating NSKeyedArchiver’s literal "$null" marker as absent.