Parse data URIs into bytevector+mimetype lists

This commit is contained in:
Jaidyn Ann 2024-02-11 09:22:07 -06:00
parent 6c744928f8
commit 5de1c57b18
2 changed files with 77 additions and 8 deletions

View File

@ -3,6 +3,6 @@
(author "Jaidyn Ann") (author "Jaidyn Ann")
(category net) (category net)
(license "GPLv3") (license "GPLv3")
(dependencies srfi-1 srfi-13 srfi-130 uri-common) (dependencies srfi-1 srfi-4 srfi-13 srfi-19 srfi-130 srfi-207 uri-common)
(components (components
(extension vcarded))) (extension vcarded)))

View File

@ -21,10 +21,12 @@
(chicken base) (chicken base)
(chicken condition) (chicken condition)
(chicken io) (chicken io)
srfi-1 (srfi 1)
srfi-13 (srfi 4)
srfi-19 (srfi 13)
srfi-130 (srfi 19)
(srfi 130)
(srfi 207)
(prefix uri-common uri:)) (prefix uri-common uri:))
@ -61,6 +63,74 @@
(ignore-error (string->date str hms) #f)))) (ignore-error (string->date str hms) #f))))
;; Parse a string into a URI object.
(define (string->uri string)
(uri:uri-reference string))
;; Parse a data URIs contents into a list containing the mimetype (string)
;; and bytevector contents (u8vector).
;; "data:text/plain;base64,ZGFk" → ("text/plain;base64" #u8(100 97 100))
(define (data-uri-str->bytevector uri)
(let* [(str (string-drop uri (string-length "data:")))
(split (string-split str ","))
(mimetype (car split))
(contents (string-join (cdr split) ","))]
(list
mimetype
(if (string-contains mimetype "base64")
(base64->bytevector contents)
(list->u8vector
(map char->integer
(string->list contents)))))))
;; Given a bytevector and according mimetype, return the associated
;; data-URI.
;; "text/plain;base64" #u8(100 97 100) → "data:text/plain;base64,ZGFk"
(define (bytevector->data-uri-str mimetype bytevector)
(string-concatenate
(list
"data:"
mimetype
","
(if (string-contains mimetype "base64")
(bytevector->base64 bytevector)
(list->string
(map integer->char
(u8vector->list bytevector)))))))
;; Given a URI propertys value string(s) (like PHOTO or URL), return either
;; a URI (if URI is valid), string (if invalid), or u8vector/bytevector (if
;; data-URI).
(define (parse-uri-prop-value . strings)
(let* [(str (string-join strings ";"))
;; We parse data URIs ourselves; so lets not be redundant.
(uri (if (not (string-prefix? "data:" str))
(string->uri str)))]
(cond
[(string-prefix? "data:" str)
(data-uri-str->bytevector str)]
[(not (uri:uri? uri))
str]
[#t
uri])))
;; Given a parsed URI propertys value, serialize back into the original
;; string-form… as best we can.
(define (serialize-uri-prop-value value)
(cond [(uri:uri? value)
(uri:uri->string value)]
[(list? value)
(bytevector->data-uri-str (car value) (cadr value))]
[(string? value)
value]
[#t
""]))
;; A list of the parser/serializer functions for each vcard property. ;; A list of the parser/serializer functions for each vcard property.
;; ((TEL #<procedure> #<procedure>) ;; ((TEL #<procedure> #<procedure>)
;; (ADR #<procedure> #<procedure>) ;; (ADR #<procedure> #<procedure>)
@ -70,9 +140,8 @@
(append (append
(map (lambda (uri-prop) (map (lambda (uri-prop)
(list uri-prop (list uri-prop
(lambda strs (or (uri:uri-reference (string-join strs ";")) parse-uri-prop-value
(string-join strs ";"))) serialize-uri-prop-value))
(lambda (url) (uri:uri->string url))))
vcard-url-properties) vcard-url-properties)
(map (lambda (date-prop) (map (lambda (date-prop)
(list date-prop (list date-prop