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 >>" . 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