[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [code] Quoted-printable decoding.
From: |
Ludovic Courtès |
Subject: |
Re: [code] Quoted-printable decoding. |
Date: |
Sat, 17 Aug 2013 14:50:29 +0200 |
User-agent: |
Gnus/5.130007 (Ma Gnus v0.7) Emacs/24.3 (gnu/linux) |
Dmitry Bogatov <address@hidden> skribis:
> Today I faced the need to decode quoted-printable message, and for fun,
> learning and love to scheme implemented it myself rather than use any
> other language. I found no existing implementation in Guile or Guile
> Lib.
>
> I would like to share code and ready to work and discuss to make it part
> of Guile. If it possible, I would like to put my code to public domain
> to avoid legal issues.
That’s something that could perhaps end up in a (web ...) module, Andy?
> (use-modules (ice-9 iconv))
> (use-modules (rnrs bytevectors))
> (use-modules (rnrs io ports))
> (use-modules (ice-9 receive))
> (use-modules (ice-9 binary-ports))
Several modules can be listed in a single ‘use-modules’.
> (define (newline? ch) (or (char=? ch #\newline)
> (char=? ch #\return)))
>
> (define (hex-char? ch)
> (define (in-range low high)
> (and (char<=? low ch)
> (char<=? ch high)))
> (or (in-range #\0 #\9)
> (in-range #\A #\F)
> (in-range #\a #\f)))
Use SRFI-14 character sets instead.
> (define* (decode str #:key (enc "utf-8"))
> (define (char-ref index) (string-ref str index))
> (define length (string-length str))
> (define index 0)
> (receive [bv-port bv-get-content]
> [open-bytevector-output-port]
> (while (not (= index length))
> (let ([char (char-ref index)])
> (if (char=? char #\=)
> (let ([char+ (char-ref (+ 1 index))]
> [char++ (char-ref (+ 2 index))])
> (cond
> [[hex-char? char+]
> (put-u8 bv-port
> (string->number
> (string char+ char++) 16))
> (inc! index 2)]
> [[newline? char++] (inc! index 2)]
> [else (inc! index)]))
> (put-u8 bv-port (char->integer char))))
> (inc! index))
> (bytevector->string (bv-get-content) enc
> 'substitute)))
I think this function is not robust against malformed input (it could
lead to out-of-bounds references).
Stylistic note: some of us (ahem) prefer a functional style. I would
write the loop as a recursive function, and pass the index value as an
argument:
(let loop ((index 0))
...
(loop (+ 1 index)))
Ludo’.