. "$BST_LIB" # libHaru 2.4.4 (meta-oe recipes-support/libharu) -- the ANSI-C PDF writer, # driven through /usr/bin/libharu-demo, which this port ships because upstream # ships no usable driver (see recipes-support/libharu/libharu_%.bbappend for the # three separate reasons its own 26 demo programs are not one). # # THE ORACLE IS A STORED DIGEST, AND THAT IS UNUSUAL ON THIS SHELF, so it is # worth saying exactly why it is valid here when libvorbis next door rejected the # same idea. libvorbis's decoder is bit-exact within one build and NOT across # two, because its configure gives x86-64 an -ffast-math line wasm32 does not get # and its MDCT runs through libm. libHaru has neither property: # # - IT READS NO CLOCK. The only time(NULL) in the tree is hpdf_pdfa.c:298, # reached only from HPDF_SetPDFAConformance, which nothing here calls. No # CreationDate, ModDate, Producer or trailer /ID is written unless asked, and # libharu-demo asks with a fixed 2001-01-01 date. So the output is a pure # function of the API calls. # - THE PINNED DOCUMENTS TOUCH NO libm. `doc` is text, strokes and fills at # integer coordinates; `circles` is HPDF_Page_Circle / HPDF_Page_Ellipse, # which emit Beziers from a hardcoded kappa. Both are integer and # float-literal arithmetic through libHaru's own HPDF_FToA. # # The two digests below were measured on an x86-64 native build of the same # SRCREV before any wasm32 build was spent, so a mismatch on the arm is a # divergence FROM something rather than a number nobody has seen before. # # WHAT IS DELIBERATELY *NOT* PINNED ACROSS MACHINES: # # - docz. Same document with HPDF_COMP_ALL, so its bytes come out of zlib's # deflate and belong to the zlib build as much as to libHaru. Checked # against itself (two runs identical), against doc (strictly smaller, and # carrying /FlateDecode where doc carries none) and structurally. # - arcs. HPDF_Page_Arc is the ONE drawing primitive that reaches libm -- # InternalArc computes its Bezier control points from HPDF_SIN/HPDF_COS, # which hpdf_conf.h defines as plain sin and cos. Its digest IS asserted, on # purpose and as the port's libm-equivalence probe: if x86-64 and wasm32 # agree to the last bit through libHaru's %f formatter, that is a finding # worth having, and if they do not, the red is attributable to exactly one # cause because nothing else in this file goes near libm. A red here does NOT # mean the PDF is wrong -- see the design doc, which records what to do with # it -- and it is held apart from `circles` precisely so that it cannot be # confused with a curve-emission fault. # # EVERYTHING IS OFFLINE. No display, no network, no fonts beyond the base-14 set # libHaru has built in, and no input file of any kind: every document is written # from nothing but the API. require libharu-demo libharu/present tmp=${TMPDIR:-/tmp} w=$tmp/bst-libharu.$$ mkdir -p "$w" 2>/dev/null # ------------------------------------------------------------------ helpers --- # A PDF's first 8 bytes and last 6 are fixed by the format, and the offset after # `startxref` must land on the `xref` keyword -- three checks that are true of # every conforming file and of no truncated or half-written one, and none of # which depends on a stored value. pdf_head() { head -c 8 "$1" 2>/dev/null; } pdf_eof() { tail -c 6 "$1" 2>/dev/null | tr -d '\n'; } # The Catalog and the Pages node are the first two objects libHaru writes, so # 512 bytes is always enough and the parse never has to read a deflated stream. pdf_pagecount() { head -c 512 "$1" 2>/dev/null | awk '/^\/Type \/Pages$/ { f = 1 } f && /^\/Count / { print $2; exit }' } # Page objects counted independently of the Pages node's own bookkeeping, so a # /Count that disagrees with the objects actually written is caught rather than # believed. -a because docz carries deflated streams. pdf_pageobjs() { grep -a -c '^/Type /Page$' "$1" 2>/dev/null; } # The last 64 bytes are "startxref\n\n%%EOF\n" in every file here. pdf_xref_target() { _off=$(tail -c 64 "$1" 2>/dev/null | awk '/startxref/ { getline; gsub(/[^0-9]/, "", $0); print; exit }') [ -n "$_off" ] || { printf 'no-startxref'; return; } dd if="$1" bs=1 skip="$_off" count=4 2>/dev/null } sha() { sha256sum "$1" 2>/dev/null | cut -d' ' -f1; } size() { wc -c < "$1" 2>/dev/null | tr -d ' '; } # ------------------------------------------------------------------ version --- check_out libharu/version 2.4.4 libharu-demo version # ---------------------------------------------------------- doc: the ticket --- # "A demo programme writes a fixed PDF ... the criterion is a digest of the # produced file plus a structural check that it opens as a valid PDF with the # expected page count." Cases doc-rc through doc-deterministic are that sentence. check libharu/doc-rc libharu-demo doc "$w/doc.pdf" check libharu/doc-exists test -s "$w/doc.pdf" check_eq libharu/doc-size 8888 "$(size "$w/doc.pdf")" check_eq libharu/doc-sha256 \ 034194e1c0226607230395a51b79dd0967db6029a0548a1f39ce5dab217d0ce3 \ "$(sha "$w/doc.pdf")" check_eq libharu/doc-header '%PDF-1.3' "$(pdf_head "$w/doc.pdf")" check_eq libharu/doc-eof '%%EOF' "$(pdf_eof "$w/doc.pdf")" check_eq libharu/doc-pagecount 3 "$(pdf_pagecount "$w/doc.pdf")" check_eq libharu/doc-page-objects 3 "$(pdf_pageobjs "$w/doc.pdf")" check_eq libharu/doc-startxref xref "$(pdf_xref_target "$w/doc.pdf")" # The pinned date is what makes every digest above reproducible; assert it as # itself so that "the digest moved" and "the clock leaked in" are two results. check_out libharu/doc-creationdate "/CreationDate (D:20010101120000+00'00')" \ grep -a -o "/CreationDate ([^)]*)" "$w/doc.pdf" check_out libharu/doc-moddate "/ModDate (D:20010101120000+00'00')" \ grep -a -o "/ModDate ([^)]*)" "$w/doc.pdf" check_out libharu/doc-title "brintOS libHaru determinism fixture" \ grep -a -o "/Title ([^)]*)" "$w/doc.pdf" # Same subcommand, second file: the digest above proves reproducibility against # another machine, this proves it against another run on this one. libharu-demo doc "$w/doc2.pdf" >/dev/null 2>&1 check libharu/doc-deterministic cmp -s "$w/doc.pdf" "$w/doc2.pdf" # doc uses no compression, so a FlateDecode filter here would mean the # compression mode was ignored -- which is the thing docz's cases below prove # actually takes effect. check_eq libharu/doc-no-flate 0 "$(grep -a -c FlateDecode "$w/doc.pdf")" # -------------------------------------------------------------- docz: zlib --- # The same document through HPDF_COMP_ALL. Not digest-compared across machines # (see the header): checked for structure, for effect, and against itself. check libharu/docz-rc libharu-demo docz "$w/docz.pdf" check_eq libharu/docz-header '%PDF-1.3' "$(pdf_head "$w/docz.pdf")" check_eq libharu/docz-eof '%%EOF' "$(pdf_eof "$w/docz.pdf")" check_eq libharu/docz-pagecount 3 "$(pdf_pagecount "$w/docz.pdf")" check_eq libharu/docz-page-objects 3 "$(pdf_pageobjs "$w/docz.pdf")" check_eq libharu/docz-startxref xref "$(pdf_xref_target "$w/docz.pdf")" # Three deflated streams -- one content stream per page. A zlib that silently # did nothing would still produce a valid PDF, so the filter and the size are # both asserted: the filter says compression was requested of the stream, the # size says it happened. check_eq libharu/docz-flate-streams 3 "$(grep -a -c FlateDecode "$w/docz.pdf")" check libharu/docz-smaller \ test "$(size "$w/docz.pdf")" -lt "$(size "$w/doc.pdf")" libharu-demo docz "$w/docz2.pdf" >/dev/null 2>&1 check libharu/docz-deterministic cmp -s "$w/docz.pdf" "$w/docz2.pdf" # ------------------------------------------------- circles: curves, no libm --- check libharu/circles-rc libharu-demo circles "$w/circles.pdf" check_eq libharu/circles-size 3242 "$(size "$w/circles.pdf")" check_eq libharu/circles-sha256 \ a08cb25fdd54dbb3312685e98dfff11de6d2864f0f20e49af9940305d561aacf \ "$(sha "$w/circles.pdf")" check_eq libharu/circles-header '%PDF-1.3' "$(pdf_head "$w/circles.pdf")" check_eq libharu/circles-eof '%%EOF' "$(pdf_eof "$w/circles.pdf")" check_eq libharu/circles-pagecount 1 "$(pdf_pagecount "$w/circles.pdf")" check_eq libharu/circles-startxref xref "$(pdf_xref_target "$w/circles.pdf")" libharu-demo circles "$w/circles2.pdf" >/dev/null 2>&1 check libharu/circles-deterministic cmp -s "$w/circles.pdf" "$w/circles2.pdf" # ------------------------------------------------------ arcs: the libm probe --- # Everything here except the digest is a structural claim and holds whatever libm # returns; the digest is the one case in this file that is an x86-64/wasm32 # floating-point equivalence claim, and it is alone in that on purpose. check libharu/arcs-rc libharu-demo arcs "$w/arcs.pdf" check_eq libharu/arcs-header '%PDF-1.3' "$(pdf_head "$w/arcs.pdf")" check_eq libharu/arcs-eof '%%EOF' "$(pdf_eof "$w/arcs.pdf")" check_eq libharu/arcs-pagecount 1 "$(pdf_pagecount "$w/arcs.pdf")" check_eq libharu/arcs-startxref xref "$(pdf_xref_target "$w/arcs.pdf")" libharu-demo arcs "$w/arcs2.pdf" >/dev/null 2>&1 check libharu/arcs-deterministic cmp -s "$w/arcs.pdf" "$w/arcs2.pdf" check_eq libharu/arcs-size 2172 "$(size "$w/arcs.pdf")" check_eq libharu/arcs-sha256-libm \ 17af4774c847b0b15cdd4d4932e0ad361d0d15a206c8e223211d906b55b21e17 \ "$(sha "$w/arcs.pdf")" # ------------------------------------------------------- the error handler --- # libHaru's documented error idiom, and the shape every upstream demo uses: # longjmp out of the library's own callback, here provoked with a font name that # is not one of the base-14. It is the one construct in this port that could # plausibly fail on a coroutinized arm while every ordinary call succeeded, and # nothing else on this image exercises setjmp/longjmp across a library frame. # 0x102F is HPDF_INVALID_FONT_NAME. check_out libharu/error-longjmp 'longjmp-taken error=0x102F' libharu-demo error # ------------------------------------------------------------- CLI hygiene --- check_rc libharu/usage-no-args 2 libharu-demo check_rc libharu/usage-bad-verb 2 libharu-demo bogus out.pdf check_rc libharu/usage-missing-arg 2 libharu-demo doc # --------------------------------------------------------------- packaging --- # The dev and staticdev packages are in this image's EMCRAFT_TOOLS, so the # archive and the public header are on target and their absence is a packaging # regression rather than a missing feature. check libharu/staticdev-archive test -f /usr/lib/libhpdf.a check libharu/dev-header test -f /usr/include/hpdf.h check libharu/dev-config-header test -f /usr/include/hpdf_config.h # The 1.2 MB of C#/Delphi/FreeBASIC/Oberon-2/Python/Ruby/VB bindings upstream # installs into ${datadir}/libharu are re-homed to libharu-doc by the bbappend, # and this image ships no port's -doc package. If they reappear, FILES:${PN}-doc # stopped matching and the rootfs grew by more than the port itself. check libharu/no-bindings-shipped test ! -d /usr/share/libharu/bindings # The driver is what makes the bare `libharu` package non-empty; if it is missing # the package regressed to documentation-only and every case above already failed # on `require`, so this asserts the install path rather than the tool. check libharu/installed-demo test -x /usr/bin/libharu-demo rm -rf "$w"