1 #!/usr/bin/env python 2 3 """ 4 POSIX character set conversion functions. 5 6 Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from __builtins__.types import check_int, check_string 23 from native import iconv, iconv_close, iconv_open, iconv_reset 24 25 # Errors produced by iconv. 26 27 EINVAL = 22 28 EILSEQ = 84 29 30 class ConverterError(Exception): 31 32 "An error indicating a failure involving a character set converter." 33 34 pass 35 36 class Converter: 37 38 "A character set converter." 39 40 def __init__(self, from_encoding, to_encoding): 41 42 "Initialise conversion between 'from_encoding' and 'to_encoding'." 43 44 check_string(from_encoding) 45 check_string(to_encoding) 46 self.__data__ = iconv_open(to_encoding, from_encoding) 47 self.reset() 48 49 def reset(self): 50 51 "Reset the state of the converter." 52 53 self.state = ["", 0, 0] 54 self.result = [] 55 iconv_reset(self.__data__) 56 57 def close(self): 58 59 "Close this converter." 60 61 iconv_close(self.__data__) 62 self.__data__ = None 63 64 def feed(self, s): 65 66 "Feed 's' to the converter." 67 68 if self.__data__ is None: 69 raise ConverterError 70 71 check_string(s) 72 73 _s, start, remaining = self.state 74 75 if _s: 76 self.state = [_s + s, start, remaining + len(s)] 77 else: 78 self.state = [s, 0, len(s)] 79 80 while True: 81 82 # Obtain converted text and update the state. 83 84 try: 85 out = iconv(self.__data__, self.state) 86 87 # Incomplete input does not cause an exception. 88 89 except OSError, exc: 90 if exc.value == EINVAL: 91 self.result.append(exc.arg) 92 return 93 else: 94 raise 95 96 # Add any returned text to the result. 97 98 self.result.append(out) 99 100 # Test for the end of the conversion. 101 102 _s, start, remaining = self.state 103 104 if not remaining: 105 return 106 107 def __str__(self): 108 109 "Return the value of the converted string." 110 111 return "".join(self.result) 112 113 # vim: tabstop=4 expandtab shiftwidth=4