Digest-MD6

 view release on metacpan or  search on metacpan

MD6.xs  view on Meta::CPAN

    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 )