You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/pitfall/fontkit/directory.rkt

88 lines
3.4 KiB
Racket

#lang fontkit/racket
(require restructure "tables.rkt")
(provide (all-defined-out))
#|
https://github.com/mbutterick/fontkit/blob/master/src/tables/directory.js
|#
(define TableEntry (+Struct
(dictify 'tag (+String 4)
'checkSum uint32be
'offset uint32be
'length uint32be)))
;; for stupid tags like 'cvt '
(define (symbol-replace sym this that)
(string->symbol (string-replace (if (string? sym) sym (symbol->string sym)) this that)))
(define (escape-tag tag) (symbol-replace tag " " "_"))
(define (unescape-tag tag) (symbol-replace tag "_" " "))
(define-subclass Struct (RDirectory)
(define/override (process this-res stream)
(define new-tables-val (mhash))
(for ([table (in-list (· this-res tables))])
(hash-set! new-tables-val (escape-tag (· table tag)) table))
(hash-set! this-res 'tables new-tables-val))
(define/override (preEncode this-val stream)
(define preamble-length 12)
(define table-header-size (+ preamble-length
(* (length (hash-keys (· this-val tables))) (send TableEntry size))))
(define-values (table-headers table-datas _)
(for/lists (ths tds lens)
([(tag table) (in-hash (· this-val tables))])
(define table-data
(let ([es (+EncodeStream)])
(send (hash-ref table-codecs tag) encode es table)
(send es dump)))
(define table-header (mhash
'tag (unescape-tag tag)
'checkSum 0
'offset (apply + (cons table-header-size lens))
'length (bytes-length table-data)))
(values table-header table-data (bytes-length table-data))))
(define numTables (length table-headers))
(define searchRange (* (floor (log numTables 2)) 16))
(hash-set*! this-val
'tag "true"
'numTables numTables
'tables table-headers
'searchRange searchRange
'entrySelector (floor (/ searchRange (log 2)))
'rangeShift (- (* numTables 16) searchRange)
'data table-datas)))
(define directory-common-dict (dictify 'tag (+String 4)
'numTables uint16be
'searchRange uint16be
'entrySelector uint16be
'rangeShift uint16be
'tables (+Array TableEntry 'numTables)))
(define Directory (+RDirectory directory-common-dict))
;; we don't know what tables we might get
;; so we represent as generic Buffer type,
;; and convert the tables to bytes manually in preEncode
(define EncodableDirectory (+RDirectory (append directory-common-dict (list (cons 'data (+Array (+Buffer)))))))
(define (directory-decode ip [options (mhash)])
(send Directory decode (+DecodeStream (port->bytes ip))))
(define (file-directory-decode ps)
(directory-decode (open-input-file ps)))
(test-module
(define ip (open-input-file charter-path))
(define decoded-dir (deserialize (read (open-input-file charter-directory-path))))
(check-equal? (directory-decode ip) decoded-dir))