diff options
Diffstat (limited to 'lib/pure/base64.nim')
-rw-r--r-- | lib/pure/base64.nim | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim new file mode 100644 index 000000000..a4673b5f7 --- /dev/null +++ b/lib/pure/base64.nim @@ -0,0 +1,129 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a base64 encoder and decoder. + +const + cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +proc encode*(s: string, lineLen = 75, newLine="\13\10"): string = + ## encodes `s` into base64 representation. After `lineLen` characters, a + ## `newline` is added. + var total = ((len(s) + 2) div 3) * 4 + var numLines = (total + (lineLen - 1)) div lineLen + if numLines > 0: inc(total, (numLines-1) * newLine.len) + + result = newString(total) + var i = 0 + var r = 0 + var currLine = 0 + while i < s.len - 2: + var a = ord(s[i]) + var b = ord(s[i+1]) + var c = ord(s[i+2]) + result[r] = cb64[a shr 2] + result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] + result[r+3] = cb64[c and 0x3F] + inc(r, 4) + inc(i, 3) + inc(currLine, 4) + if currLine >= lineLen and i != s.len-2: + for x in items(newLine): + result[r] = x + inc(r) + currLine = 0 + + if i < s.len-1: + var a = ord(s[i]) + var b = ord(s[i+1]) + result[r] = cb64[a shr 2] + result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result[r+2] = cb64[((b and 0x0F) shl 2)] + result[r+3] = '=' + assert(r+4 == result.len) + elif i < s.len: + var a = ord(s[i]) + result[r] = cb64[a shr 2] + result[r+1] = cb64[(a and 3) shl 4] + result[r+2] = '=' + result[r+3] = '=' + assert(r+4 == result.len) + else: + assert(r == result.len) + +proc decodeByte(b: char): int {.inline.} = + case b + of '+': result = ord('>') + of '0'..'9': result = ord(b) + 4 + of 'A'..'Z': result = ord(b) - ord('A') + of 'a'..'z': result = ord(b) - 71 + else: result = 63 + +proc decode*(s: string): string = + ## decodes a string in base64 representation back into its original form. + ## Whitespace is skipped. + const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'} + var total = ((len(s) + 3) div 4) * 3 + # total is an upper bound, as we will skip arbitrary whitespace: + result = newString(total) + + var i = 0 + var r = 0 + while true: + while s[i] in Whitespace: inc(i) + if i < s.len-3: + var a = s[i].decodeByte + var b = s[i+1].decodeByte + var c = s[i+2].decodeByte + var d = s[i+3].decodeByte + + result[r] = chr((a shl 2) or ((b shr 4) and 0x03)) + result[r+1] = chr((b shl 4) or ((c shr 2) and 0x0F)) + result[r+2] = chr((c shl 6) or (d and 0x3F)) + inc(r, 3) + inc(i, 4) + else: break + if i < s.len-2 and s[i+2] == '=': + var a = s[i].decodeByte + var b = s[i+1].decodeByte + result[r] = chr(a shl 2 or ((b shr 4) and 3)) + inc(r) + elif i < s.len-3 and s[i+3] == '=': + var a = s[i].decodeByte + var b = s[i+1].decodeByte + var c = s[i+2].decodeByte + result[r] = chr((a shl 2) or ((b shr 4) and 3)) + result[r+1] = chr((b shl 4) or ((c shr 2) and 0xF)) + inc(r, 2) + setLen(result, r) + +when isMainModule: + assert encode("leasure.") == "bGVhc3VyZS4=" + assert encode("easure.") == "ZWFzdXJlLg==" + assert encode("asure.") == "YXN1cmUu" + assert encode("sure.") == "c3VyZS4=" + + const longText = """Man is distinguished, not only by his reason, but by this + singular passion from other animals, which is a lust of the mind, + that by a perseverance of delight in the continued and indefatigable + generation of knowledge, exceeds the short vehemence of any carnal + pleasure.""" + const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", + "asure.", longText] + for t in items(tests): + if decode(encode(t)) != t: + echo "##", t, "##" + + echo encode("Man is distinguished, not only by his reason, but by this" & + " singular passion from other animals, which is a lust of the mind, " & + "that by a perseverance of delight in the continued and indefatigable" & + " generation of knowledge, exceeds the short vehemence of any carnal" & + " pleasure.") + |