1 # gaf - Python library for manipulating gEDA files
2 #**********************************************************************
4 # __ _ _ __ ___| |_ | |__ __ _ ___ ___ / /_ | or |
5 # / _` | '_ \ / _ \ __| | '_ \ / _` / __|/ _ \ '_ \| or |_
6 # | (_| | | | | __/ |_ | |_) | (_| \__ \ __/ (_) |__ _|
7 # \__, |_| |_|\___|\__| |_.__/ \__,_|___/\___|\___/ |_|
10 # created by Alfred Reibenschuh <alfredreibenschuh@gmx.net>,
11 # under the "GNU Library General Public License" (see below).
13 #**********************************************************************
14 # Copyright (C) 2003 Free Software Foundation
15 # Copyright (C) 2013-2020 Roland Lutz
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
27 # You should have received a copy of the GNU General Public License
28 # along with this program; if not, write to the Free Software Foundation,
29 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 ## \namespace xorn.base64
32 ## Reading and writing base64-encoded data
34 from gettext
import gettext
as _
36 BASE64
= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
39 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0x00-0x0f
40 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0x10-0x1f
41 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, # 0x20-0x2f
42 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, # 0x30-0x3f
43 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, # 0x40-0x4f
44 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, # 0x50-0x5f
45 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, # 0x60-0x6f
46 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, # 0x70-0x7f
47 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0x80-0x8f
48 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0x90-0x9f
49 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0xa0-0xaf
50 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0xb0-0xbf
51 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0xc0-0xcf
52 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0xd0-0xdf
53 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0xe0-0xef
54 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 0xf0-0xff
57 ## Write a binary string to a file in %base64 representation.
59 # If \a columns is not \c None, insert a newline every \a columns
60 # characters. This is required by RFC 2045, but some applications
61 # don't require it. \a columns must positive and a multiple of \c 4.
63 # If \a delim is not \c None, it is written on a separate line after
64 # the data. This argument is provided for symmetry with \ref decode.
68 def encode(f
, src
, columns
= 72, delim
= None):
70 blen
= len(src
) - len(src
) % 3
73 for pos
in xrange(0, blen
, 3):
74 # Convert 3 bytes of src to 4 bytes of output
76 # output[0] = input[0] 7:2
77 # output[1] = input[0] 1:0 input[1] 7:4
78 # output[2] = input[1] 3:0 input[2] 7:6
79 # output[3] = input[1] 5:0
81 i0
, i1
, i2
= [ord(ch
) for ch
in src
[pos
:pos
+ 3]]
83 # Map output to the Base64 alphabet
84 f
.write(BASE64
[i0
>> 2] +
85 BASE64
[((i0
& 0x03) << 4) + (i1
>> 4)] +
86 BASE64
[((i1
& 0x0f) << 2) + (i2
>> 6)] +
89 if columns
is not None:
91 if ocnt
% (columns
/ 4) == 0 and pos
!= len(src
) - 3:
94 # Now worry about padding with remaining 1 or 2 bytes
97 if blen
== len(src
) - 1:
100 i1
= ord(src
[blen
+ 1])
103 f
.write(BASE64
[i0
>> 2] +
104 BASE64
[((i0
& 0x03) << 4) + (i1
>> 4)])
105 if blen
== len(src
) - 1:
108 f
.write(BASE64
[((i1
& 0x0f) << 2) + (i2
>> 6)])
114 if delim
is not None:
115 f
.write(delim
+ '\n')
117 ## Raised when reading invalid or unterminated base64-encoded data.
119 class DecodingError(Exception):
122 ## Read a string in %base64 representation from a file.
124 # This function is liberal in what it will accept. It ignores
125 # non-base64 symbols.
127 # If \a delim is \c None, read until the end of the file. If \a delim
128 # is not \c None, read until a line containing exactly \a delim is
131 # \return A string containing the decoded data.
133 # \throw DecodingError if reading something that is not valid
134 # base64-encoded data
135 # \throw DecodingError if the end of the file is hit and \a delim is
138 def decode(f
, delim
= None):
148 except StopIteration:
149 if delim
is not None:
150 raise DecodingError
, _("Unexpected end-of-file")
153 if delim
is not None and line
== delim
+ '\n':
162 # Skip any non-base64 anywhere
172 res
= (pos
& 0x0f) << 4
175 dst
+= [res |
(pos
>> 2)]
176 res
= (pos
& 0x03) << 6
182 # We are done decoding Base-64 chars. Let's see if we ended
183 # on a byte boundary, and/or with erroneous trailing characters.
187 # Invalid = in first position
190 # Invalid = in second position
193 # Valid, means one byte of info
194 # Make sure there is another trailing = sign.
198 # Valid, means two bytes of info
199 # We know this char is an =. Is there anything but
200 # whitespace after it?
203 if state
== 2 or state
== 3:
204 # Now make sure for cases 2 and 3 that the "extra"
205 # bits that slopped past the last full byte were
206 # zeros. If we don't check them, they become a
207 # subliminal channel.
211 # We ended by seeing the end of the string. Make sure we
212 # have no partial bytes lying around.
215 return ''.join(chr(b
) for b
in dst
)