Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
287
julia-0.6.2/share/julia/base/base64.jl
Normal file
287
julia-0.6.2/share/julia/base/base64.jl
Normal file
@@ -0,0 +1,287 @@
|
||||
# This file is a part of Julia. License is MIT: https://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
|
||||
#############################################################################
|
||||
|
||||
"""
|
||||
Base64EncodePipe(ostream)
|
||||
|
||||
Returns a new write-only I/O stream, which converts any bytes written to it into
|
||||
base64-encoded ASCII bytes written to `ostream`.
|
||||
Calling [`close`](@ref) on the `Base64EncodePipe` stream
|
||||
is necessary to complete the encoding (but does not close `ostream`).
|
||||
|
||||
```jldoctest
|
||||
julia> io = IOBuffer();
|
||||
|
||||
julia> iob64_encode = Base64EncodePipe(io);
|
||||
|
||||
julia> write(iob64_encode, "Hello!")
|
||||
6
|
||||
|
||||
julia> close(iob64_encode);
|
||||
|
||||
julia> str = String(take!(io))
|
||||
"SGVsbG8h"
|
||||
|
||||
julia> String(base64decode(str))
|
||||
"Hello!"
|
||||
```
|
||||
"""
|
||||
mutable struct 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 unsafe_write(b::Base64EncodePipe, x::Ptr{UInt8}, n::UInt)
|
||||
s = 1 # starting index
|
||||
# finish any cached data to write:
|
||||
if b.nb == 1
|
||||
if n >= 2
|
||||
write(b.io, b64(b.b0, unsafe_load(x, 1), unsafe_load(x, 2))...)
|
||||
s = 3
|
||||
elseif n == 1
|
||||
b.b1 = unsafe_load(x, 1)
|
||||
b.nb = 2
|
||||
return
|
||||
else
|
||||
return
|
||||
end
|
||||
elseif b.nb == 2
|
||||
if n >= 1
|
||||
write(b.io, b64(b.b0, b.b1, unsafe_load(x, 1))...)
|
||||
s = 2
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
# write all groups of three bytes:
|
||||
while s + 2 <= n
|
||||
write(b.io, b64(unsafe_load(x, s), unsafe_load(x, s + 1), unsafe_load(x, s + 2))...)
|
||||
s += 3
|
||||
end
|
||||
# cache any leftover bytes:
|
||||
if s + 1 == n
|
||||
b.b0 = unsafe_load(x, s)
|
||||
b.b1 = unsafe_load(x, s + 1)
|
||||
b.nb = 2
|
||||
elseif s == n
|
||||
b.b0 = unsafe_load(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
|
||||
nothing
|
||||
end
|
||||
|
||||
# like sprint, but returns base64 string
|
||||
"""
|
||||
base64encode(writefunc, args...)
|
||||
base64encode(args...)
|
||||
|
||||
Given a [`write`](@ref)-like function `writefunc`, which takes an I/O stream as its first argument,
|
||||
`base64encode(writefunc, args...)` calls `writefunc` to write `args...` to a base64-encoded
|
||||
string, and returns the string. `base64encode(args...)` is equivalent to `base64encode(write, args...)`:
|
||||
it converts its arguments into bytes using the standard [`write`](@ref) functions and returns the
|
||||
base64-encoded string.
|
||||
|
||||
See also [`base64decode`](@ref).
|
||||
"""
|
||||
function base64encode(f::Function, args...)
|
||||
s = IOBuffer()
|
||||
b = Base64EncodePipe(s)
|
||||
f(b, args...)
|
||||
close(b)
|
||||
String(take!(s))
|
||||
end
|
||||
base64encode(x...) = base64encode(write, x...)
|
||||
|
||||
#############################################################################
|
||||
|
||||
"""
|
||||
Base64DecodePipe(istream)
|
||||
|
||||
Returns a new read-only I/O stream, which decodes base64-encoded data read from `istream`.
|
||||
|
||||
```jldoctest
|
||||
julia> io = IOBuffer();
|
||||
|
||||
julia> iob64_decode = Base64DecodePipe(io);
|
||||
|
||||
julia> write(io, "SGVsbG8h")
|
||||
8
|
||||
|
||||
julia> seekstart(io);
|
||||
|
||||
julia> String(read(iob64_decode))
|
||||
"Hello!"
|
||||
```
|
||||
"""
|
||||
mutable struct 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 !isempty(b.cache)
|
||||
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) = isempty(b.cache) && eof(b.io)
|
||||
close(b::Base64DecodePipe) = nothing
|
||||
|
||||
# Decodes a base64-encoded string
|
||||
|
||||
"""
|
||||
base64decode(string)
|
||||
|
||||
Decodes the base64-encoded `string` and returns a `Vector{UInt8}` of the decoded bytes.
|
||||
|
||||
See also [`base64encode`](@ref)
|
||||
|
||||
```jldoctest
|
||||
julia> b = base64decode("SGVsbG8h")
|
||||
6-element Array{UInt8,1}:
|
||||
0x48
|
||||
0x65
|
||||
0x6c
|
||||
0x6c
|
||||
0x6f
|
||||
0x21
|
||||
|
||||
julia> String(b)
|
||||
"Hello!"
|
||||
```
|
||||
"""
|
||||
function base64decode(s)
|
||||
b = IOBuffer(s)
|
||||
try
|
||||
return read(Base64DecodePipe(b))
|
||||
finally
|
||||
close(b)
|
||||
end
|
||||
end
|
||||
|
||||
end # module
|
||||
Reference in New Issue
Block a user