• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37728

26 Mar 2024 03:46AM UTC coverage: 80.612% (-0.8%) from 81.423%
#37728

push

local

web-flow
Update zlib to 1.3.1 (#53841)

Released January 22, 2024

69920 of 86737 relevant lines covered (80.61%)

14456248.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.07
/stdlib/Base64/src/decode.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# Generate decode table.
4
const BASE64_CODE_END = 0x40
5
const BASE64_CODE_PAD = 0x41
6
const BASE64_CODE_IGN = 0x42
7
const BASE64_DECODE = fill(BASE64_CODE_IGN, 256)
8
for (i, c) in enumerate(BASE64_ENCODE)
9
    BASE64_DECODE[Int(c)+1] = UInt8(i - 1)
10
end
11
BASE64_DECODE[Int(encodepadding())+1] = BASE64_CODE_PAD
12
decode(x::UInt8) = @inbounds return BASE64_DECODE[x + 1]
352✔
13

14
"""
15
    Base64DecodePipe(istream)
16

17
Return a new read-only I/O stream, which decodes base64-encoded data read from
18
`istream`.
19

20
# Examples
21
```jldoctest
22
julia> io = IOBuffer();
23

24
julia> iob64_decode = Base64DecodePipe(io);
25

26
julia> write(io, "SGVsbG8h")
27
8
28

29
julia> seekstart(io);
30

31
julia> String(read(iob64_decode))
32
"Hello!"
33
```
34
"""
35
struct Base64DecodePipe <: IO
36
    io::IO
37
    buffer::Buffer
38
    rest::Vector{UInt8}
39

40
    function Base64DecodePipe(io::IO)
41
        buffer = Buffer(512)
1✔
42
        return new(io, buffer, UInt8[])
1✔
43
    end
44
end
45

46
Base.isreadable(pipe::Base64DecodePipe) = !isempty(pipe.rest) || isreadable(pipe.io)
×
47
Base.iswritable(::Base64DecodePipe) = false
×
48

49
function Base.unsafe_read(pipe::Base64DecodePipe, ptr::Ptr{UInt8}, n::UInt)
×
50
    p = read_until_end(pipe, ptr, n)
×
51
    if p < ptr + n
×
52
        throw(EOFError())
×
53
    end
54
    return nothing
×
55
end
56

57
# Read and decode as much data as possible.
58
function read_until_end(pipe::Base64DecodePipe, ptr::Ptr{UInt8}, n::UInt)
1✔
59
    p = ptr
1✔
60
    p_end = ptr + n
1✔
61
    while !isempty(pipe.rest) && p < p_end
1✔
62
        unsafe_store!(p, popfirst!(pipe.rest))
×
63
        p += 1
×
64
    end
×
65

66
    buffer = pipe.buffer
1✔
67
    i = 0
1✔
68
    b1 = b2 = b3 = b4 = BASE64_CODE_IGN
1✔
69
    while true
89✔
70
        if b1 < 0x40 && b2 < 0x40 && b3 < 0x40 && b4 < 0x40 && p + 2 < p_end
89✔
71
            # fast path to decode
72
            unsafe_store!(p    , b1 << 2 | b2 >> 4)
86✔
73
            unsafe_store!(p + 1, b2 << 4 | b3 >> 2)
86✔
74
            unsafe_store!(p + 2, b3 << 6 | b4     )
86✔
75
            p += 3
86✔
76
        else
77
            i, p, ended = decode_slow(b1, b2, b3, b4, buffer, i, pipe.io, p, p_end - p, pipe.rest)
3✔
78
            if ended
3✔
79
                break
1✔
80
            end
81
        end
82
        if p < p_end
88✔
83
            if i + 4 ≤ lastindex(buffer)
88✔
84
                b1 = decode(buffer[i+1])
86✔
85
                b2 = decode(buffer[i+2])
86✔
86
                b3 = decode(buffer[i+3])
86✔
87
                b4 = decode(buffer[i+4])
86✔
88
                i += 4
86✔
89
            else
90
                consumed!(buffer, i)
2✔
91
                read_to_buffer(pipe.io, buffer)
2✔
92
                i = 0
2✔
93
                b1 = b2 = b3 = b4 = BASE64_CODE_IGN
2✔
94
            end
95
        else
96
            break
×
97
        end
98
    end
88✔
99
    consumed!(buffer, i)
1✔
100

101
    return p
1✔
102
end
103

104
function Base.read(pipe::Base64DecodePipe, ::Type{UInt8})
×
105
    if isempty(pipe.rest)
×
106
        unsafe_read(pipe, convert(Ptr{UInt8}, C_NULL), 0)
×
107
        if isempty(pipe.rest)
×
108
            throw(EOFError())
×
109
        end
110
    end
111
    return popfirst!(pipe.rest)
×
112
end
113

114
function Base.readbytes!(pipe::Base64DecodePipe, data::AbstractVector{UInt8}, nb::Integer=length(data))
1✔
115
    require_one_based_indexing(data)
1✔
116
    filled::Int = 0
1✔
117
    while filled < nb && !eof(pipe)
2✔
118
        if length(data) == filled
1✔
119
            resize!(data, min(length(data) * 2, nb))
×
120
        end
121
        p = pointer(data, filled + 1)
1✔
122
        p_end = read_until_end(pipe, p, UInt(min(length(data), nb) - filled))
1✔
123
        filled += p_end - p
1✔
124
    end
1✔
125
    resize!(data, filled)
1✔
126
    return filled
1✔
127
end
128

129
Base.eof(pipe::Base64DecodePipe) = isempty(pipe.rest) && eof(pipe.io)::Bool
2✔
130
Base.close(pipe::Base64DecodePipe) = nothing
×
131

132
# Decode data from (b1, b2, b3, b5, buffer, input) into (ptr, rest).
133
function decode_slow(b1, b2, b3, b4, buffer, i, input, ptr, n, rest)
3✔
134
    # Skip ignore code.
135
    while true
6✔
136
        if b1 == BASE64_CODE_IGN
18✔
137
            b1, b2, b3 = b2, b3, b4
12✔
138
        elseif b2 == BASE64_CODE_IGN
3✔
139
            b2, b3 = b3, b4
×
140
        elseif b3 == BASE64_CODE_IGN
3✔
141
            b3 = b4
×
142
        elseif b4 == BASE64_CODE_IGN
3✔
143
            # pass
144
        else
145
            break
3✔
146
        end
147
        if i + 1 ≤ lastindex(buffer)
12✔
148
            b4 = decode(buffer[i+=1])
4✔
149
        elseif !eof(input)
8✔
150
            b4 = decode(read(input, UInt8))
4✔
151
        else
152
            b4 = BASE64_CODE_END
4✔
153
        end
154
    end
12✔
155

156
    # Check the decoded quadruplet.
157
    k = 0
3✔
158
    if b1 < 0x40 && b2 < 0x40 && b3 < 0x40 && b4 < 0x40
3✔
159
        k = 3
2✔
160
    elseif b1 < 0x40 && b2 < 0x40 && b3 < 0x40 && (b4 == BASE64_CODE_PAD || b4 == BASE64_CODE_END)
1✔
161
        b4 = 0x00
×
162
        k = 2
×
163
    elseif b1 < 0x40 && b2 < 0x40 && (b3 == BASE64_CODE_PAD || b3 == BASE64_CODE_END) && (b4 == BASE64_CODE_PAD || b4 == BASE64_CODE_END)
1✔
164
        b3 = b4 = 0x00
×
165
        k = 1
×
166
    elseif b1 == b2 == b3 == b4 == BASE64_CODE_END
1✔
167
        b1 = b2 = b3 = b4 = 0x00
1✔
168
    else
169
        throw(ArgumentError("malformed base64 sequence"))
×
170
    end
171

172
    # Write output.
173
    p::Ptr{UInt8} = ptr
3✔
174
    p_end = ptr + n
3✔
175
    function output(b)
3✔
176
        if p < p_end
6✔
177
            unsafe_store!(p, b)
6✔
178
            p += 1
6✔
179
        else
180
            push!(rest, b)
×
181
        end
182
    end
183
    k ≥ 1 && output(b1 << 2 | b2 >> 4)
3✔
184
    k ≥ 2 && output(b2 << 4 | b3 >> 2)
3✔
185
    k ≥ 3 && output(b3 << 6 | b4     )
3✔
186

187
    return i, p, k == 0
×
188
end
189

190
"""
191
    base64decode(string)
192

193
Decode the base64-encoded `string` and returns a `Vector{UInt8}` of the decoded
194
bytes.
195

196
See also [`base64encode`](@ref).
197

198
# Examples
199
```jldoctest
200
julia> b = base64decode("SGVsbG8h")
201
6-element Vector{UInt8}:
202
 0x48
203
 0x65
204
 0x6c
205
 0x6c
206
 0x6f
207
 0x21
208

209
julia> String(b)
210
"Hello!"
211
```
212
"""
213
function base64decode(s)
1✔
214
    b = IOBuffer(s)
1✔
215
    try
1✔
216
        return read(Base64DecodePipe(b))
1✔
217
    finally
218
        close(b)
1✔
219
    end
220
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc