This commit is contained in:
cosmin.apreutesei
2013-12-20 00:16:56 +02:00
commit 9d37310f5e
14 changed files with 562 additions and 0 deletions
BIN
View File
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
Copyright-Only Dedication (based on United States law)
or Public Domain Certification
The person or persons who have associated work with this document (the
"Dedicator" or "Certifier") hereby either (a) certifies that, to the best of
his knowledge, the work of authorship identified is in the public domain of the
country from which the work is published, or (b) hereby dedicates whatever
copyright the dedicators holds in the work of authorship identified below (the
"Work") to the public domain. A certifier, moreover, dedicates any copyright
interest he may have in the associated work, and for these purposes, is
described as a "dedicator" below.
A certifier has taken reasonable steps to verify the copyright status of this
work. Certifier recognizes that his good faith efforts may not shield him from
liability if in fact the work certified is not in the public domain.
Dedicator makes this dedication for the benefit of the public at large and to
the detriment of the Dedicator's heirs and successors. Dedicator intends this
dedication to be an overt act of relinquishment in perpetuity of all present
and future rights under copyright law, whether vested or contingent, in the
Work. Dedicator understands that such relinquishment of all rights includes
the relinquishment of all rights to enforce (by lawsuit or otherwise) those
copyrights in the Work.
Dedicator recognizes that, once placed in the public domain, the Work may be
freely reproduced, distributed, transmitted, used, modified, built upon, or
otherwise exploited by anyone for any purpose, commercial or non-commercial,
and in any way, including by methods that have not yet been invented or
conceived.
+138
View File
@@ -0,0 +1,138 @@
b64: Base64 Encoding/Decoding Routines
======================================
Overview:
--------
libb64 is a library of ANSI C routines for fast encoding/decoding data into and
from a base64-encoded format. C++ wrappers are included, as well as the source
code for standalone encoding and decoding executables.
base64 consists of ASCII text, and is therefore a useful encoding for storing
binary data in a text file, such as xml, or sending binary data over text-only
email.
References:
----------
* Wikipedia article:
http://en.wikipedia.org/wiki/Base64
* base64, another implementation of a commandline en/decoder:
http://www.fourmilab.ch/webtools/base64/
Why?
---
I did this because I need an implementation of base64 encoding and decoding,
without any licensing problems. Most OS implementations are released under
either the GNU/GPL, or a BSD-variant, which is not what I require.
Also, the chance to actually use the co-routine implementation in code is rare,
and its use here is fitting. I couldn't pass up the chance.
For more information on this technique, see "Coroutines in C", by Simon Tatham,
which can be found online here:
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
So then, under which license do I release this code? On to the next section...
License:
-------
This work is released under into the Public Domain.
It basically boils down to this: I put this work in the public domain, and you
can take it and do whatever you want with it.
An example of this "license" is the Creative Commons Public Domain License, a
copy of which can be found in the LICENSE file, and also online at
http://creativecommons.org/licenses/publicdomain/
Commandline Use:
---------------
There is a new executable available, it is simply called base64.
It can encode and decode files, as instructed by the user.
To encode a file:
$ ./base64 -e filea fileb
fileb will now be the base64-encoded version of filea.
To decode a file:
$ ./base64 -d fileb filec
filec will now be identical to filea.
Programming:
-----------
Some C++ wrappers are provided as well, so you don't have to get your hands
dirty. Encoding from standard input to standard output is as simple as
#include <b64/encode.h>
#include <iostream>
int main()
{
base64::encoder E;
E.encode(std::cin, std::cout);
return 0;
}
Both standalone executables and a static library is provided in the package,
Implementation:
--------------
It is DAMN fast, if I may say so myself. The C code uses a little trick which
has been used to implement coroutines, of which one can say that this
implementation is an example.
(To see how the libb64 codebase compares with some other BASE64 implementations
available, see the BENCHMARKS file)
The trick involves the fact that a switch-statement may legally cross into
sub-blocks. A very thorough and enlightening essay on co-routines in C, using
this method, can be found in the above mentioned "Coroutines in C", by Simon
Tatham: http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
For example, an RLE decompressing routine, adapted from the article:
1 static int STATE = 0;
2 static int len, c;
3 switch (STATE)
4 {
5 while (1)
6 {
7 c = getchar();
8 if (c == EOF) return EOF;
9 if (c == 0xFF) {
10 len = getchar();
11 c = getchar();
12 while (len--)
13 {
14 STATE = 0;
15 return c;
16 case 0:
17 }
18 } else
19 STATE = 1;
20 return c;
21 case 1:
22 }
23 }
24 }
As can be seen from this example, a coroutine depends on a state variable,
which it sets directly before exiting (lines 14 and 119). The next time the
routine is entered, the switch moves control to the specific point directly
after the previous exit (lines 16 and 21).hands
(As an aside, in the mentioned article the combination of the top-level switch,
the various setting of the state, the return of a value, and the labelling of
the exit point is wrapped in #define macros, making the structure of the
routine even clearer.)
The obvious problem with any such routine is the static keyword.
Any static variables in a function spell doom for multithreaded applications.
Also, in situations where this coroutine is used by more than one other
coroutines, the consistency is disturbed.
What is needed is a structure for storing these variabled, which is passed to
the routine seperately. This obviously breaks the modularity of the function,
since now the caller has to worry about and care for the internal state of the
routine (the callee). This allows for a fast, multithreading-enabled
implementation, which may (obviously) be wrapped in a C++ object for ease of
use.
The base64 encoding and decoding functionality in this package is implemented
in exactly this way, providing both a high-speed high-maintanence C interface,
and a wrapped C++ which is low-maintanence and only slightly less performant.
+1
View File
@@ -0,0 +1 @@
libb64 1.2 from http://libb64.sourceforge.net/ (public domain)
+4
View File
@@ -0,0 +1,4 @@
gcc *.c -O3 -s -I. -shared -o ../../linux/bin/libb64.so -Wall
cd ../..
linux/bin/luajit libb64_test.lua
+5
View File
@@ -0,0 +1,5 @@
gcc *.c -O3 -s -I. -shared -o ../../bin/b64.dll -Wall
cd ../..
bin/luajit libb64_test.lua
+88
View File
@@ -0,0 +1,88 @@
/*
cdecoder.c - c source to a base64 decoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include "cdecode.h"
int base64_decode_value(char value_in)
{
static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,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,-1,-1,-1,-1,-1,-1,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};
static const char decoding_size = sizeof(decoding);
value_in -= 43;
if (value_in < 0 || value_in > decoding_size) return -1;
return decoding[(int)value_in];
}
void base64_init_decodestate(base64_decodestate* state_in)
{
state_in->step = step_a;
state_in->plainchar = 0;
}
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
{
const char* codechar = code_in;
char* plainchar = plaintext_out;
char fragment;
*plainchar = state_in->plainchar;
switch (state_in->step)
{
while (1)
{
case step_a:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_a;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar = (fragment & 0x03f) << 2;
case step_b:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_b;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x030) >> 4;
*plainchar = (fragment & 0x00f) << 4;
case step_c:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_c;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03c) >> 2;
*plainchar = (fragment & 0x003) << 6;
case step_d:
do {
if (codechar == code_in+length_in)
{
state_in->step = step_d;
state_in->plainchar = *plainchar;
return plainchar - plaintext_out;
}
fragment = (char)base64_decode_value(*codechar++);
} while (fragment < 0);
*plainchar++ |= (fragment & 0x03f);
}
}
/* control should not reach here */
return plainchar - plaintext_out;
}
+28
View File
@@ -0,0 +1,28 @@
/*
cdecode.h - c header for a base64 decoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#ifndef BASE64_CDECODE_H
#define BASE64_CDECODE_H
typedef enum
{
step_a, step_b, step_c, step_d
} base64_decodestep;
typedef struct
{
base64_decodestep step;
char plainchar;
} base64_decodestate;
void base64_init_decodestate(base64_decodestate* state_in);
int base64_decode_value(char value_in);
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
#endif /* BASE64_CDECODE_H */
+109
View File
@@ -0,0 +1,109 @@
/*
cencoder.c - c source to a base64 encoding algorithm implementation
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#include "cencode.h"
const int CHARS_PER_LINE = 72;
void base64_init_encodestate(base64_encodestate* state_in)
{
state_in->step = step_A;
state_in->result = 0;
state_in->stepcount = 0;
}
char base64_encode_value(char value_in)
{
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (value_in > 63) return '=';
return encoding[(int)value_in];
}
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
{
const char* plainchar = plaintext_in;
const char* const plaintextend = plaintext_in + length_in;
char* codechar = code_out;
char result;
char fragment;
result = state_in->result;
switch (state_in->step)
{
while (1)
{
case step_A:
if (plainchar == plaintextend)
{
state_in->result = result;
state_in->step = step_A;
return codechar - code_out;
}
fragment = *plainchar++;
result = (fragment & 0x0fc) >> 2;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x003) << 4;
case step_B:
if (plainchar == plaintextend)
{
state_in->result = result;
state_in->step = step_B;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0f0) >> 4;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x00f) << 2;
case step_C:
if (plainchar == plaintextend)
{
state_in->result = result;
state_in->step = step_C;
return codechar - code_out;
}
fragment = *plainchar++;
result |= (fragment & 0x0c0) >> 6;
*codechar++ = base64_encode_value(result);
result = (fragment & 0x03f) >> 0;
*codechar++ = base64_encode_value(result);
++(state_in->stepcount);
if (state_in->stepcount == CHARS_PER_LINE/4)
{
*codechar++ = '\n';
state_in->stepcount = 0;
}
}
}
/* control should not reach here */
return codechar - code_out;
}
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
{
char* codechar = code_out;
switch (state_in->step)
{
case step_B:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
*codechar++ = '=';
break;
case step_C:
*codechar++ = base64_encode_value(state_in->result);
*codechar++ = '=';
break;
case step_A:
break;
}
*codechar++ = '\n';
return codechar - code_out;
}
+31
View File
@@ -0,0 +1,31 @@
/*
cencode.h - c header for a base64 encoding algorithm
This is part of the libb64 project, and has been placed in the public domain.
For details, see http://sourceforge.net/projects/libb64
*/
#ifndef BASE64_CENCODE_H
#define BASE64_CENCODE_H
typedef enum
{
step_A, step_B, step_C
} base64_encodestep;
typedef struct
{
base64_encodestep step;
char result;
int stepcount;
} base64_encodestate;
void base64_init_encodestate(base64_encodestate* state_in);
char base64_encode_value(char value_in);
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
#endif /* BASE64_CENCODE_H */
+76
View File
@@ -0,0 +1,76 @@
--libb64 ffi binding
local ffi = require'ffi'
local C = ffi.load'b64'
ffi.cdef[[
typedef struct
{
int step;
char plainchar;
} base64_decodestate;
void base64_init_decodestate(base64_decodestate* state_in);
int base64_decode_value(char value_in);
int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in);
typedef struct
{
int step;
char result;
int stepcount;
} base64_encodestate;
void base64_init_encodestate(base64_encodestate* state_in);
char base64_encode_value(char value_in);
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
]]
local function decode_tobuffer(data, size, buf, sz)
size = size or #data
if size == 0 then return 0 end
assert(sz >= math.floor(size * 3 / 4), 'buffer too small')
local state_in = ffi.new'base64_decodestate'
C.base64_init_decodestate(state_in)
return C.base64_decode_block(data, size, buf, state_in)
end
local function decode(data, size)
size = size or #data
if size == 0 then return '' end
local sz = math.floor(size * 3 / 4)
local buf = ffi.new('uint8_t[?]', sz)
sz = decode_tobuffer(data, size, buf, sz)
return ffi.string(buf, sz)
end
local function encode_tobuffer(data, size, buf, sz)
size = size or #data
if size == 0 then return 0 end
assert(sz >= size * 2 + 3, 'buffer too small')
local state_in = ffi.new'base64_encodestate'
C.base64_init_encodestate(state_in)
local sz = C.base64_encode_block(data, size, buf, state_in)
sz = sz + C.base64_encode_blockend(buf + sz, state_in)
buf[sz-1] = 0 --replace \n
return sz-1
end
local function encode(data, size)
size = size or #data
if size == 0 then return '' end
local sz = size * 2 + 3
local buf = ffi.new('uint8_t[?]', sz)
sz = encode_tobuffer(data, size, buf, sz)
return ffi.string(buf, sz)
end
if not ... then require'libb64_test' end
return {
decode_tobuffer = decode_tobuffer,
decode = decode,
encode_tobuffer = encode_tobuffer,
encode = encode,
C = C,
}
+31
View File
@@ -0,0 +1,31 @@
---
project: libb64
tagline: fast base64 encoding and decoding
---
v1.0 | libb64 1.2 | LuaJIT 2
## `local b64 = require'libb64'`
FFI binding of [libb64](http://libb64.sourceforge.net/), a fast base64 encoder and decoder by Chris Venter.
b64.encode(s[, size]) -> s
b64.decode(s[, size]) -> s
b64.encode(cdata, size) -> s
b64.decode(cdata, size) -> s
Encode/decode a string or cdata to a string.
b64.encode_tobuffer(s, [size], out_buf, out_size) -> bytes_written
b64.decode_tobuffer(s, [size], out_buf, out_size) -> bytes_written
b64.encode_tobuffer(cdata, size, out_buf, out_size) -> bytes_written
b64.decode_tobuffer(cdata, size, out_buf, out_size) -> bytes_written
Encode/decode a string or cdata to a buffer.
* encoding needs a buffer of at least `size * 2 + 3` bytes
* decoding needs a buffer of at least `math.floor(size * 3 / 4)` bytes
## TODO
Stream-like interface similar to zlib's inflate/deflate.
+22
View File
@@ -0,0 +1,22 @@
local b64 = require'libb64'
local decode = b64.decode
local encode = b64.encode
assert(decode'YW55IGNhcm5hbCBwbGVhc3VyZS4=' == 'any carnal pleasure.')
assert(decode'YW55IGNhcm5hbCBwbGVhc3VyZQ==' == 'any carnal pleasure')
assert(decode'YW55IGNhcm5hbCBwbGVhc3Vy' == 'any carnal pleasur')
assert(decode'YW55IGNhcm5hbCBwbGVhc3U=' == 'any carnal pleasu')
assert(decode'YW55IGNhcm5hbCBwbGVhcw==' == 'any carnal pleas')
assert(decode'., ? !@#$%^& \n\r\n\r YW55IGNhcm5hbCBwbGVhcw== \n\r' == 'any carnal pleas')
assert(encode'any carnal pleasure.' == 'YW55IGNhcm5hbCBwbGVhc3VyZS4=')
assert(encode'any carnal pleasure' == 'YW55IGNhcm5hbCBwbGVhc3VyZQ==')
assert(encode'any carnal pleasur' == 'YW55IGNhcm5hbCBwbGVhc3Vy')
assert(encode'any carnal pleasu' == 'YW55IGNhcm5hbCBwbGVhc3U=')
assert(encode'any carnal pleas' == 'YW55IGNhcm5hbCBwbGVhcw==')
assert(decode(encode'') == '')
assert(decode(encode'x') == 'x')
assert(decode(encode'xx') == 'xx')
assert(decode'.!@#$%^&*( \n\r\t' == '')
Binary file not shown.