Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 49f1370

Browse files
Use StringError exception and errors
Implement Milan's idea for abstract StringEncodingError Changes per Milan's review: generalerror -> iconv_error Removal of iconv: from most error messages Addition of more specific exceptions: IConvError, OutputBufferError, InvalidBytesError Eliminate GeneralError, per review Remove iconv_error, modulename, clean up show, per review
1 parent 4cb98a3 commit 49f1370

File tree

2 files changed

+78
-25
lines changed

2 files changed

+78
-25
lines changed

‎src/iconv.jl‎

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,52 @@
11
# This file is a part of Julia. License is MIT: http://julialang.org/license
22

33
module iconv
4-
import Base: close, eof, flush, read, readall, write
4+
import Base: close, eof, flush, read, readall, write, show
55
import Base.Libc: errno, strerror, E2BIG, EINVAL, EILSEQ
66
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))
750

851
depsjl = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
952
isfile(depsjl) ? include(depsjl) : error("libiconv not properly installed. Please run\nPkg.build(\"iconv\")")
@@ -14,7 +57,7 @@ isfile(depsjl) ? include(depsjl) : error("libiconv not properly installed. Pleas
1457
function 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
1962
end
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
3073
end
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())
175216
end
176217

177218
function 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())
240281
end
241282

242283
function read(s::StringDecoder, ::Type{UInt8})

‎test/runtests.jl‎

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,23 @@ end
2929
let s = "a string チャネルパートナーの選択"
3030
p = StringEncoder(IOBuffer(), "UTF-16LE")
3131
write(p, s.data[1:10])
32-
@test_throws ErrorException close(p)
32+
@test_throws IncompleteSequenceError close(p)
33+
34+
# This time, call show
35+
p = StringEncoder(IOBuffer(), "UTF-16LE")
36+
write(p, s.data[1:10])
37+
try
38+
close(p)
39+
catch err
40+
@test isa(err, IncompleteSequenceError)
41+
io = IOBuffer()
42+
showerror(io, err)
43+
@test takebuf_string(io) == "Incomplete byte sequence at end of input"
44+
end
3345

3446
p = StringDecoder(IOBuffer(encode(s, "UTF-16LE")[1:19]), "UTF-16LE")
3547
@test readall(p) == s[1:9]
36-
@test_throws ErrorException close(p)
48+
@test_throws IncompleteSequenceError close(p)
3749

3850
# Test stateful encoding, which output some bytes on final reset
3951
# with strings containing different scripts
@@ -48,39 +60,39 @@ let s = "a string チャネルパートナーの選択"
4860
close(p)
4961
end
5062

51-
@test_throws ErrorException encode("qwertyé€", "ASCII")
63+
@test_throws InvalidSequenceError encode("qwertyé€", "ASCII")
5264
try
5365
encode("qwertyé€", "ASCII")
5466
catch err
5567
io = IOBuffer()
5668
showerror(io, err)
5769
@test takebuf_string(io) ==
58-
"iconv error: byte sequence 0xc3a9e282ac is invalid in source encoding or cannot be represented in target encoding"
70+
"Byte sequence 0xc3a9e282ac is invalid in source encoding or cannot be represented in target encoding"
5971
end
6072

6173
# win_iconv currently does not throw an error on bytes >= 0x80 in ASCII sources
6274
# https://github.com/win-iconv/win-iconv/pull/26
6375
if OS_NAME != :Windows
64-
@test_throws ErrorException decode(b"qwertyé€", "ASCII")
76+
@test_throws InvalidSequenceError decode(b"qwertyé€", "ASCII")
6577
try
6678
decode(b"qwertyé€", "ASCII")
6779
catch err
6880
io = IOBuffer()
6981
showerror(io, err)
7082
@test takebuf_string(io) ==
71-
"iconv error: byte sequence 0xc3a9e282ac is invalid in source encoding or cannot be represented in target encoding"
83+
"Byte sequence 0xc3a9e282ac is invalid in source encoding or cannot be represented in target encoding"
7284
end
7385
end
7486

7587
let x = encode("ÄÆä", "ISO-8859-1")
76-
@test_throws ErrorException decode(x, "UTF-8")
88+
@test_throws InvalidSequenceError decode(x, "UTF-8")
7789
try
7890
decode(x, "UTF-8")
7991
catch err
8092
io = IOBuffer()
8193
showerror(io, err)
8294
@test takebuf_string(io) ==
83-
"iconv error: byte sequence 0xc4c6e4 is invalid in source encoding or cannot be represented in target encoding"
95+
"Byte sequence 0xc4c6e4 is invalid in source encoding or cannot be represented in target encoding"
8496
end
8597
end
8698

@@ -91,7 +103,7 @@ mktemp() do p, io
91103
@test readall(p, "CP1252") == s
92104
end
93105

94-
@test_throws ErrorException p = StringEncoder(IOBuffer(), "nonexistent_encoding")
95-
@test_throws ErrorException p = StringDecoder(IOBuffer(), "nonexistent_encoding")
106+
@test_throws InvalidEncodingError p = StringEncoder(IOBuffer(), "nonexistent_encoding")
107+
@test_throws InvalidEncodingError p = StringDecoder(IOBuffer(), "nonexistent_encoding")
96108

97109
nothing

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /