mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-30 03:23:19 +01:00
[svn r134] Merged the DMD 1.024 frontend.
Added std.base64.
This commit is contained in:
@@ -29,6 +29,7 @@ Declaration::Declaration(Identifier *id)
|
||||
: Dsymbol(id)
|
||||
{
|
||||
type = NULL;
|
||||
originalType = NULL;
|
||||
storage_class = STCundefined;
|
||||
protection = PROTundefined;
|
||||
linkage = LINKdefault;
|
||||
@@ -622,9 +623,13 @@ void VarDeclaration::semantic(Scope *sc)
|
||||
* declarations.
|
||||
*/
|
||||
storage_class &= ~STCauto;
|
||||
originalType = type;
|
||||
}
|
||||
else
|
||||
{ if (!originalType)
|
||||
originalType = type;
|
||||
type = type->semantic(loc, sc);
|
||||
}
|
||||
|
||||
type->checkDeprecated(loc, sc);
|
||||
linkage = sc->linkage;
|
||||
|
||||
@@ -91,6 +91,7 @@ int overloadApply(FuncDeclaration *fstart,
|
||||
struct Declaration : Dsymbol
|
||||
{
|
||||
Type *type;
|
||||
Type *originalType; // before semantic analysis
|
||||
unsigned storage_class;
|
||||
enum PROT protection;
|
||||
enum LINK linkage;
|
||||
@@ -114,6 +115,7 @@ struct Declaration : Dsymbol
|
||||
int isFinal() { return storage_class & STCfinal; }
|
||||
int isAbstract() { return storage_class & STCabstract; }
|
||||
int isConst() { return storage_class & STCconst; }
|
||||
int isInvariant() { return 0; }
|
||||
int isAuto() { return storage_class & STCauto; }
|
||||
int isScope() { return storage_class & (STCscope | STCauto); }
|
||||
int isSynchronized() { return storage_class & STCsynchronized; }
|
||||
|
||||
19
dmd/doc.c
19
dmd/doc.c
@@ -269,7 +269,6 @@ void Module::gendocfile()
|
||||
}
|
||||
|
||||
buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars());
|
||||
|
||||
if (isDocFile)
|
||||
{
|
||||
size_t commentlen = strlen((char *)comment);
|
||||
@@ -283,7 +282,6 @@ void Module::gendocfile()
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
dc->writeSections(sc, this, sc->docbuf);
|
||||
emitMemberComments(sc);
|
||||
}
|
||||
@@ -654,6 +652,10 @@ void prefix(OutBuffer *buf, Dsymbol *s)
|
||||
buf->writestring("static ");
|
||||
if (d->isConst())
|
||||
buf->writestring("const ");
|
||||
#if V2
|
||||
if (d->isInvariant())
|
||||
buf->writestring("invariant ");
|
||||
#endif
|
||||
if (d->isFinal())
|
||||
buf->writestring("final ");
|
||||
if (d->isSynchronized())
|
||||
@@ -663,7 +665,7 @@ void prefix(OutBuffer *buf, Dsymbol *s)
|
||||
|
||||
void Declaration::toDocBuffer(OutBuffer *buf)
|
||||
{
|
||||
//printf("Declaration::toDocbuffer() %s\n", toChars());
|
||||
//printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType);
|
||||
if (ident)
|
||||
{
|
||||
prefix(buf, this);
|
||||
@@ -671,7 +673,12 @@ void Declaration::toDocBuffer(OutBuffer *buf)
|
||||
if (type)
|
||||
{ HdrGenState hgs;
|
||||
hgs.ddoc = 1;
|
||||
type->toCBuffer(buf, ident, &hgs);
|
||||
if (originalType)
|
||||
{ //originalType->print();
|
||||
originalType->toCBuffer(buf, ident, &hgs);
|
||||
}
|
||||
else
|
||||
type->toCBuffer(buf, ident, &hgs);
|
||||
}
|
||||
else
|
||||
buf->writestring(ident->toChars());
|
||||
@@ -723,10 +730,11 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf)
|
||||
td->onemember == this)
|
||||
{ HdrGenState hgs;
|
||||
unsigned o = buf->offset;
|
||||
TypeFunction *tf = (TypeFunction *)type;
|
||||
|
||||
hgs.ddoc = 1;
|
||||
prefix(buf, td);
|
||||
type->next->toCBuffer(buf, NULL, &hgs);
|
||||
tf->next->toCBuffer(buf, NULL, &hgs);
|
||||
buf->writeByte(' ');
|
||||
buf->writestring(ident->toChars());
|
||||
buf->writeByte('(');
|
||||
@@ -738,7 +746,6 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf)
|
||||
tp->toCBuffer(buf, &hgs);
|
||||
}
|
||||
buf->writeByte(')');
|
||||
TypeFunction *tf = (TypeFunction *)type;
|
||||
Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs);
|
||||
buf->writestring(";\n");
|
||||
|
||||
|
||||
@@ -1270,7 +1270,7 @@ RealExp::RealExp(Loc loc, real_t value, Type *type)
|
||||
|
||||
char *RealExp::toChars()
|
||||
{
|
||||
static char buffer[sizeof(value) * 3 + 8 + 1 + 1];
|
||||
char buffer[sizeof(value) * 3 + 8 + 1 + 1];
|
||||
|
||||
#ifdef IN_GCC
|
||||
value.format(buffer, sizeof(buffer));
|
||||
@@ -1280,7 +1280,7 @@ char *RealExp::toChars()
|
||||
sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value);
|
||||
#endif
|
||||
assert(strlen(buffer) < sizeof(buffer));
|
||||
return buffer;
|
||||
return mem.strdup(buffer);
|
||||
}
|
||||
|
||||
integer_t RealExp::toInteger()
|
||||
@@ -1484,7 +1484,7 @@ ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
|
||||
|
||||
char *ComplexExp::toChars()
|
||||
{
|
||||
static char buffer[sizeof(value) * 3 + 8 + 1];
|
||||
char buffer[sizeof(value) * 3 + 8 + 1];
|
||||
|
||||
#ifdef IN_GCC
|
||||
char buf1[sizeof(value) * 3 + 8 + 1];
|
||||
@@ -1496,7 +1496,7 @@ char *ComplexExp::toChars()
|
||||
sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value));
|
||||
assert(strlen(buffer) < sizeof(buffer));
|
||||
#endif
|
||||
return buffer;
|
||||
return mem.strdup(buffer);
|
||||
}
|
||||
|
||||
integer_t ComplexExp::toInteger()
|
||||
@@ -3140,7 +3140,13 @@ Lagain:
|
||||
if (cd->isInterfaceDeclaration())
|
||||
error("cannot create instance of interface %s", cd->toChars());
|
||||
else if (cd->isAbstract())
|
||||
error("cannot create instance of abstract class %s", cd->toChars());
|
||||
{ error("cannot create instance of abstract class %s", cd->toChars());
|
||||
for (int i = 0; i < cd->vtbl.dim; i++)
|
||||
{ FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration();
|
||||
if (fd && fd->isAbstract())
|
||||
error("function %s is abstract", fd->toChars());
|
||||
}
|
||||
}
|
||||
checkDeprecated(sc, cd);
|
||||
if (cd->isNested())
|
||||
{ /* We need a 'this' pointer for the nested class.
|
||||
@@ -5528,9 +5534,9 @@ Lagain:
|
||||
TemplateDeclaration *td = dte->td;
|
||||
assert(td);
|
||||
if (!arguments)
|
||||
// Should fix deduce() so it works on NULL argument
|
||||
// Should fix deduceFunctionTemplate() so it works on NULL argument
|
||||
arguments = new Expressions();
|
||||
f = td->deduce(sc, loc, NULL, arguments);
|
||||
f = td->deduceFunctionTemplate(sc, loc, NULL, arguments);
|
||||
if (!f)
|
||||
{ type = Type::terror;
|
||||
return this;
|
||||
@@ -5705,7 +5711,7 @@ Lagain:
|
||||
else if (e1->op == TOKtemplate)
|
||||
{
|
||||
TemplateExp *te = (TemplateExp *)e1;
|
||||
f = te->td->deduce(sc, loc, NULL, arguments);
|
||||
f = te->td->deduceFunctionTemplate(sc, loc, NULL, arguments);
|
||||
if (!f)
|
||||
{ type = Type::terror;
|
||||
return this;
|
||||
|
||||
@@ -145,6 +145,9 @@ void FuncDeclaration::semantic(Scope *sc)
|
||||
|
||||
if (isAbstract() && !isVirtual())
|
||||
error("non-virtual functions cannot be abstract");
|
||||
|
||||
if (isAbstract() && isFinal())
|
||||
error("cannot be both final and abstract");
|
||||
#if 0
|
||||
if (isAbstract() && fbody)
|
||||
error("abstract functions cannot have bodies");
|
||||
|
||||
@@ -71,7 +71,7 @@ Global::Global()
|
||||
copyright = "Copyright (c) 1999-2007 by Digital Mars and Tomas Lindquist Olsen";
|
||||
written = "written by Walter Bright and Tomas Lindquist Olsen";
|
||||
llvmdc_version = "0.1";
|
||||
version = "v1.023";
|
||||
version = "v1.024";
|
||||
global.structalign = 8;
|
||||
|
||||
memset(¶ms, 0, sizeof(Param));
|
||||
|
||||
@@ -87,6 +87,7 @@ Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen
|
||||
vmoduleinfo = NULL;
|
||||
massert = NULL;
|
||||
marray = NULL;
|
||||
sictor = NULL;
|
||||
sctor = NULL;
|
||||
sdtor = NULL;
|
||||
stest = NULL;
|
||||
|
||||
@@ -147,6 +147,7 @@ struct Module : Package
|
||||
Symbol *cov; // private uint[] __coverage;
|
||||
unsigned *covb; // bit array of valid code line numbers
|
||||
|
||||
Symbol *sictor; // module order independent constructor
|
||||
Symbol *sctor; // module constructor
|
||||
Symbol *sdtor; // module destructor
|
||||
Symbol *stest; // module unit test
|
||||
|
||||
60
dmd/mtype.c
60
dmd/mtype.c
@@ -2742,38 +2742,50 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
|
||||
}
|
||||
//printf("TypeFunction::semantic() this = %p\n", this);
|
||||
|
||||
linkage = sc->linkage;
|
||||
if (!next)
|
||||
TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction));
|
||||
memcpy(tf, this, sizeof(TypeFunction));
|
||||
if (parameters)
|
||||
{ tf->parameters = (Arguments *)parameters->copy();
|
||||
for (size_t i = 0; i < parameters->dim; i++)
|
||||
{ Argument *arg = (Argument *)parameters->data[i];
|
||||
Argument *cpy = (Argument *)mem.malloc(sizeof(Argument));
|
||||
memcpy(cpy, arg, sizeof(Argument));
|
||||
tf->parameters->data[i] = (void *)cpy;
|
||||
}
|
||||
}
|
||||
|
||||
tf->linkage = sc->linkage;
|
||||
if (!tf->next)
|
||||
{
|
||||
assert(global.errors);
|
||||
next = tvoid;
|
||||
tf->next = tvoid;
|
||||
}
|
||||
next = next->semantic(loc,sc);
|
||||
if (next->toBasetype()->ty == Tsarray)
|
||||
{ error(loc, "functions cannot return static array %s", next->toChars());
|
||||
next = Type::terror;
|
||||
tf->next = tf->next->semantic(loc,sc);
|
||||
if (tf->next->toBasetype()->ty == Tsarray)
|
||||
{ error(loc, "functions cannot return static array %s", tf->next->toChars());
|
||||
tf->next = Type::terror;
|
||||
}
|
||||
if (next->toBasetype()->ty == Tfunction)
|
||||
if (tf->next->toBasetype()->ty == Tfunction)
|
||||
{ error(loc, "functions cannot return a function");
|
||||
next = Type::terror;
|
||||
tf->next = Type::terror;
|
||||
}
|
||||
if (next->toBasetype()->ty == Ttuple)
|
||||
if (tf->next->toBasetype()->ty == Ttuple)
|
||||
{ error(loc, "functions cannot return a tuple");
|
||||
next = Type::terror;
|
||||
tf->next = Type::terror;
|
||||
}
|
||||
if (next->isauto() && !(sc->flags & SCOPEctor))
|
||||
error(loc, "functions cannot return auto %s", next->toChars());
|
||||
if (tf->next->isauto() && !(sc->flags & SCOPEctor))
|
||||
error(loc, "functions cannot return auto %s", tf->next->toChars());
|
||||
|
||||
if (parameters)
|
||||
{ size_t dim = Argument::dim(parameters);
|
||||
if (tf->parameters)
|
||||
{ size_t dim = Argument::dim(tf->parameters);
|
||||
|
||||
for (size_t i = 0; i < dim; i++)
|
||||
{ Argument *arg = Argument::getNth(parameters, i);
|
||||
{ Argument *arg = Argument::getNth(tf->parameters, i);
|
||||
Type *t;
|
||||
|
||||
inuse++;
|
||||
tf->inuse++;
|
||||
arg->type = arg->type->semantic(loc,sc);
|
||||
if (inuse == 1) inuse--;
|
||||
if (tf->inuse == 1) tf->inuse--;
|
||||
t = arg->type->toBasetype();
|
||||
|
||||
if (arg->storageClass & (STCout | STCref | STClazy))
|
||||
@@ -2795,27 +2807,27 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
|
||||
* change.
|
||||
*/
|
||||
if (t->ty == Ttuple)
|
||||
{ dim = Argument::dim(parameters);
|
||||
{ dim = Argument::dim(tf->parameters);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
deco = merge()->deco;
|
||||
tf->deco = tf->merge()->deco;
|
||||
|
||||
if (inuse)
|
||||
if (tf->inuse)
|
||||
{ error(loc, "recursive type");
|
||||
inuse = 0;
|
||||
tf->inuse = 0;
|
||||
return terror;
|
||||
}
|
||||
|
||||
if (varargs == 1 && linkage != LINKd && Argument::dim(parameters) == 0)
|
||||
if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0)
|
||||
error(loc, "variadic functions with non-D linkage must have at least one parameter");
|
||||
|
||||
/* Don't return merge(), because arg identifiers and default args
|
||||
* can be different
|
||||
* even though the types match
|
||||
*/
|
||||
return this;
|
||||
return tf;
|
||||
}
|
||||
|
||||
/********************************
|
||||
|
||||
@@ -729,7 +729,7 @@ static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc lo
|
||||
FuncDeclaration *fd;
|
||||
|
||||
assert(td);
|
||||
fd = td->deduce(sc, loc, targsi, arguments);
|
||||
fd = td->deduceFunctionTemplate(sc, loc, targsi, arguments);
|
||||
if (!fd)
|
||||
return;
|
||||
m->anyf = fd;
|
||||
|
||||
@@ -647,7 +647,7 @@ int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2)
|
||||
* dedargs Expression/Type deduced template arguments
|
||||
*/
|
||||
|
||||
MATCH TemplateDeclaration::deduceMatch(Objects *targsi, Expressions *fargs,
|
||||
MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs,
|
||||
Objects *dedargs)
|
||||
{
|
||||
size_t i;
|
||||
@@ -662,7 +662,7 @@ MATCH TemplateDeclaration::deduceMatch(Objects *targsi, Expressions *fargs,
|
||||
Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
|
||||
|
||||
#if 0
|
||||
printf("\nTemplateDeclaration::deduceMatch() %s\n", toChars());
|
||||
printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars());
|
||||
for (i = 0; i < fargs->dim; i++)
|
||||
{ Expression *e = (Expression *)fargs->data[i];
|
||||
printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars());
|
||||
@@ -985,7 +985,7 @@ int TemplateDeclaration::isOverloadable()
|
||||
* fargs arguments to function
|
||||
*/
|
||||
|
||||
FuncDeclaration *TemplateDeclaration::deduce(Scope *sc, Loc loc,
|
||||
FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc,
|
||||
Objects *targsi, Expressions *fargs)
|
||||
{
|
||||
MATCH m_best = MATCHnomatch;
|
||||
@@ -996,7 +996,7 @@ FuncDeclaration *TemplateDeclaration::deduce(Scope *sc, Loc loc,
|
||||
FuncDeclaration *fd;
|
||||
|
||||
#if 0
|
||||
printf("TemplateDeclaration::deduce() %s\n", toChars());
|
||||
printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars());
|
||||
printf(" targsi:\n");
|
||||
if (targsi)
|
||||
{ for (int i = 0; i < targsi->dim; i++)
|
||||
@@ -1028,8 +1028,8 @@ FuncDeclaration *TemplateDeclaration::deduce(Scope *sc, Loc loc,
|
||||
MATCH m;
|
||||
Objects dedargs;
|
||||
|
||||
m = td->deduceMatch(targsi, fargs, &dedargs);
|
||||
//printf("deduceMatch = %d\n", m);
|
||||
m = td->deduceFunctionTemplateMatch(targsi, fargs, &dedargs);
|
||||
//printf("deduceFunctionTemplateMatch = %d\n", m);
|
||||
if (!m) // if no match
|
||||
continue;
|
||||
|
||||
|
||||
@@ -71,8 +71,8 @@ struct TemplateDeclaration : ScopeDsymbol
|
||||
MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag);
|
||||
int leastAsSpecialized(TemplateDeclaration *td2);
|
||||
|
||||
MATCH deduceMatch(Objects *targsi, Expressions *fargs, Objects *dedargs);
|
||||
FuncDeclaration *deduce(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs);
|
||||
MATCH deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, Objects *dedargs);
|
||||
FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expressions *fargs);
|
||||
void declareParameter(Scope *sc, TemplateParameter *tp, Object *o);
|
||||
|
||||
TemplateDeclaration *isTemplateDeclaration() { return this; }
|
||||
|
||||
@@ -2,16 +2,18 @@ module phobos;
|
||||
|
||||
import
|
||||
std.array,
|
||||
std.base64,
|
||||
std.ctype,
|
||||
std.format,
|
||||
std.intrinsic,
|
||||
std.math,
|
||||
std.moduleinit,
|
||||
std.outofmemory,
|
||||
std.stdarg,
|
||||
std.stdint,
|
||||
std.stdio,
|
||||
std.stdarg,
|
||||
std.string,
|
||||
std.traits,
|
||||
std.uni,
|
||||
std.utf,
|
||||
|
||||
|
||||
293
lphobos/std/base64.d
Normal file
293
lphobos/std/base64.d
Normal file
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* Encodes/decodes MIME base64 data.
|
||||
*
|
||||
* Macros:
|
||||
* WIKI=Phobos/StdBase64
|
||||
* References:
|
||||
* <a href="http://en.wikipedia.org/wiki/Base64">Wikipedia Base64</a>$(BR)
|
||||
* <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>$(BR)
|
||||
*/
|
||||
|
||||
|
||||
/* base64.d
|
||||
* Modified from C. Miller's version, his copyright is below.
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2004 Christopher E. Miller
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
module std.base64;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
class Base64Exception: Exception
|
||||
{
|
||||
this(char[] msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
class Base64CharException: Base64Exception
|
||||
{
|
||||
this(char[] msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char[] array = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of bytes needed to encode a string of length slen.
|
||||
*/
|
||||
|
||||
uint encodeLength(uint slen)
|
||||
{
|
||||
uint result;
|
||||
result = slen / 3;
|
||||
if(slen % 3)
|
||||
result++;
|
||||
return result * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes str[] and places the result in buf[].
|
||||
* Params:
|
||||
* str = string to encode
|
||||
* buf = destination buffer, must be large enough for the result.
|
||||
* Returns:
|
||||
* slice into buf[] representing encoded result
|
||||
*/
|
||||
|
||||
char[] encode(char[] str, char[] buf)
|
||||
in
|
||||
{
|
||||
assert(buf.length >= encodeLength(str.length));
|
||||
}
|
||||
body
|
||||
{
|
||||
if(!str.length)
|
||||
return buf[0 .. 0];
|
||||
|
||||
uint stri;
|
||||
uint strmax = str.length / 3;
|
||||
uint strleft = str.length % 3;
|
||||
uint x;
|
||||
char* sp, bp;
|
||||
|
||||
bp = &buf[0];
|
||||
sp = &str[0];
|
||||
for(stri = 0; stri != strmax; stri++)
|
||||
{
|
||||
x = (sp[0] << 16) | (sp[1] << 8) | (sp[2]);
|
||||
sp+= 3;
|
||||
*bp++ = array[(x & 0b11111100_00000000_00000000) >> 18];
|
||||
*bp++ = array[(x & 0b00000011_11110000_00000000) >> 12];
|
||||
*bp++ = array[(x & 0b00000000_00001111_11000000) >> 6];
|
||||
*bp++ = array[(x & 0b00000000_00000000_00111111)];
|
||||
}
|
||||
|
||||
switch(strleft)
|
||||
{
|
||||
case 2:
|
||||
x = (sp[0] << 16) | (sp[1] << 8);
|
||||
sp += 2;
|
||||
*bp++ = array[(x & 0b11111100_00000000_00000000) >> 18];
|
||||
*bp++ = array[(x & 0b00000011_11110000_00000000) >> 12];
|
||||
*bp++ = array[(x & 0b00000000_00001111_11000000) >> 6];
|
||||
*bp++ = '=';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
x = *sp++ << 16;
|
||||
*bp++ = array[(x & 0b11111100_00000000_00000000) >> 18];
|
||||
*bp++ = array[(x & 0b00000011_11110000_00000000) >> 12];
|
||||
*bp++ = '=';
|
||||
*bp++ = '=';
|
||||
break;
|
||||
|
||||
case 0:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return buf[0 .. (bp - &buf[0])];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encodes str[] and returns the result.
|
||||
*/
|
||||
|
||||
char[] encode(char[] str)
|
||||
{
|
||||
return encode(str, new char[encodeLength(str.length)]);
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(encode("f") == "Zg==");
|
||||
assert(encode("fo") == "Zm8=");
|
||||
assert(encode("foo") == "Zm9v");
|
||||
assert(encode("foos") == "Zm9vcw==");
|
||||
assert(encode("all your base64 are belong to foo") == "YWxsIHlvdXIgYmFzZTY0IGFyZSBiZWxvbmcgdG8gZm9v");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of bytes needed to decode an encoded string of this
|
||||
* length.
|
||||
*/
|
||||
uint decodeLength(uint elen)
|
||||
{
|
||||
return elen / 4 * 3;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes str[] and places the result in buf[].
|
||||
* Params:
|
||||
* str = string to encode
|
||||
* buf = destination buffer, must be large enough for the result.
|
||||
* Returns:
|
||||
* slice into buf[] representing encoded result
|
||||
* Errors:
|
||||
* Throws Base64Exception on invalid base64 encoding in estr[].
|
||||
* Throws Base64CharException on invalid base64 character in estr[].
|
||||
*/
|
||||
char[] decode(char[] estr, char[] buf)
|
||||
in
|
||||
{
|
||||
assert(buf.length + 2 >= decodeLength(estr.length)); //account for '=' padding
|
||||
}
|
||||
body
|
||||
{
|
||||
void badc(char ch)
|
||||
{
|
||||
throw new Base64CharException("Invalid base64 character '" ~ (&ch)[0 .. 1] ~ "'");
|
||||
}
|
||||
|
||||
|
||||
uint arrayIndex(char ch)
|
||||
out(result)
|
||||
{
|
||||
assert(ch == array[result]);
|
||||
}
|
||||
body
|
||||
{
|
||||
if(ch >= 'A' && ch <= 'Z')
|
||||
return ch - 'A';
|
||||
if(ch >= 'a' && ch <= 'z')
|
||||
return 'Z' - 'A' + 1 + ch - 'a';
|
||||
if(ch >= '0' && ch <= '9')
|
||||
return 'Z' - 'A' + 1 + 'z' - 'a' + 1 + ch - '0';
|
||||
if(ch == '+')
|
||||
return 'Z' - 'A' + 1 + 'z' - 'a' + 1 + '9' - '0' + 1;
|
||||
if(ch == '/')
|
||||
return 'Z' - 'A' + 1 + 'z' - 'a' + 1 + '9' - '0' + 1 + 1;
|
||||
badc(ch);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
if(!estr.length)
|
||||
return buf[0 .. 0];
|
||||
|
||||
if(estr.length % 4)
|
||||
throw new Base64Exception("Invalid encoded base64 string");
|
||||
|
||||
uint estri;
|
||||
uint estrmax = estr.length / 4;
|
||||
uint x;
|
||||
char* sp, bp;
|
||||
char ch;
|
||||
|
||||
sp = &estr[0];
|
||||
bp = &buf[0];
|
||||
for(estri = 0; estri != estrmax; estri++)
|
||||
{
|
||||
x = arrayIndex(sp[0]) << 18 | arrayIndex(sp[1]) << 12;
|
||||
sp += 2;
|
||||
|
||||
ch = *sp++;
|
||||
if(ch == '=')
|
||||
{
|
||||
if(*sp++ != '=')
|
||||
badc('=');
|
||||
*bp++ = cast(char) (x >> 16);
|
||||
break;
|
||||
}
|
||||
x |= arrayIndex(ch) << 6;
|
||||
|
||||
ch = *sp++;
|
||||
if(ch == '=')
|
||||
{
|
||||
*bp++ = cast(char) (x >> 16);
|
||||
*bp++ = cast(char) ((x >> 8) & 0xFF);
|
||||
break;
|
||||
}
|
||||
x |= arrayIndex(ch);
|
||||
|
||||
*bp++ = cast(char) (x >> 16);
|
||||
*bp++ = cast(char) ((x >> 8) & 0xFF);
|
||||
*bp++ = cast(char) (x & 0xFF);
|
||||
}
|
||||
|
||||
return buf[0 .. (bp - &buf[0])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes estr[] and returns the result.
|
||||
* Errors:
|
||||
* Throws Base64Exception on invalid base64 encoding in estr[].
|
||||
* Throws Base64CharException on invalid base64 character in estr[].
|
||||
*/
|
||||
|
||||
char[] decode(char[] estr)
|
||||
{
|
||||
return decode(estr, new char[decodeLength(estr.length)]);
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
assert(decode(encode("f")) == "f");
|
||||
assert(decode(encode("fo")) == "fo");
|
||||
assert(decode(encode("foo")) == "foo");
|
||||
assert(decode(encode("foos")) == "foos");
|
||||
assert(decode(encode("all your base64 are belong to foo")) == "all your base64 are belong to foo");
|
||||
|
||||
assert(decode(encode("testing some more")) == "testing some more");
|
||||
assert(decode(encode("asdf jkl;")) == "asdf jkl;");
|
||||
assert(decode(encode("base64 stuff")) == "base64 stuff");
|
||||
assert(decode(encode("\1\2\3\4\5\6\7foo\7\6\5\4\3\2\1!")) == "\1\2\3\4\5\6\7foo\7\6\5\4\3\2\1!");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user