summaryrefslogtreecommitdiff
path: root/ext/digest/digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/digest/digest.c')
-rw-r--r--ext/digest/digest.c726
1 files changed, 459 insertions, 267 deletions
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index b8144f3706..4a5245f911 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -15,32 +15,24 @@
#include "digest.h"
-static VALUE mDigest, cDigest_Base;
-static ID id_metadata, id_new, id_initialize, id_update, id_digest;
+static VALUE rb_mDigest;
+static VALUE rb_mDigest_Instance;
+static VALUE rb_cDigest_Class;
+static VALUE rb_cDigest_Base;
-/*
- * Digest::Base
- */
-
-static algo_t *
-get_digest_base_metadata(VALUE klass)
-{
- VALUE obj;
- algo_t *algo;
+static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length;
+static ID id_metadata;
- if (rb_ivar_defined(klass, id_metadata) == Qfalse) {
- return NULL;
- }
-
- obj = rb_ivar_get(klass, id_metadata);
+RUBY_EXTERN void Init_digest_base(void);
- Data_Get_Struct(obj, algo_t, algo);
-
- return algo;
-}
+/*
+ * Document-module: Digest
+ *
+ * This module provides a framework for message digest libraries.
+ */
static VALUE
-hexdigest_str_new(VALUE str_digest)
+hexencode_str_new(VALUE str_digest)
{
char *digest;
size_t digest_len;
@@ -72,376 +64,576 @@ hexdigest_str_new(VALUE str_digest)
return str;
}
+/*
+ * call-seq:
+ * Digest.hexencode(string) -> hexencoded_string
+ *
+ * Generates a hex-encoded version of a given _string_.
+ */
static VALUE
-bubblebabble_str_new(VALUE str_digest)
+rb_digest_s_hexencode(VALUE klass, VALUE str)
{
- char *digest;
- size_t digest_len;
- VALUE str;
- char *p;
- int i, j, seed = 1;
- static const char vowels[] = {
- 'a', 'e', 'i', 'o', 'u', 'y'
- };
- static const char consonants[] = {
- 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n',
- 'p', 'r', 's', 't', 'v', 'z', 'x'
- };
+ return hexencode_str_new(str);
+}
- StringValue(str_digest);
- digest = RSTRING_PTR(str_digest);
- digest_len = RSTRING_LEN(str_digest);
+/*
+ * Document-module: Digest::Instance
+ *
+ * This module provides instance methods for a digest implementation
+ * object to calculate message digest values.
+ */
- if ((LONG_MAX - 2) / 3 < (digest_len | 1)) {
- rb_raise(rb_eRuntimeError, "digest string too long");
- }
+/*
+ * call-seq:
+ * digest_obj.update(string) -> digest_obj
+ * digest_obj << string -> digest_obj
+ *
+ * Updates the digest using a given _string_ and returns self.
+ *
+ * The update() method and the left-shift operator are overridden by
+ * each implementation subclass. (One should be an alias for the
+ * other)
+ */
+static VALUE
+rb_digest_instance_update(VALUE self, VALUE str)
+{
+ rb_raise(rb_eRuntimeError, "%s does not implement update()", rb_inspect(self));
+}
- str = rb_str_new(0, (digest_len | 1) * 3 + 2);
- p = RSTRING_PTR(str);
+/*
+ * call-seq:
+ * digest_obj.instance_eval { finish } -> digest_obj
+ *
+ * Finishes the digest and returns the resulting hash value.
+ *
+ * This method is overridden by each implementation subclass and often
+ * made private, because some of those subclasses may leave internal
+ * data uninitialized. Do not call this method from outside. Use
+ * #digest!() instead, which ensures that internal data be reset for
+ * security reasons.
+ */
+static VALUE
+rb_digest_instance_finish(VALUE self)
+{
+ rb_raise(rb_eRuntimeError, "%s does not implement finish()", rb_inspect(self));
+}
- i = j = 0;
- p[j++] = 'x';
+/*
+ * call-seq:
+ * digest_obj.reset -> digest_obj
+ *
+ * Resets the digest to the initial state and returns self.
+ *
+ * This method is overridden by each implementation subclass.
+ */
+static VALUE
+rb_digest_instance_reset(VALUE self)
+{
+ rb_raise(rb_eRuntimeError, "%s does not implement reset()", rb_inspect(self));
+}
- for (;;) {
- unsigned char byte1, byte2;
+/*
+ * call-seq:
+ * digest_obj.new -> another_digest_obj
+ *
+ * Returns a new, initialized copy of the digest object. Equivalent
+ * to digest_obj.clone().reset().
+ */
+static VALUE
+rb_digest_instance_new(VALUE self)
+{
+ VALUE clone = rb_obj_clone(self);
+ rb_funcall(clone, id_reset, 0);
+ return clone;
+}
+
+/*
+ * call-seq:
+ * digest_obj.digest -> string
+ * digest_obj.digest(string) -> string
+ *
+ * If none is given, returns the resulting hash value of the digest,
+ * keeping the digest's state.
+ *
+ * If a _string_ is given, returns the hash value for the given
+ * _string_, resetting the digest to the initial state before and
+ * after the process.
+ */
+static VALUE
+rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str, value;
+
+ if (rb_scan_args(argc, argv, "01", &str) > 0) {
+ rb_funcall(self, id_reset, 0);
+ rb_funcall(self, id_update, 1, str);
+ value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
+ } else {
+ VALUE clone = rb_obj_clone(self);
+
+ value = rb_funcall(clone, id_finish, 0);
+ rb_funcall(clone, id_reset, 0);
+ }
+
+ return value;
+}
- if (i >= digest_len) {
- p[j++] = vowels[seed % 6];
- p[j++] = consonants[16];
- p[j++] = vowels[seed / 6];
- break;
- }
+/*
+ * call-seq:
+ * digest_obj.digest! -> string
+ *
+ * Returns the resulting hash value and resets the digest to the
+ * initial state.
+ */
+static VALUE
+rb_digest_instance_digest_bang(VALUE self)
+{
+ VALUE value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
- byte1 = digest[i++];
- p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6];
- p[j++] = consonants[(byte1 >> 2) & 15];
- p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6];
+ return value;
+}
- if (i >= digest_len) {
- break;
- }
+/*
+ * call-seq:
+ * digest_obj.hexdigest -> string
+ * digest_obj.hexdigest(string) -> string
+ *
+ * If none is given, returns the resulting hash value of the digest in
+ * a hex-encoded form, keeping the digest's state.
+ *
+ * If a _string_ is given, returns the hash value for the given
+ * _string_ in a hex-encoded form, resetting the digest to the initial
+ * state before and after the process.
+ */
+static VALUE
+rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str, value;
- byte2 = digest[i++];
- p[j++] = consonants[(byte2 >> 4) & 15];
- p[j++] = '-';
- p[j++] = consonants[byte2 & 15];
+ if (rb_scan_args(argc, argv, "01", &str) > 0) {
+ rb_funcall(self, id_reset, 0);
+ rb_funcall(self, id_update, 1, str);
+ value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
+ } else {
+ VALUE clone = rb_obj_clone(self);
- seed = (seed * 5 + byte1 * 7 + byte2) % 36;
+ value = rb_funcall(clone, id_finish, 0);
+ rb_funcall(clone, id_reset, 0);
}
- p[j] = 'x';
+ return hexencode_str_new(value);
+}
+
+/*
+ * call-seq:
+ * digest_obj.hexdigest! -> string
+ *
+ * Returns the resulting hash value and resets the digest to the
+ * initial state.
+ */
+static VALUE
+rb_digest_instance_hexdigest_bang(VALUE self)
+{
+ VALUE value = rb_funcall(self, id_finish, 0);
+ rb_funcall(self, id_reset, 0);
+
+ return hexencode_str_new(value);
+}
+
+/*
+ * call-seq:
+ * digest_obj.to_s -> string
+ *
+ * Returns digest_obj.hexdigest().
+ */
+static VALUE
+rb_digest_instance_to_s(VALUE self)
+{
+ return rb_funcall(self, id_hexdigest, 0);
+}
+
+/*
+ * call-seq:
+ * digest_obj.inspect -> string
+ *
+ * Creates a printable version of the digest object.
+ */
+static VALUE
+rb_digest_instance_inspect(VALUE self)
+{
+ VALUE str;
+ size_t digest_len = 32; /* about this size at least */
+ char *cname;
+
+ cname = rb_obj_classname(self);
+ /* #<Digest::ClassName: xxxxx...xxxx> */
+ str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
+ rb_str_buf_cat2(str, "#<");
+ rb_str_buf_cat2(str, cname);
+ rb_str_buf_cat2(str, ": ");
+ rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
+ rb_str_buf_cat2(str, ">");
return str;
}
+/*
+ * call-seq:
+ * digest_obj == another_digest_obj -> boolean
+ * digest_obj == string -> boolean
+ *
+ * If a string is given, checks whether it is equal to the hex-encoded
+ * hash value of the digest object. If another instance of the same
+ * digest class is given, checks whether they have the same hash
+ * value. Otherwise returns false.
+ */
static VALUE
-rb_digest_base_alloc(VALUE klass)
+rb_digest_instance_equal(VALUE self, VALUE other)
{
- algo_t *algo;
- VALUE obj;
- void *pctx;
+ VALUE str1, str2;
- if (klass == cDigest_Base) {
- rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
+ if (rb_obj_class(self) == rb_obj_class(other)) {
+ str1 = rb_digest_instance_digest(0, 0, self);
+ str2 = rb_digest_instance_digest(0, 0, other);
+ } else {
+ str1 = rb_digest_instance_to_s(self);
+ str2 = other;
}
- algo = get_digest_base_metadata(klass);
+ /* never blindly assume that subclass methods return strings */
+ StringValue(str1);
+ StringValue(str2);
- if (algo == NULL) {
- return Data_Wrap_Struct(klass, 0, free, 0);
+ if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
+ rb_str_cmp(str1, str2) == 0) {
+ return Qtrue;
}
+ return Qfalse;
+}
- pctx = xmalloc(algo->ctx_size);
- algo->init_func(pctx);
+/*
+ * call-seq:
+ * digest_obj.digest_length -> integer
+ *
+ * Returns the length of the hash value of the digest.
+ *
+ * This method should be overridden by each implementation subclass.
+ * If not, digest_obj.digest().length() is returned.
+ */
+static VALUE
+rb_digest_instance_digest_length(VALUE self)
+{
+ /* subclasses really should redefine this method */
+ VALUE digest = rb_digest_instance_digest(0, 0, self);
- obj = Data_Wrap_Struct(klass, 0, free, pctx);
+ /* never blindly assume that #digest() returns a string */
+ StringValue(digest);
+ return INT2NUM(RSTRING_LEN(digest));
+}
- return obj;
+/*
+ * call-seq:
+ * digest_obj.length -> integer
+ * digest_obj.size -> integer
+ *
+ * Returns digest_obj.digest_length().
+ */
+static VALUE
+rb_digest_instance_length(VALUE self)
+{
+ return rb_funcall(self, id_digest_length, 0);
}
+/*
+ * call-seq:
+ * digest_obj.block_length -> integer
+ *
+ * Returns the block length of the digest.
+ *
+ * This method is overridden by each implementation subclass.
+ */
static VALUE
-rb_digest_base_s_digest(VALUE klass, VALUE str)
+rb_digest_instance_block_length(VALUE self)
{
- algo_t *algo = get_digest_base_metadata(klass);
+ rb_raise(rb_eRuntimeError, "%s does not implement block_length()", rb_inspect(self));
+}
+
+/*
+ * Document-class: Digest::Class
+ *
+ * This module stands as a base class for digest implementation
+ * classes.
+ */
+
+/*
+ * call-seq:
+ * Digest::Class.digest(string, *parameters) -> hash_string
+ *
+ * Returns the hash value of a given _string_. This is equivalent to
+ * Digest::Class.new(*parameters).digest(string), where extra
+ * _parameters_, if any, are passed through to the constructor and the
+ * _string_ is passed to #digest().
+ */
+static VALUE
+rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str;
void *pctx;
volatile VALUE obj;
- if (algo == NULL) {
- VALUE obj = rb_funcall(klass, id_new, 0);
- rb_funcall(obj, id_update, 1, str);
- return rb_funcall(obj, id_digest, 0);
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "no data given");
}
- obj = rb_digest_base_alloc(klass);
- Data_Get_Struct(obj, void, pctx);
+ str = *argv++;
+ argc--;
StringValue(str);
- algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
- str = rb_str_new(0, algo->digest_len);
- algo->finish_func(pctx, RSTRING_PTR(str));
+ obj = rb_obj_alloc(klass);
+ rb_obj_call_init(obj, argc, argv);
- return str;
+ return rb_funcall(obj, id_digest, 1, str);
}
+/*
+ * call-seq:
+ * Digest::Class.hexdigest(string[, ...]) -> hash_string
+ *
+ * Returns the hex-encoded hash value of a given _string_. This is
+ * almost equivalent to
+ * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
+ */
static VALUE
-rb_digest_base_s_hexdigest(VALUE klass, VALUE str)
+rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
{
- return hexdigest_str_new(rb_funcall(klass, id_digest, 1, str));
+ return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
}
-static VALUE
-rb_digest_base_s_bubblebabble(VALUE klass, VALUE str)
-{
- return bubblebabble_str_new(rb_funcall(klass, id_digest, 1, str));
-}
+/*
+ * Document-class: Digest::Base
+ *
+ * This abstract class provides a common interface to message digest
+ * implementation classes written in C.
+ */
-static VALUE
-rb_digest_base_copy(VALUE copy, VALUE obj)
+static rb_digest_metadata_t *
+get_digest_base_metadata(VALUE klass)
{
- algo_t *algo;
- void *pctx1, *pctx2;
-
- if (copy == obj) return copy;
- rb_check_frozen(copy);
- algo = get_digest_base_metadata(rb_obj_class(copy));
+ VALUE obj;
+ rb_digest_metadata_t *algo;
- if (algo == NULL) {
- /* initialize_copy() is undefined or something */
+ if (rb_ivar_defined(klass, id_metadata) == Qfalse) {
+ /* This class should not be subclassed in Ruby */
rb_notimplement();
}
- /* get_digest_base_metadata() may return a NULL */
- if (algo != get_digest_base_metadata(rb_obj_class(obj))) {
- rb_raise(rb_eTypeError, "wrong argument class");
+ obj = rb_ivar_get(klass, id_metadata);
+
+ Data_Get_Struct(obj, rb_digest_metadata_t, algo);
+
+ switch (algo->api_version) {
+ case 2:
+ break;
+
+ /*
+ * put conversion here if possible when API is updated
+ */
+
+ default:
+ rb_raise(rb_eRuntimeError, "Incompatible digest API version");
}
- Data_Get_Struct(obj, void, pctx1);
- Data_Get_Struct(copy, void, pctx2);
- memcpy(pctx2, pctx1, algo->ctx_size);
- return copy;
+ return algo;
}
static VALUE
-rb_digest_base_reset(VALUE self)
+rb_digest_base_alloc(VALUE klass)
{
- algo_t *algo;
+ rb_digest_metadata_t *algo;
+ VALUE obj;
void *pctx;
- algo = get_digest_base_metadata(rb_obj_class(self));
-
- if (algo == NULL) {
- rb_funcall(self, id_initialize, 0);
-
- return self;
+ if (klass == rb_cDigest_Base) {
+ rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
}
- Data_Get_Struct(self, void, pctx);
+ algo = get_digest_base_metadata(klass);
- memset(pctx, 0, algo->ctx_size);
+ pctx = xmalloc(algo->ctx_size);
algo->init_func(pctx);
- return self;
+ obj = Data_Wrap_Struct(klass, 0, free, pctx);
+
+ return obj;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_update(VALUE self, VALUE str)
+rb_digest_base_copy(VALUE copy, VALUE obj)
{
- algo_t *algo;
- void *pctx;
+ rb_digest_metadata_t *algo;
+ void *pctx1, *pctx2;
- algo = get_digest_base_metadata(rb_obj_class(self));
+ if (copy == obj) return copy;
- if (algo == NULL) {
- /* subclasses must define update() */
- rb_notimplement();
- }
+ rb_check_frozen(copy);
- Data_Get_Struct(self, void, pctx);
+ algo = get_digest_base_metadata(rb_obj_class(copy));
- StringValue(str);
- algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
+ Data_Get_Struct(obj, void, pctx1);
+ Data_Get_Struct(copy, void, pctx2);
+ memcpy(pctx2, pctx1, algo->ctx_size);
- return self;
+ return copy;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_lshift(VALUE self, VALUE str)
+rb_digest_base_reset(VALUE self)
{
- algo_t *algo;
+ rb_digest_metadata_t *algo;
void *pctx;
algo = get_digest_base_metadata(rb_obj_class(self));
- if (algo == NULL) {
- /* subclasses just need to define update(), not << */
- rb_funcall(self, id_update, 1, str);
-
- return self;
- }
-
Data_Get_Struct(self, void, pctx);
- StringValue(str);
- algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
+ algo->init_func(pctx);
return self;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_init(int argc, VALUE *argv, VALUE self)
+rb_digest_base_update(VALUE self, VALUE str)
{
- VALUE arg;
+ rb_digest_metadata_t *algo;
+ void *pctx;
- rb_scan_args(argc, argv, "01", &arg);
+ algo = get_digest_base_metadata(rb_obj_class(self));
- if (!NIL_P(arg)) rb_digest_base_update(self, arg);
+ Data_Get_Struct(self, void, pctx);
+
+ StringValue(str);
+ algo->update_func(pctx, RSTRING_PTR(str), RSTRING_LEN(str));
return self;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_digest(VALUE self)
+rb_digest_base_finish(VALUE self)
{
- algo_t *algo;
- void *pctx1, *pctx2;
- size_t ctx_size;
+ rb_digest_metadata_t *algo;
+ void *pctx;
VALUE str;
algo = get_digest_base_metadata(rb_obj_class(self));
- if (algo == NULL) {
- /* subclasses must define update() */
- rb_notimplement();
- }
-
- Data_Get_Struct(self, void, pctx1);
-
- ctx_size = algo->ctx_size;
- pctx2 = xmalloc(ctx_size);
- memcpy(pctx2, pctx1, ctx_size);
+ Data_Get_Struct(self, void, pctx);
str = rb_str_new(0, algo->digest_len);
- algo->finish_func(pctx2, RSTRING_PTR(str));
- free(pctx2);
-
- return str;
-}
+ algo->finish_func(pctx, RSTRING_PTR(str));
-static VALUE
-rb_digest_base_hexdigest(VALUE self)
-{
- return hexdigest_str_new(rb_funcall(self, id_digest, 0));
-}
+ /* avoid potential coredump caused by use of a finished context */
+ algo->init_func(pctx);
-static VALUE
-rb_digest_base_bubblebabble(VALUE self)
-{
- return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
+ return str;
}
+/* :nodoc: */
static VALUE
-rb_digest_base_inspect(VALUE self)
+rb_digest_base_digest_length(VALUE self)
{
- algo_t *algo;
- VALUE klass, str;
- size_t digest_len = 32; /* no need to be just the right size */
- char *cname;
+ rb_digest_metadata_t *algo;
- klass = rb_obj_class(self);
- algo = get_digest_base_metadata(klass);
-
- if (algo != NULL)
- digest_len = algo->digest_len;
-
- cname = rb_obj_classname(self);
+ algo = get_digest_base_metadata(rb_obj_class(self));
- /* #<Digest::Alg: xxxxx...xxxx> */
- str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
- rb_str_buf_cat2(str, "#<");
- rb_str_buf_cat2(str, cname);
- rb_str_buf_cat2(str, ": ");
- rb_str_buf_append(str, rb_digest_base_hexdigest(self));
- rb_str_buf_cat2(str, ">");
- return str;
+ return INT2NUM(algo->digest_len);
}
+/* :nodoc: */
static VALUE
-rb_digest_base_equal(VALUE self, VALUE other)
+rb_digest_base_block_length(VALUE self)
{
- algo_t *algo;
- VALUE klass;
- VALUE str1, str2;
+ rb_digest_metadata_t *algo;
- klass = rb_obj_class(self);
-
- if (rb_obj_class(other) == klass) {
- str1 = rb_digest_base_digest(self);
- str2 = rb_digest_base_digest(other);
- } else {
- StringValue(other);
- str2 = other;
-
- algo = get_digest_base_metadata(klass);
-
- if (RSTRING_LEN(str2) == algo->digest_len)
- str1 = rb_digest_base_digest(self);
- else
- str1 = rb_digest_base_hexdigest(self);
- }
-
- if (RSTRING_LEN(str1) == RSTRING_LEN(str2)
- && rb_str_cmp(str1, str2) == 0)
- return Qtrue;
+ algo = get_digest_base_metadata(rb_obj_class(self));
- return Qfalse;
+ return INT2NUM(algo->block_len);
}
-/*
- * This module provides an interface to the following hash algorithms:
- *
- * - the MD5 Message-Digest Algorithm by the RSA Data Security,
- * Inc., described in RFC 1321
- *
- * - the SHA-1 Secure Hash Algorithm by NIST (the US' National
- * Institute of Standards and Technology), described in FIPS PUB
- * 180-1.
- *
- * - the SHA-256/384/512 Secure Hash Algorithm by NIST (the US'
- * National Institute of Standards and Technology), described in
- * FIPS PUB 180-2.
- *
- * - the RIPEMD-160 cryptographic hash function, designed by Hans
- * Dobbertin, Antoon Bosselaers, and Bart Preneel.
- */
-
void
Init_digest(void)
{
- mDigest = rb_define_module("Digest");
-
- cDigest_Base = rb_define_class_under(mDigest, "Base", rb_cObject);
-
- rb_define_alloc_func(cDigest_Base, rb_digest_base_alloc);
- rb_define_singleton_method(cDigest_Base, "digest", rb_digest_base_s_digest, 1);
- rb_define_singleton_method(cDigest_Base, "hexdigest", rb_digest_base_s_hexdigest, 1);
- rb_define_singleton_method(cDigest_Base, "bubblebabble", rb_digest_base_s_bubblebabble, 1);
-
- rb_define_method(cDigest_Base, "initialize", rb_digest_base_init, -1);
- rb_define_method(cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
- rb_define_method(cDigest_Base, "reset", rb_digest_base_reset, 0);
- rb_define_method(cDigest_Base, "update", rb_digest_base_update, 1);
- rb_define_method(cDigest_Base, "<<", rb_digest_base_lshift, 1);
- rb_define_method(cDigest_Base, "digest", rb_digest_base_digest, 0);
- rb_define_method(cDigest_Base, "hexdigest", rb_digest_base_hexdigest, 0);
- rb_define_method(cDigest_Base, "bubblebabble", rb_digest_base_bubblebabble, 0);
- rb_define_method(cDigest_Base, "to_s", rb_digest_base_hexdigest, 0);
- rb_define_method(cDigest_Base, "inspect", rb_digest_base_inspect, 0);
- rb_define_method(cDigest_Base, "==", rb_digest_base_equal, 1);
+ id_reset = rb_intern("reset");
+ id_update = rb_intern("update");
+ id_finish = rb_intern("finish");
+ id_digest = rb_intern("digest");
+ id_hexdigest = rb_intern("hexdigest");
+ id_digest_length = rb_intern("digest_length");
+
+ /*
+ * module Digest
+ */
+ rb_mDigest = rb_define_module("Digest");
+
+ /* module functions */
+ rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
+
+ /*
+ * module Digest::Instance
+ */
+ rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
+
+ /* instance methods that should be overridden */
+ rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
+ rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
+ rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
+ rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
+ rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
+ rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
+
+ /* instance methods that may be overridden */
+ rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
+ rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
+
+ /* instance methods that need not usually be overridden */
+ rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
+ rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
+ rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
+ rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
+ rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
+ rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_hexdigest, 0);
+ rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
+ rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
+
+ /*
+ * class Digest::Class
+ */
+ rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
+ rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
+
+ /* class methods */
+ rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
+ rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
id_metadata = rb_intern("metadata");
- id_new = rb_intern("new");
- id_initialize = rb_intern("initialize");
- id_update = rb_intern("update");
- id_digest = rb_intern("digest");
+
+ /* class Digest::Base < Digest::Class */
+ rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
+
+ rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
+
+ rb_define_method(rb_cDigest_Base, "initialize_copy", rb_digest_base_copy, 1);
+ rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
+ rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
+ rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
+ rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
+ rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
+ rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
}