Digest-MD6
view release on metacpan or search on metacpan
bits -= 6;
if ( ++phase == 4 ) {
phase = 0;
p += 3;
}
*op++ = b64[b];
}
*op = '\0';
return buf;
}
/* Formats */
#define F_BIN 0
#define F_HEX 1
#define F_B64 2
#define HASH_MAX_BITS 512
#define HASH_MAX_BYTES ( HASH_MAX_BITS / 8 )
static SV *
make_mortal_sv( pTHX_ const unsigned char *src, int bits, int type ) {
STRLEN len;
char result[HASH_MAX_BYTES * 2 + 1];
char *ret;
switch ( type ) {
case F_BIN:
len = ( bits + 7 ) / 8;
ret = ( char * ) src;
break;
case F_HEX:
ret = enc_hex( result, src, bits );
len = strlen( ret );
break;
case F_B64:
ret = enc_base64( result, src, bits );
len = strlen( ret );
break;
default:
croak( "Bad conversion type (%d)", type );
break;
}
return sv_2mortal( newSVpv( ret, len ) );
}
/********************************************************************/
/* *INDENT-OFF* */
typedef PerlIO* InputStream;
MODULE = Digest::MD6 PACKAGE = Digest::MD6
PROTOTYPES: DISABLE
void
new(xclass, ...)
SV* xclass
PREINIT:
md6_state* context;
PPCODE:
int digest_len = (int) SvIV(get_sv("Digest::MD6::HASH_LENGTH", FALSE));
if (!SvROK(xclass)) {
STRLEN my_na;
char *sclass = SvPV(xclass, my_na);
New(55, context, 1, md6_state);
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), sclass, (void*)context);
SvREADONLY_on(SvRV(ST(0)));
} else {
context = get_md6_ctx(aTHX_ xclass);
}
if ( items > 1 )
digest_len = (int) SvIV(ST(1));
MD6Init(context, digest_len);
XSRETURN(1);
void
clone(self)
SV* self
PREINIT:
md6_state* cont = get_md6_ctx(aTHX_ self);
const char *myname = sv_reftype(SvRV(self),TRUE);
md6_state* context;
PPCODE:
New(55, context, 1, md6_state);
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), myname , (void*)context);
SvREADONLY_on(SvRV(ST(0)));
memcpy(context,cont,sizeof(md6_state));
XSRETURN(1);
void
DESTROY(context)
md6_state* context
CODE:
Safefree(context);
void
reset(self)
SV* self
PREINIT:
md6_state* context = get_md6_ctx(aTHX_ self);
PPCODE:
MD6Init(context, context->d);
XSRETURN(1); /* self */
void
add(self, ...)
SV* self
PREINIT:
md6_state* context = get_md6_ctx(aTHX_ self);
int i;
unsigned char *data;
STRLEN len;
PPCODE:
for (i = 1; i < items; i++) {
data = (unsigned char *)(SvPV(ST(i), len));
MD6Update(context, data, len);
}
XSRETURN(1); /* self */
void
_add_bits(self, ...)
SV* self
PREINIT:
md6_state* context = get_md6_ctx(aTHX_ self);
int i;
unsigned char *data;
STRLEN len;
IV bits;
PPCODE:
if (!(items & 1)) {
croak("add_bits expects a number of data, length pairs");
}
for (i = 1; i < items; i += 2) {
data = (unsigned char *)(SvPV(ST(i), len));
bits = SvIV(ST(i+1));
if ( bits > len * 8 ) {
croak("not enough bits in data");
}
MD6UpdateBits(context, data, bits);
}
XSRETURN(1); /* self */
void
addfile(self, fh)
SV* self
InputStream fh
PREINIT:
md6_state* context = get_md6_ctx(aTHX_ self);
/* TODO is the correct? */
STRLEN fill = context->bits_processed / 8;
#ifdef USE_HEAP_INSTEAD_OF_STACK
unsigned char* buffer;
#else
unsigned char buffer[4096];
#endif
int n;
CODE:
if (fh) {
#ifdef USE_HEAP_INSTEAD_OF_STACK
New(0, buffer, 4096, unsigned char);
assert(buffer);
#endif
if (fill) {
/* The MD6Update() function is faster if it can work with
* complete blocks. This will fill up any buffered block
* first.
*/
STRLEN missing = 64 - fill;
if ( (n = PerlIO_read(fh, buffer, missing)) > 0)
MD6Update(context, buffer, n);
else
XSRETURN(1); /* self */
}
/* Process blocks until EOF or error */
while ( (n = PerlIO_read(fh, buffer, sizeof(buffer))) > 0) {
MD6Update(context, buffer, n);
}
#ifdef USE_HEAP_INSTEAD_OF_STACK
Safefree(buffer);
#endif
if (PerlIO_error(fh)) {
croak("Reading from filehandle failed");
}
}
else {
croak("No filehandle passed");
}
XSRETURN(1); /* self */
void
digest(context)
md6_state* context
ALIAS:
Digest::MD6::digest = F_BIN
Digest::MD6::hexdigest = F_HEX
Digest::MD6::b64digest = F_B64
PREINIT:
unsigned char digeststr[HASH_MAX_BYTES];
PPCODE:
MD6Final(digeststr, context);
MD6Init(context, context->d); /* In case it is reused */
ST(0) = make_mortal_sv(aTHX_ digeststr, context->d, ix);
XSRETURN(1);
void
md6(...)
ALIAS:
Digest::MD6::md6 = F_BIN
Digest::MD6::md6_hex = F_HEX
Digest::MD6::md6_base64 = F_B64
PREINIT:
md6_state ctx;
int i;
unsigned char *data;
STRLEN len;
unsigned char digeststr[HASH_MAX_BYTES];
PPCODE:
int digest_len = (int) SvIV(get_sv("Digest::MD6::HASH_LENGTH", FALSE));
MD6Init(&ctx, digest_len);
if (DOWARN) {
char *msg = 0;
if (items == 1) {
if (SvROK(ST(0))) {
SV* sv = SvRV(ST(0));
if (SvOBJECT(sv) && strEQ(HvNAME(SvSTASH(sv)), "Digest::MD6"))
msg = "probably called as method";
else
msg = "called with reference argument";
}
}
else if (items > 1) {
data = (unsigned char *)SvPV(ST(0), len);
if (len == 11 && memEQ("Digest::MD6", data, 11)) {
msg = "probably called as class method";
}
else if (SvROK(ST(0))) {
SV* sv = SvRV(ST(0));
if (SvOBJECT(sv) && strEQ(HvNAME(SvSTASH(sv)), "Digest::MD6"))
msg = "probably called as method";
}
}
if (msg) {
const char *f =
(ix == F_BIN) ? "md6"
: (ix == F_HEX) ? "md6_hex"
: "md6_base64";
warn("&Digest::MD6::%s function %s", f, msg);
}
}
for (i = 0; i < items; i++) {
data = (unsigned char *)(SvPV(ST(i), len));
MD6Update(&ctx, data, len);
}
MD6Final(digeststr, &ctx);
ST(0) = make_mortal_sv(aTHX_ digeststr, ctx.d, ix);
XSRETURN(1);
( run in 0.545 second using v1.01-cache-2.11-cpan-71847e10f99 )