* Copyright 1991-1992 RSA Data Security, Inc.
*
* This code is derived from Neil Winton's MD5-1.7 Perl module, which in
- * turn is derived from the reference implementation in RFC 1231 which
+ * turn is derived from the reference implementation in RFC 1321 which
* comes with this message:
*
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
#ifdef __cplusplus
extern "C" {
#endif
+#define PERL_NO_GET_CONTEXT /* we want efficiency */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
}
#endif
-#ifndef SvPVbyte
+#ifndef PERL_VERSION
+# include <patchlevel.h>
+# if !(defined(PERL_VERSION) || (SUBVERSION > 0 && defined(PATCHLEVEL)))
+# include <could_not_find_Perl_patchlevel.h>
+# endif
+# define PERL_REVISION 5
+# define PERL_VERSION PATCHLEVEL
+# define PERL_SUBVERSION SUBVERSION
+#endif
+
+#if PERL_VERSION <= 4 && !defined(PL_dowarn)
+ #define PL_dowarn dowarn
+#endif
+
+#ifdef G_WARN_ON
+ #define DOWARN (PL_dowarn & G_WARN_ON)
+#else
+ #define DOWARN PL_dowarn
+#endif
+
+#ifdef SvPVbyte
+ #if PERL_REVISION == 5 && PERL_VERSION < 7
+ /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
+ #undef SvPVbyte
+ #define SvPVbyte(sv, lp) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
+
+ static char *
+ my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+ {
+ sv_utf8_downgrade(sv,0);
+ return SvPV(sv,*lp);
+ }
+ #endif
+#else
#define SvPVbyte SvPV
#endif
+#ifndef dTHX
+ #define pTHX_
+ #define aTHX_
+#endif
+
/* Perl does not guarantee that U32 is exactly 32 bits. Some system
* has no integral type with exactly 32 bits. For instance, A Cray has
* short, int and long all at 64 bits so we need to apply this macro
#ifndef BYTESWAP
static void u2s(U32 u, U8* s)
{
- *s++ = u & 0xFF;
- *s++ = (u >> 8) & 0xFF;
- *s++ = (u >> 16) & 0xFF;
- *s = (u >> 24) & 0xFF;
+ *s++ = (U8)(u & 0xFF);
+ *s++ = (U8)((u >> 8) & 0xFF);
+ *s++ = (U8)((u >> 16) & 0xFF);
+ *s = (U8)((u >> 24) & 0xFF);
}
#define s2u(s,u) ((u) = (U32)(*s) | \
* padding is also the reason the buffer in MD5_CTX have to be
* 128 bytes.
*/
-static unsigned char PADDING[64] = {
+static const unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
#define INT2PTR(any,d) (any)(d)
#endif
-static MD5_CTX* get_md5_ctx(SV* sv)
+static MD5_CTX* get_md5_ctx(pTHX_ SV* sv)
{
if (SvROK(sv)) {
sv = SvRV(sv);
static char* hex_16(const unsigned char* from, char* to)
{
- static char *hexdigits = "0123456789abcdef";
+ static const char hexdigits[] = "0123456789abcdef";
const unsigned char *end = from + 16;
char *d = to;
static char* base64_16(const unsigned char* from, char* to)
{
- static char* base64 =
+ static const char base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const unsigned char *end = from + 16;
unsigned char c1, c2, c3;
#define F_HEX 1
#define F_B64 2
-static SV* make_mortal_sv(const unsigned char *src, int type)
+static SV* make_mortal_sv(pTHX_ const unsigned char *src, int type)
{
STRLEN len;
char result[33];
sv_setref_pv(ST(0), sclass, (void*)context);
SvREADONLY_on(SvRV(ST(0)));
} else {
- context = get_md5_ctx(xclass);
+ context = get_md5_ctx(aTHX_ xclass);
}
MD5Init(context);
XSRETURN(1);
void
+clone(self)
+ SV* self
+ PREINIT:
+ MD5_CTX* cont = get_md5_ctx(aTHX_ self);
+ const char *myname = sv_reftype(SvRV(self),TRUE);
+ MD5_CTX* context;
+ PPCODE:
+ New(55, context, 1, MD5_CTX);
+ ST(0) = sv_newmortal();
+ sv_setref_pv(ST(0), myname , (void*)context);
+ SvREADONLY_on(SvRV(ST(0)));
+ memcpy(context,cont,sizeof(MD5_CTX));
+ XSRETURN(1);
+
+void
DESTROY(context)
MD5_CTX* context
CODE:
add(self, ...)
SV* self
PREINIT:
- MD5_CTX* context = get_md5_ctx(self);
+ MD5_CTX* context = get_md5_ctx(aTHX_ self);
int i;
unsigned char *data;
STRLEN len;
SV* self
InputStream fh
PREINIT:
- MD5_CTX* context = get_md5_ctx(self);
+ MD5_CTX* context = get_md5_ctx(aTHX_ self);
STRLEN fill = context->bytes_low & 0x3F;
+#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 MD5Update() 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)))
+ if ( (n = PerlIO_read(fh, buffer, missing)) > 0)
MD5Update(context, buffer, n);
else
XSRETURN(1); /* self */
}
- /* Process blocks until EOF */
- while ( (n = PerlIO_read(fh, buffer, sizeof(buffer)))) {
+ /* Process blocks until EOF or error */
+ while ( (n = PerlIO_read(fh, buffer, sizeof(buffer))) > 0) {
MD5Update(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 */
PPCODE:
MD5Final(digeststr, context);
MD5Init(context); /* In case it is reused */
- ST(0) = make_mortal_sv(digeststr, ix);
+ ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
XSRETURN(1);
void
unsigned char digeststr[16];
PPCODE:
MD5Init(&ctx);
- if (PL_dowarn && items > 1) {
- data = (unsigned char *)SvPVbyte(ST(0), len);
- if (len == 11 && memEQ("Digest::MD5", data, 11)) {
- char *f = (ix == F_BIN) ? "md5" :
- (ix == F_HEX) ? "md5_hex" : "md5_base64";
- warn("&Digest::MD5::%s function probably called as method", f);
- }
+
+ 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::MD5"))
+ msg = "probably called as method";
+ else
+ msg = "called with reference argument";
+ }
+ }
+ else if (items > 1) {
+ data = (unsigned char *)SvPVbyte(ST(0), len);
+ if (len == 11 && memEQ("Digest::MD5", 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::MD5"))
+ msg = "probably called as method";
+ }
+ }
+ if (msg) {
+ const char *f = (ix == F_BIN) ? "md5" :
+ (ix == F_HEX) ? "md5_hex" : "md5_base64";
+ warn("&Digest::MD5::%s function %s", f, msg);
+ }
}
+
for (i = 0; i < items; i++) {
data = (unsigned char *)(SvPVbyte(ST(i), len));
MD5Update(&ctx, data, len);
}
MD5Final(digeststr, &ctx);
- ST(0) = make_mortal_sv(digeststr, ix);
+ ST(0) = make_mortal_sv(aTHX_ digeststr, ix);
XSRETURN(1);