#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <rhash.h>
#include <rhash_torrent.h>
typedef unsigned long long ulonglong;
/* helper macros and functions */
#define BASE32_LENGTH(size) (((size) * 8 + 4) / 5)
#define BASE64_LENGTH(size) ((((size) + 2) / 3) * 4)
void verify_single_bit_hash_id(unsigned hash_id, CV* cv)
{
const char* error;
const GV *gv;
const char *func_name;
if(0 == (hash_id & RHASH_ALL_HASHES)) {
error = "%s: unsupported hash_id = 0x%x";
} else if(0 != (hash_id & (hash_id - 1))) {
error = "%s: hash_id is not a single bit: 0x%x";
} else {
return; /* success */
}
gv = CvGV(cv);
func_name = (gv ? GvNAME(gv) : "Rhash");
croak(error, func_name, hash_id);
}
/* allocate a perl string scalar variable, containing str_len + 1 bytes */
SV * allocate_string_buffer(STRLEN str_len)
{
SV * sv = newSV(str_len); /* allocates (str_len + 1) bytes */
SvPOK_only(sv);
SvCUR_set(sv, str_len);
return sv;
}
MODULE = Crypt::Rhash PACKAGE = Crypt::Rhash
##############################################################################
# Initialize LibRHash in the module bootstrap function
BOOT:
rhash_library_init();
##############################################################################
# perl bindings for Hi-level functions
SV *
rhash_msg_wrapper(hash_id, message)
unsigned hash_id
PROTOTYPE: $$
PREINIT:
STRLEN length;
unsigned char out[264];
int res;
INPUT:
char* message = SvPV(ST(1), length);
CODE:
verify_single_bit_hash_id(hash_id, cv);
res = rhash_msg(hash_id, message, length, out);
if(res < 0) {
croak("%s: %s", "rhash_msg_wrapper", strerror(errno));
}
RETVAL = newSVpv((char*)out, rhash_get_digest_size(hash_id));
OUTPUT:
RETVAL
SV *
rhash_file_wrapper(hash_id, filepath)
unsigned hash_id
char * filepath
PROTOTYPE: $$
PREINIT:
int res;
unsigned char out[264];
CODE:
verify_single_bit_hash_id(hash_id, cv);
res = rhash_file(hash_id, filepath, out);
if(res < 0) {
croak("%s: %s: %s", "rhash_file", filepath, strerror(errno));
}
RETVAL = newSVpv((char*)out, rhash_get_digest_size(hash_id));
OUTPUT:
RETVAL
##############################################################################
# perl bindings for Low-level functions
struct rhash_context *
rhash_init_multi_wrapper(AV* array)
PROTOTYPE: $
PREINIT:
unsigned hash_ids[64];
size_t length = 0;
int i;
CODE:
for (i = 0; i <= av_len(array); i++) {
SV** elem = av_fetch(array, i, 0);
if (elem != NULL) {
if (length >= (sizeof(hash_ids)/sizeof(*hash_ids)))
croak("too many hash identifiers passed");
hash_ids[length] = (unsigned)SvNV(*elem);
length++;
}
}
if (length == 0)
croak("at least one hash identifier must be passed");
RETVAL = rhash_init_multi(length, hash_ids);
OUTPUT:
RETVAL
int
rhash_update(ctx, message)
struct rhash_context * ctx
PROTOTYPE: $$
PREINIT:
STRLEN length;
INPUT:
char* message = SvPV(ST(1), length);
CODE:
RETVAL = rhash_update(ctx, message, length);
OUTPUT:
RETVAL
int
rhash_final(ctx)
struct rhash_context * ctx
PROTOTYPE: $
CODE:
RETVAL = rhash_final(ctx, 0);
OUTPUT:
RETVAL
void
rhash_reset(ctx)
struct rhash_context * ctx
PROTOTYPE: $
void
rhash_free(ctx)
struct rhash_context * ctx
PROTOTYPE: $
SV *
rhash_print_wrapper(ctx, hash_id, flags = 0)
struct rhash_context * ctx
unsigned hash_id
int flags
PROTOTYPE: $$;$
PREINIT:
int len;
char out[264];
CODE:
if(hash_id != 0) verify_single_bit_hash_id(hash_id, cv);
len = rhash_print(out, ctx, hash_id, flags);
/* set exact length to support raw output (RHPR_RAW) */
RETVAL = newSVpv(out, len);
OUTPUT:
RETVAL
SV *
rhash_print_magnet_wrapper(ctx, filename, hash_mask)
struct rhash_context * ctx
SV * filename
SV * hash_mask
PROTOTYPE: $;$$
PREINIT:
/* process undefined values */
char * name = (SvOK(filename) ? SvPV_nolen(filename) : 0);
unsigned mask = (SvOK(hash_mask) ? (unsigned)SvUV(hash_mask) : RHASH_ALL_HASHES);
size_t buf_size;
CODE:
/* allocate a string buffer and print magnet link into it */
buf_size = rhash_print_magnet(0, name, ctx, mask, RHPR_FILESIZE);
RETVAL = allocate_string_buffer(buf_size - 1);
rhash_print_magnet(SvPVX(RETVAL), name, ctx, mask, RHPR_FILESIZE);
/* note: length(RETVAL) = (buf_size - 1),
* so the following call is not required:
* SvCUR_set(RETVAL, strlen(SvPVX(RETVAL))); */
OUTPUT:
RETVAL
unsigned
rhash_get_hash_id(ctx)
struct rhash_context * ctx
PROTOTYPE: $
CODE:
RETVAL = ctx->hash_id;
OUTPUT:
RETVAL
ulonglong
rhash_get_hashed_length(ctx)
struct rhash_context * ctx
PROTOTYPE: $
CODE:
RETVAL = ctx->msg_size;
OUTPUT:
RETVAL
##############################################################################
# Information functions
int
count()
CODE:
RETVAL = rhash_count();
OUTPUT:
RETVAL
SV *
librhash_version_string()
PREINIT:
unsigned version;
CODE:
version = rhash_get_version();
RETVAL = allocate_string_buffer(20);
sprintf(SvPVX(RETVAL), "%u.%u.%u", (version >> 24) & 255, (version >> 16) & 255, (version >> 8) & 255);
SvCUR_set(RETVAL, strlen(SvPVX(RETVAL)));
OUTPUT:
RETVAL
int
librhash_version()
CODE:
RETVAL = rhash_get_version();
OUTPUT:
RETVAL
int
is_base32(hash_id)
unsigned hash_id
PROTOTYPE: $
CODE:
RETVAL = rhash_is_base32(hash_id);
OUTPUT:
RETVAL
int
get_digest_size(hash_id)
unsigned hash_id
PROTOTYPE: $
CODE:
RETVAL = rhash_get_digest_size(hash_id);
OUTPUT:
RETVAL
int
get_hash_length(hash_id)
unsigned hash_id
PROTOTYPE: $
CODE:
RETVAL = rhash_get_hash_length(hash_id);
OUTPUT:
RETVAL
const char *
get_name(hash_id)
unsigned hash_id
PROTOTYPE: $
CODE:
RETVAL = rhash_get_name(hash_id);
OUTPUT:
RETVAL
##############################################################################
# Hash printing functions
##############################################################################
# Hash conversion functions
SV *
raw2hex(bytes)
PROTOTYPE: $
PREINIT:
STRLEN size;
INPUT:
unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
CODE:
RETVAL = allocate_string_buffer(size * 2);
rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_HEX);
OUTPUT:
RETVAL
SV *
raw2base32(bytes)
PROTOTYPE: $
PREINIT:
STRLEN size;
INPUT:
unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
CODE:
RETVAL = allocate_string_buffer(BASE32_LENGTH(size));
rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_BASE32);
OUTPUT:
RETVAL
SV *
raw2base64(bytes)
PROTOTYPE: $
PREINIT:
STRLEN size;
INPUT:
unsigned char * bytes = (unsigned char*)SvPV(ST(0), size);
CODE:
RETVAL = allocate_string_buffer(BASE64_LENGTH(size));
rhash_print_bytes(SvPVX(RETVAL), bytes, size, RHPR_BASE64);
OUTPUT:
RETVAL
##############################################################################
# BTIH / BitTorrent support functions
void
rhash_bt_add_filename(ctx, filename, filesize)
struct rhash_context * ctx
char * filename
ulonglong filesize
PROTOTYPE: $$$
CODE:
rhash_torrent_add_file(ctx, filename, filesize);
void
rhash_bt_set_piece_length(ctx, piece_length)
struct rhash_context * ctx
unsigned piece_length
PROTOTYPE: $$
CODE:
rhash_torrent_set_piece_length(ctx, piece_length);
void
rhash_bt_set_private(ctx)
struct rhash_context * ctx
PROTOTYPE: $
CODE:
rhash_torrent_set_options(ctx, RHASH_TORRENT_OPT_PRIVATE);
SV *
rhash_bt_get_torrent_text(ctx)
struct rhash_context * ctx
PROTOTYPE: $
PREINIT:
const rhash_str* text;
CODE:
text = rhash_torrent_generate_content(ctx);
if(!text) {
XSRETURN_UNDEF;
}
RETVAL = newSVpv(text->str, text->length);
OUTPUT:
RETVAL