1
1
# This file is a part of Julia. License is MIT: http://julialang.org/license
2
2
3
3
module iconv
4
- import Base: close, eof, flush, read, readall, write
4
+ import Base: close, eof, flush, read, readall, write, show
5
5
import Base. Libc: errno, strerror, E2BIG, EINVAL, EILSEQ
6
6
export StringEncoder, StringDecoder, encode, decode
7
+ export StringEncodingError, OutputBufferError, IConvError
8
+ export InvalidEncodingError, InvalidSequenceError, IncompleteSequenceError
9
+
10
+
11
+ abstract StringEncodingError
12
+
13
+ # Specified encodings or the combination are not supported by iconv
14
+ type InvalidEncodingError <: StringEncodingError
15
+ args:: Tuple{ASCIIString, ASCIIString}
16
+ end
17
+ InvalidEncodingError (from, to) = InvalidEncodingError ((from, to))
18
+ message (:: Type{InvalidEncodingError} ) = " Conversion from <<1>> to <<2>> not supported by iconv implementation, check that specified encodings are correct"
19
+
20
+ # Encountered invalid byte sequence
21
+ type InvalidSequenceError <: StringEncodingError
22
+ args:: Tuple{ASCIIString}
23
+ end
24
+ InvalidSequenceError (seq:: Vector{UInt8} ) = InvalidSequenceError ((bytes2hex (seq),))
25
+ message (:: Type{InvalidSequenceError} ) = " Byte sequence 0x<<1>> is invalid in source encoding or cannot be represented in target encoding"
26
+
27
+ type IConvError <: StringEncodingError
28
+ args:: Tuple{ASCIIString, Int, ASCIIString}
29
+ end
30
+ IConvError (func) = IConvError ((func, errno (), strerror (errno ())))
31
+ message (:: Type{IConvError} ) = " <<1>>: <<2>> (<<3>>)"
32
+
33
+ # Input ended with incomplete byte sequence
34
+ type IncompleteSequenceError <: StringEncodingError ; end
35
+ message (:: Type{IncompleteSequenceError} ) = " Incomplete byte sequence at end of input"
36
+
37
+ type OutputBufferError <: StringEncodingError ; end
38
+ message (:: Type{OutputBufferError} ) = " Ran out of space in the output buffer"
39
+
40
+ function show (io:: IO , exc:: StringEncodingError )
41
+ str = message (typeof (exc))
42
+ for i = 1 : length (exc. args)
43
+ str = replace (str, " <<$i >>" , exc. args[i])
44
+ end
45
+ print (io, str)
46
+ end
47
+
48
+ show {T<:Union{IncompleteSequenceError,OutputBufferError}} (io:: IO , exc:: T ) =
49
+ print (io, message (T))
7
50
8
51
depsjl = joinpath (dirname (@__FILE__ ), " .." , " deps" , " deps.jl" )
9
52
isfile (depsjl) ? include (depsjl) : error (" libiconv not properly installed. Please run\n Pkg.build(\" iconv\" )" )
@@ -14,7 +57,7 @@ isfile(depsjl) ? include(depsjl) : error("libiconv not properly installed. Pleas
14
57
function iconv_close (cd:: Ptr{Void} )
15
58
if cd != C_NULL
16
59
ccall ((:iconv_close , libiconv), Cint, (Ptr{Void},), cd) == 0 ||
17
- error ( " failed to call iconv_close: error $( errno ()) ( $( strerror ( errno ())) ) " )
60
+ throw ( IConvError ( " iconv_close" ) )
18
61
end
19
62
end
20
63
@@ -23,9 +66,9 @@ function iconv_open(tocode, fromcode)
23
66
if p != Ptr {Void} (- 1 )
24
67
return p
25
68
elseif errno () == EINVAL
26
- error ( " conversion from $ fromcode to $tocode not supported by iconv implementation, check that specified encodings are correct " )
69
+ throw ( InvalidEncodingError ( fromcode, tocode) )
27
70
else
28
- error ( " iconv_open error $( errno ()) : $( strerror ( errno ())) " )
71
+ throw ( IConvError ( " iconv_open" ) )
29
72
end
30
73
end
31
74
@@ -84,16 +127,16 @@ function iconv!(cd::Ptr{Void}, inbuf::Vector{UInt8}, outbuf::Vector{UInt8},
84
127
85
128
# Should never happen unless a very small buffer is used
86
129
if err == E2BIG && outbytesleft[] == BUFSIZE
87
- error ( " iconv error: ran out of space in the output buffer " )
130
+ throw ( OutputBufferError () )
88
131
# Output buffer is full, or sequence is incomplete:
89
132
# copy remaining bytes to the start of the input buffer for next time
90
133
elseif err == E2BIG || err == EINVAL
91
134
copy! (inbuf, 1 , inbuf, inbytesleft_orig- inbytesleft[]+ 1 , inbytesleft[])
92
135
elseif err == EILSEQ
93
- b = inbuf[(inbytesleft_orig- inbytesleft[]+ 1 ): inbytesleft_orig]
94
- error ( " iconv error: byte sequence 0x $( bytes2hex (b)) is invalid in source encoding or cannot be represented in target encoding " )
136
+ seq = inbuf[(inbytesleft_orig- inbytesleft[]+ 1 ): inbytesleft_orig]
137
+ throw ( InvalidSequenceError (seq) )
95
138
else
96
- error ( " iconv error $( errno ()) : $( strerror ( errno ())) " )
139
+ throw ( IConvError ( " iconv" ) )
97
140
end
98
141
end
99
142
@@ -114,13 +157,11 @@ function iconv_reset!(s::Union{StringEncoder, StringDecoder})
114
157
if ret == - 1 % Csize_t
115
158
err = errno ()
116
159
if err == EINVAL
117
- error ( " iconv error: incomplete byte sequence at end of input " )
160
+ throw ( IncompleteSequenceError () )
118
161
elseif err == E2BIG
119
- error (" iconv error: ran out of space in the output buffer" )
120
- elseif err == EILSEQ
121
- error (" iconv error: invalid byte sequence in input" )
162
+ throw (OutputBufferError ())
122
163
else
123
- error ( " iconv error $( errno ()) : $( strerror ( errno ())) " )
164
+ throw ( IConvError ( " iconv" ) )
124
165
end
125
166
end
126
167
@@ -171,7 +212,7 @@ function close(s::StringEncoder)
171
212
# Make sure C memory/resources are returned
172
213
finalize (s)
173
214
# flush() wasn't able to empty input buffer, which cannot happen with correct data
174
- s. inbytesleft[] == 0 || error ( " iconv error: incomplete byte sequence at end of input " )
215
+ s. inbytesleft[] == 0 || throw ( IncompleteSequenceError () )
175
216
end
176
217
177
218
function write (s:: StringEncoder , x:: UInt8 )
@@ -236,7 +277,7 @@ function close(s::StringDecoder)
236
277
# Make sure C memory/resources are returned
237
278
finalize (s)
238
279
# iconv_reset!() wasn't able to empty input buffer, which cannot happen with correct data
239
- s. inbytesleft[] == 0 || error ( " iconv error: incomplete byte sequence at end of input " )
280
+ s. inbytesleft[] == 0 || throw ( IncompleteSequenceError () )
240
281
end
241
282
242
283
function read (s:: StringDecoder , :: Type{UInt8} )
0 commit comments