/usr/share/julia/base/base64.jl is in julia-common 0.4.7-6.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | # This file is a part of Julia. License is MIT: http://julialang.org/license
module Base64
import Base: read, write, close, eof, empty!
export Base64EncodePipe, Base64DecodePipe, base64encode, base64decode
# Base64EncodePipe is a pipe-like IO object, which converts into base64 data sent
# to a stream. (You must close the pipe to complete the encode, separate from
# closing the target stream). We also have a function base64encode(f,
# args...) which works like sprint except that it produces
# base64-encoded data, along with base64encode(args...) which is equivalent
# to base64encode(write, args...), to return base64 strings.
# A Base64DecodePipe object can be used to decode base64-encoded data read from a stream
# , while function base64decode is useful for decoding strings
#############################################################################
type Base64EncodePipe <: IO
io::IO
# writing works in groups of 3, so we need to cache last two bytes written
b0::UInt8
b1::UInt8
nb::UInt8 # number of bytes in cache: 0, 1, or 2
function Base64EncodePipe(io::IO)
b = new(io,0,0,0)
finalizer(b, close)
return b
end
end
#############################################################################
# Based on code by Stefan Karpinski from https://github.com/hackerschool/WebSockets.jl (distributed under the same MIT license as Julia)
const b64chars = ['A':'Z';'a':'z';'0':'9';'+';'/']
const base64_pad = UInt8('=')
function b64(x::UInt8, y::UInt8, z::UInt8)
n = Int(x)<<16 | Int(y)<<8 | Int(z)
b64chars[(n >> 18) + 1],
b64chars[(n >> 12) & 0b111111 + 1],
b64chars[(n >> 6) & 0b111111 + 1],
b64chars[(n ) & 0b111111 + 1]
end
function b64(x::UInt8, y::UInt8)
a, b, c = b64(x, y, 0x0)
a, b, c, base64_pad
end
function b64(x::UInt8)
a, b = b64(x, 0x0, 0x0)
a, b, base64_pad, base64_pad
end
const sentinel = typemax(UInt8)
const revb64chars = fill(sentinel, 256)
# Fill revb64chars
for (val, ch) in enumerate(b64chars)
revb64chars[UInt8(ch)] = UInt8(val - 1)
end
# Decode a block of at least 2 and at most 4 bytes, received in encvec
# Returns the first decoded byte and stores up to two more in cache
function b64decode!(encvec::Vector{UInt8}, cache::Vector{UInt8})
if length(encvec) < 2
throw(ArgumentError("incorrect base64 format, block must be at least 2 and at most 4 bytes"))
end
@inbounds u = revb64chars[encvec[1]]
@inbounds v = revb64chars[encvec[2]]
empty!(cache)
res = (u << 2) | (v >> 4)
if length(encvec) > 2
@inbounds w = revb64chars[encvec[3]]
push!(cache, (v << 4) | (w >> 2))
end
if length(encvec) > 3
@inbounds z = revb64chars[encvec[4]]
push!(cache, (w << 6) | z)
end
res
end
#############################################################################
function write(b::Base64EncodePipe, x::AbstractVector{UInt8})
n = length(x)
s = 1 # starting index
# finish any cached data to write:
if b.nb == 1
if n >= 2
write(b.io, b64(b.b0, x[1], x[2])...)
s = 3
elseif n == 1
b.b1 = x[1]
b.nb = 2
return
else
return
end
elseif b.nb == 2
if n >= 1
write(b.io, b64(b.b0, b.b1, x[1])...)
s = 2
else
return
end
end
# write all groups of three bytes:
while s + 2 <= n
write(b.io, b64(x[s], x[s+1], x[s+2])...)
s += 3
end
# cache any leftover bytes:
if s + 1 == n
b.b0 = x[s]
b.b1 = x[s+1]
b.nb = 2
elseif s == n
b.b0 = x[s]
b.nb = 1
else
b.nb = 0
end
n
end
function write(b::Base64EncodePipe, x::UInt8)
if b.nb == 0
b.b0 = x
b.nb = 1
elseif b.nb == 1
b.b1 = x
b.nb = 2
else
write(b.io, b64(b.b0,b.b1,x)...)
b.nb = 0
end
1
end
function close(b::Base64EncodePipe)
if b.nb > 0
# write leftover bytes + padding
if b.nb == 1
write(b.io, b64(b.b0)...)
else # b.nb == 2
write(b.io, b64(b.b0, b.b1)...)
end
b.nb = 0
end
end
# like sprint, but returns base64 string
function base64encode(f::Function, args...)
s = IOBuffer()
b = Base64EncodePipe(s)
f(b, args...)
close(b)
takebuf_string(s)
end
base64encode(x...) = base64encode(write, x...)
#############################################################################
type Base64DecodePipe <: IO
io::IO
# reading works in blocks of 4 characters that are decoded into 3 bytes and 2 of them cached
cache::Vector{UInt8}
encvec::Vector{UInt8}
function Base64DecodePipe(io::IO)
b = new(io,[],[])
finalizer(b, close)
return b
end
end
function read(b::Base64DecodePipe, t::Type{UInt8})
if length(b.cache) > 0
return shift!(b.cache)
else
empty!(b.encvec)
while !eof(b.io) && length(b.encvec) < 4
c::UInt8 = read(b.io, t)
@inbounds if revb64chars[c] != sentinel
push!(b.encvec, c)
end
end
return b64decode!(b.encvec,b.cache)
end
end
eof(b::Base64DecodePipe) = length(b.cache) == 0 && eof(b.io)
close(b::Base64DecodePipe) = nothing
# Decodes a base64-encoded string
function base64decode(s)
b = IOBuffer(s)
try
return readbytes(Base64DecodePipe(b))
finally
close(b)
end
end
end # module
|