1;;; Encoding and decoding byte representations of strings
2
3;; Copyright (C) 2013, 2021 Free Software Foundation, Inc.
4
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13;;;; Lesser General Public License for more details.
14;;;;
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19;;; Code:
20
21(define-module (ice-9 iconv)
22  #:use-module (rnrs bytevectors)
23  #:use-module (ice-9 binary-ports)
24  #:use-module ((ice-9 rdelim) #:select (read-string))
25  #:export (string->bytevector
26            bytevector->string
27            call-with-encoded-output-string))
28
29(define* (call-with-encoded-output-string encoding proc
30                                          #:optional
31                                          (conversion-strategy 'error))
32  "Call PROC on a fresh port.  Encode the resulting string as a
33bytevector according to ENCODING, and return the bytevector."
34  (if (and (string-ci=? encoding "utf-8")
35           (eq? conversion-strategy 'error))
36      ;; I don't know why, but this appears to be faster; at least for
37      ;; serving examples/debug-sxml.scm (1464 reqs/s versus 850
38      ;; reqs/s).
39      (string->utf8 (call-with-output-string proc))
40      (call-with-output-bytevector
41       (lambda (port)
42         (set-port-encoding! port encoding)
43         (if conversion-strategy
44             (set-port-conversion-strategy! port conversion-strategy))
45         (proc port)))))
46
47;; TODO: Provide C implementations that call scm_from_stringn and
48;; friends?
49
50(define* (string->bytevector str encoding
51                             #:optional (conversion-strategy 'error))
52  "Encode STRING according to ENCODING, which should be a string naming
53a character encoding, like \"utf-8\"."
54  (if (and (string-ci=? encoding "utf-8")
55           (eq? conversion-strategy 'error))
56      (string->utf8 str)
57      (call-with-encoded-output-string
58       encoding
59       (lambda (port)
60         (display str port))
61       conversion-strategy)))
62
63(define* (bytevector->string bv encoding
64                             #:optional (conversion-strategy 'error))
65  "Decode the string represented by BV.  The bytes in the bytevector
66will be interpreted according to ENCODING, which should be a string
67naming a character encoding, like \"utf-8\"."
68  (if (and (string-ci=? encoding "utf-8")
69           (eq? conversion-strategy 'error))
70      (utf8->string bv)
71      (let ((p (open-bytevector-input-port bv)))
72        (set-port-encoding! p encoding)
73        (if conversion-strategy
74            (set-port-conversion-strategy! p conversion-strategy))
75        (let ((res (read-string p)))
76          (close-port p)
77          (if (eof-object? res)
78              ""
79              res)))))
80