11# This file is a part of Julia. License is MIT: http://julialang.org/license
22
33module iconv
4- import Base: close, eof, flush, read, readall, write
4+ import Base: close, eof, flush, read, readall, write, show
55import Base. Libc: errno, strerror, E2BIG, EINVAL, EILSEQ
66export 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))
750
851depsjl = joinpath (dirname (@__FILE__ ), " .." , " deps" , " deps.jl" )
952isfile (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
1457function iconv_close (cd:: Ptr{Void} )
1558 if cd != C_NULL
1659 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" ) )
1861 end
1962end
2063
@@ -23,9 +66,9 @@ function iconv_open(tocode, fromcode)
2366 if p != Ptr {Void} (- 1 )
2467 return p
2568 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) )
2770 else
28- error ( " iconv_open error $( errno ()) : $( strerror ( errno ())) " )
71+ throw ( IConvError ( " iconv_open" ) )
2972 end
3073end
3174
@@ -84,16 +127,16 @@ function iconv!(cd::Ptr{Void}, inbuf::Vector{UInt8}, outbuf::Vector{UInt8},
84127
85128 # Should never happen unless a very small buffer is used
86129 if err == E2BIG && outbytesleft[] == BUFSIZE
87- error ( " iconv error: ran out of space in the output buffer " )
130+ throw ( OutputBufferError () )
88131 # Output buffer is full, or sequence is incomplete:
89132 # copy remaining bytes to the start of the input buffer for next time
90133 elseif err == E2BIG || err == EINVAL
91134 copy! (inbuf, 1 , inbuf, inbytesleft_orig- inbytesleft[]+ 1 , inbytesleft[])
92135 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) )
95138 else
96- error ( " iconv error $( errno ()) : $( strerror ( errno ())) " )
139+ throw ( IConvError ( " iconv" ) )
97140 end
98141 end
99142
@@ -114,13 +157,11 @@ function iconv_reset!(s::Union{StringEncoder, StringDecoder})
114157 if ret == - 1 % Csize_t
115158 err = errno ()
116159 if err == EINVAL
117- error ( " iconv error: incomplete byte sequence at end of input " )
160+ throw ( IncompleteSequenceError () )
118161 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 ())
122163 else
123- error ( " iconv error $( errno ()) : $( strerror ( errno ())) " )
164+ throw ( IConvError ( " iconv" ) )
124165 end
125166 end
126167
@@ -171,7 +212,7 @@ function close(s::StringEncoder)
171212 # Make sure C memory/resources are returned
172213 finalize (s)
173214 # 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 () )
175216end
176217
177218function write (s:: StringEncoder , x:: UInt8 )
@@ -236,7 +277,7 @@ function close(s::StringDecoder)
236277 # Make sure C memory/resources are returned
237278 finalize (s)
238279 # 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 () )
240281end
241282
242283function read (s:: StringDecoder , :: Type{UInt8} )
0 commit comments