OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / ext / digest / digest.c
1 /************************************************
2
3   digest.c -
4
5   $Author: shyouhei $
6   created at: Fri May 25 08:57:27 JST 2001
7
8   Copyright (C) 1995-2001 Yukihiro Matsumoto
9   Copyright (C) 2001-2006 Akinori MUSHA
10
11   $RoughId: digest.c,v 1.16 2001/07/13 15:38:27 knu Exp $
12   $Id: digest.c 17775 2008-07-01 10:36:22Z shyouhei $
13
14 ************************************************/
15
16 #include "digest.h"
17
18 static VALUE rb_mDigest;
19 static VALUE rb_mDigest_Instance;
20 static VALUE rb_cDigest_Class;
21 static VALUE rb_cDigest_Base;
22
23 static ID id_reset, id_update, id_finish, id_digest, id_hexdigest, id_digest_length;
24 static ID id_metadata;
25
26 RUBY_EXTERN void Init_digest_base(void);
27
28 /*
29  * Document-module: Digest
30  *
31  * This module provides a framework for message digest libraries.
32  */
33
34 static VALUE
35 hexencode_str_new(VALUE str_digest)
36 {
37     char *digest;
38     size_t digest_len;
39     int i;
40     VALUE str;
41     char *p;
42     static const char hex[] = {
43         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
44         'a', 'b', 'c', 'd', 'e', 'f'
45     };
46
47     StringValue(str_digest);
48     digest = RSTRING_PTR(str_digest);
49     digest_len = RSTRING_LEN(str_digest);
50
51     if (LONG_MAX / 2 < digest_len) {
52         rb_raise(rb_eRuntimeError, "digest string too long");
53     }
54
55     str = rb_str_new(0, digest_len * 2);
56
57     for (i = 0, p = RSTRING_PTR(str); i < digest_len; i++) {
58         unsigned char byte = digest[i];
59
60         p[i + i]     = hex[byte >> 4];
61         p[i + i + 1] = hex[byte & 0x0f];
62     }
63
64     return str;
65 }
66
67 /*
68  * call-seq:
69  *     Digest.hexencode(string) -> hexencoded_string
70  *
71  * Generates a hex-encoded version of a given _string_.
72  */
73 static VALUE
74 rb_digest_s_hexencode(VALUE klass, VALUE str)
75 {
76     return hexencode_str_new(str);
77 }
78
79 /*
80  * Document-module: Digest::Instance
81  *
82  * This module provides instance methods for a digest implementation
83  * object to calculate message digest values.
84  */
85
86 /*
87  * call-seq:
88  *     digest_obj.update(string) -> digest_obj
89  *     digest_obj << string -> digest_obj
90  *
91  * Updates the digest using a given _string_ and returns self.
92  *
93  * The update() method and the left-shift operator are overridden by
94  * each implementation subclass. (One should be an alias for the
95  * other)
96  */
97 static VALUE
98 rb_digest_instance_update(VALUE self, VALUE str)
99 {
100     rb_raise(rb_eRuntimeError, "%s does not implement update()", RSTRING_PTR(rb_inspect(self)));
101 }
102
103 /*
104  * call-seq:
105  *     digest_obj.instance_eval { finish } -> digest_obj
106  *
107  * Finishes the digest and returns the resulting hash value.
108  *
109  * This method is overridden by each implementation subclass and often
110  * made private, because some of those subclasses may leave internal
111  * data uninitialized.  Do not call this method from outside.  Use
112  * #digest!() instead, which ensures that internal data be reset for
113  * security reasons.
114  */
115 static VALUE
116 rb_digest_instance_finish(VALUE self)
117 {
118     rb_raise(rb_eRuntimeError, "%s does not implement finish()", RSTRING_PTR(rb_inspect(self)));
119 }
120
121 /*
122  * call-seq:
123  *     digest_obj.reset -> digest_obj
124  *
125  * Resets the digest to the initial state and returns self.
126  *
127  * This method is overridden by each implementation subclass.
128  */
129 static VALUE
130 rb_digest_instance_reset(VALUE self)
131 {
132     rb_raise(rb_eRuntimeError, "%s does not implement reset()", RSTRING_PTR(rb_inspect(self)));
133 }
134
135 /*
136  * call-seq:
137  *     digest_obj.new -> another_digest_obj
138  *
139  * Returns a new, initialized copy of the digest object.  Equivalent
140  * to digest_obj.clone().reset().
141  */
142 static VALUE
143 rb_digest_instance_new(VALUE self)
144 {
145     VALUE clone = rb_obj_clone(self);
146     rb_funcall(clone, id_reset, 0);
147     return clone;
148 }
149
150 /*
151  * call-seq:
152  *     digest_obj.digest -> string
153  *     digest_obj.digest(string) -> string
154  *
155  * If none is given, returns the resulting hash value of the digest,
156  * keeping the digest's state.
157  *
158  * If a _string_ is given, returns the hash value for the given
159  * _string_, resetting the digest to the initial state before and
160  * after the process.
161  */
162 static VALUE
163 rb_digest_instance_digest(int argc, VALUE *argv, VALUE self)
164 {
165     VALUE str, value;
166
167     if (rb_scan_args(argc, argv, "01", &str) > 0) {
168         rb_funcall(self, id_reset, 0);
169         rb_funcall(self, id_update, 1, str);
170         value = rb_funcall(self, id_finish, 0);
171         rb_funcall(self, id_reset, 0);
172     } else {
173         VALUE clone = rb_obj_clone(self);
174
175         value = rb_funcall(clone, id_finish, 0);
176         rb_funcall(clone, id_reset, 0);
177     }
178
179     return value;
180 }
181
182 /*
183  * call-seq:
184  *     digest_obj.digest! -> string
185  *
186  * Returns the resulting hash value and resets the digest to the
187  * initial state.
188  */
189 static VALUE
190 rb_digest_instance_digest_bang(VALUE self)
191 {
192     VALUE value = rb_funcall(self, id_finish, 0);
193     rb_funcall(self, id_reset, 0);
194
195     return value;
196 }
197
198 /*
199  * call-seq:
200  *     digest_obj.hexdigest -> string
201  *     digest_obj.hexdigest(string) -> string
202  *
203  * If none is given, returns the resulting hash value of the digest in
204  * a hex-encoded form, keeping the digest's state.
205  *
206  * If a _string_ is given, returns the hash value for the given
207  * _string_ in a hex-encoded form, resetting the digest to the initial
208  * state before and after the process.
209  */
210 static VALUE
211 rb_digest_instance_hexdigest(int argc, VALUE *argv, VALUE self)
212 {
213     VALUE str, value;
214
215     if (rb_scan_args(argc, argv, "01", &str) > 0) {
216         rb_funcall(self, id_reset, 0);
217         rb_funcall(self, id_update, 1, str);
218         value = rb_funcall(self, id_finish, 0);
219         rb_funcall(self, id_reset, 0);
220     } else {
221         VALUE clone = rb_obj_clone(self);
222
223         value = rb_funcall(clone, id_finish, 0);
224         rb_funcall(clone, id_reset, 0);
225     }
226
227     return hexencode_str_new(value);
228 }
229
230 /*
231  * call-seq:
232  *     digest_obj.hexdigest! -> string
233  *
234  * Returns the resulting hash value and resets the digest to the
235  * initial state.
236  */
237 static VALUE
238 rb_digest_instance_hexdigest_bang(VALUE self)
239 {
240     VALUE value = rb_funcall(self, id_finish, 0);
241     rb_funcall(self, id_reset, 0);
242
243     return hexencode_str_new(value);
244 }
245
246 /*
247  * call-seq:
248  *     digest_obj.to_s -> string
249  *
250  * Returns digest_obj.hexdigest().
251  */
252 static VALUE
253 rb_digest_instance_to_s(VALUE self)
254 {
255     return rb_funcall(self, id_hexdigest, 0);
256 }
257
258 /*
259  * call-seq:
260  *     digest_obj.inspect -> string
261  *
262  * Creates a printable version of the digest object.
263  */
264 static VALUE
265 rb_digest_instance_inspect(VALUE self)
266 {
267     VALUE str;
268     size_t digest_len = 32;     /* about this size at least */
269     const char *cname;
270
271     cname = rb_obj_classname(self);
272
273     /* #<Digest::ClassName: xxxxx...xxxx> */
274     str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
275     rb_str_buf_cat2(str, "#<");
276     rb_str_buf_cat2(str, cname);
277     rb_str_buf_cat2(str, ": ");
278     rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
279     rb_str_buf_cat2(str, ">");
280     return str;
281 }
282
283 /*
284  * call-seq:
285  *     digest_obj == another_digest_obj -> boolean
286  *     digest_obj == string -> boolean
287  *
288  * If a string is given, checks whether it is equal to the hex-encoded
289  * hash value of the digest object.  If another digest instance is
290  * given, checks whether they have the same hash value.  Otherwise
291  * returns false.
292  */
293 static VALUE
294 rb_digest_instance_equal(VALUE self, VALUE other)
295 {
296     VALUE str1, str2;
297
298     if (rb_obj_is_kind_of(other, rb_mDigest_Instance) == Qtrue) {
299         str1 = rb_digest_instance_digest(0, 0, self);
300         str2 = rb_digest_instance_digest(0, 0, other);
301     } else {
302         str1 = rb_digest_instance_to_s(self);
303         str2 = other;
304     }
305
306     /* never blindly assume that subclass methods return strings */
307     StringValue(str1);
308     StringValue(str2);
309
310     if (RSTRING_LEN(str1) == RSTRING_LEN(str2) &&
311         rb_str_cmp(str1, str2) == 0) {
312         return Qtrue;
313     }
314     return Qfalse;
315 }
316
317 /*
318  * call-seq:
319  *     digest_obj.digest_length -> integer
320  *
321  * Returns the length of the hash value of the digest.
322  *
323  * This method should be overridden by each implementation subclass.
324  * If not, digest_obj.digest().length() is returned.
325  */
326 static VALUE
327 rb_digest_instance_digest_length(VALUE self)
328 {
329     /* subclasses really should redefine this method */
330     VALUE digest = rb_digest_instance_digest(0, 0, self);
331
332     /* never blindly assume that #digest() returns a string */
333     StringValue(digest);
334     return INT2NUM(RSTRING_LEN(digest));
335 }
336
337 /*
338  * call-seq:
339  *     digest_obj.length -> integer
340  *     digest_obj.size -> integer
341  *
342  * Returns digest_obj.digest_length().
343  */
344 static VALUE
345 rb_digest_instance_length(VALUE self)
346 {
347     return rb_funcall(self, id_digest_length, 0);
348 }
349
350 /*
351  * call-seq:
352  *     digest_obj.block_length -> integer
353  *
354  * Returns the block length of the digest.
355  *
356  * This method is overridden by each implementation subclass.
357  */
358 static VALUE
359 rb_digest_instance_block_length(VALUE self)
360 {
361     rb_raise(rb_eRuntimeError, "%s does not implement block_length()", RSTRING_PTR(rb_inspect(self)));
362 }
363
364 /*
365  * Document-class: Digest::Class
366  *
367  * This module stands as a base class for digest implementation
368  * classes.
369  */
370
371 /*
372  * call-seq:
373  *     Digest::Class.digest(string, *parameters) -> hash_string
374  *
375  * Returns the hash value of a given _string_.  This is equivalent to
376  * Digest::Class.new(*parameters).digest(string), where extra
377  * _parameters_, if any, are passed through to the constructor and the
378  * _string_ is passed to #digest().
379  */
380 static VALUE
381 rb_digest_class_s_digest(int argc, VALUE *argv, VALUE klass)
382 {
383     VALUE str;
384     volatile VALUE obj;
385
386     if (argc < 1) {
387         rb_raise(rb_eArgError, "no data given");
388     }
389
390     str = *argv++;
391     argc--;
392
393     StringValue(str);
394
395     obj = rb_obj_alloc(klass);
396     rb_obj_call_init(obj, argc, argv);
397
398     return rb_funcall(obj, id_digest, 1, str);
399 }
400
401 /*
402  * call-seq:
403  *     Digest::Class.hexdigest(string[, ...]) -> hash_string
404  *
405  * Returns the hex-encoded hash value of a given _string_.  This is
406  * almost equivalent to
407  * Digest.hexencode(Digest::Class.new(*parameters).digest(string)).
408  */
409 static VALUE
410 rb_digest_class_s_hexdigest(int argc, VALUE *argv, VALUE klass)
411 {
412     return hexencode_str_new(rb_funcall2(klass, id_digest, argc, argv));
413 }
414
415 /*
416  * Document-class: Digest::Base
417  *
418  * This abstract class provides a common interface to message digest
419  * implementation classes written in C.
420  */
421
422 static rb_digest_metadata_t *
423 get_digest_base_metadata(VALUE klass)
424 {
425     VALUE p;
426     VALUE obj;
427     rb_digest_metadata_t *algo;
428
429     for (p = klass; p; p = RCLASS_SUPER(p)) {
430         if (rb_ivar_defined(p, id_metadata)) {
431             obj = rb_ivar_get(p, id_metadata);
432             break;
433         }
434     }
435
436     if (!p)
437         rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
438
439     Data_Get_Struct(obj, rb_digest_metadata_t, algo);
440
441     switch (algo->api_version) {
442       case 2:
443         break;
444
445       /*
446        * put conversion here if possible when API is updated
447        */
448
449       default:
450         rb_raise(rb_eRuntimeError, "Incompatible digest API version");
451     }
452
453     return algo;
454 }
455
456 static VALUE
457 rb_digest_base_alloc(VALUE klass)
458 {
459     rb_digest_metadata_t *algo;
460     VALUE obj;
461     void *pctx;
462
463     if (klass == rb_cDigest_Base) {
464         rb_raise(rb_eNotImpError, "Digest::Base is an abstract class");
465     }
466
467     algo = get_digest_base_metadata(klass);
468
469     pctx = xmalloc(algo->ctx_size);
470     algo->init_func(pctx);
471
472     obj = Data_Wrap_Struct(klass, 0, xfree, pctx);
473
474     return obj;
475 }
476
477 /* :nodoc: */
478 static VALUE
479 rb_digest_base_copy(VALUE copy, VALUE obj)
480 {
481     rb_digest_metadata_t *algo;
482     void *pctx1, *pctx2;
483
484     if (copy == obj) return copy;
485
486     rb_check_frozen(copy);
487
488     algo = get_digest_base_metadata(rb_obj_class(copy));
489
490     Data_Get_Struct(obj, void, pctx1);
491     Data_Get_Struct(copy, void, pctx2);
492     memcpy(pctx2, pctx1, algo->ctx_size);
493
494     return copy;
495 }
496
497 /* :nodoc: */
498 static VALUE
499 rb_digest_base_reset(VALUE self)
500 {
501     rb_digest_metadata_t *algo;
502     void *pctx;
503
504     algo = get_digest_base_metadata(rb_obj_class(self));
505
506     Data_Get_Struct(self, void, pctx);
507
508     algo->init_func(pctx);
509
510     return self;
511 }
512
513 /* :nodoc: */
514 static VALUE
515 rb_digest_base_update(VALUE self, VALUE str)
516 {
517     rb_digest_metadata_t *algo;
518     void *pctx;
519
520     algo = get_digest_base_metadata(rb_obj_class(self));
521
522     Data_Get_Struct(self, void, pctx);
523
524     StringValue(str);
525     algo->update_func(pctx, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str));
526
527     return self;
528 }
529
530 /* :nodoc: */
531 static VALUE
532 rb_digest_base_finish(VALUE self)
533 {
534     rb_digest_metadata_t *algo;
535     void *pctx;
536     VALUE str;
537
538     algo = get_digest_base_metadata(rb_obj_class(self));
539
540     Data_Get_Struct(self, void, pctx);
541
542     str = rb_str_new(0, algo->digest_len);
543     algo->finish_func(pctx, (unsigned char *)RSTRING_PTR(str));
544
545     /* avoid potential coredump caused by use of a finished context */
546     algo->init_func(pctx);
547
548     return str;
549 }
550
551 /* :nodoc: */
552 static VALUE
553 rb_digest_base_digest_length(VALUE self)
554 {
555     rb_digest_metadata_t *algo;
556
557     algo = get_digest_base_metadata(rb_obj_class(self));
558
559     return INT2NUM(algo->digest_len);
560 }
561
562 /* :nodoc: */
563 static VALUE
564 rb_digest_base_block_length(VALUE self)
565 {
566     rb_digest_metadata_t *algo;
567
568     algo = get_digest_base_metadata(rb_obj_class(self));
569
570     return INT2NUM(algo->block_len);
571 }
572
573 void
574 Init_digest(void)
575 {
576     id_reset           = rb_intern("reset");
577     id_update          = rb_intern("update");
578     id_finish          = rb_intern("finish");
579     id_digest          = rb_intern("digest");
580     id_hexdigest       = rb_intern("hexdigest");
581     id_digest_length   = rb_intern("digest_length");
582
583     /*
584      * module Digest
585      */
586     rb_mDigest = rb_define_module("Digest");
587
588     /* module functions */
589     rb_define_module_function(rb_mDigest, "hexencode", rb_digest_s_hexencode, 1);
590
591     /*
592      * module Digest::Instance
593      */
594     rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
595
596     /* instance methods that should be overridden */
597     rb_define_method(rb_mDigest_Instance, "update", rb_digest_instance_update, 1);
598     rb_define_method(rb_mDigest_Instance, "<<", rb_digest_instance_update, 1);
599     rb_define_private_method(rb_mDigest_Instance, "finish", rb_digest_instance_finish, 0);
600     rb_define_method(rb_mDigest_Instance, "reset", rb_digest_instance_reset, 0);
601     rb_define_method(rb_mDigest_Instance, "digest_length", rb_digest_instance_digest_length, 0);
602     rb_define_method(rb_mDigest_Instance, "block_length", rb_digest_instance_block_length, 0);
603
604     /* instance methods that may be overridden */
605     rb_define_method(rb_mDigest_Instance, "==", rb_digest_instance_equal, 1);
606     rb_define_method(rb_mDigest_Instance, "inspect", rb_digest_instance_inspect, 0);
607
608     /* instance methods that need not usually be overridden */
609     rb_define_method(rb_mDigest_Instance, "new", rb_digest_instance_new, 0);
610     rb_define_method(rb_mDigest_Instance, "digest", rb_digest_instance_digest, -1);
611     rb_define_method(rb_mDigest_Instance, "digest!", rb_digest_instance_digest_bang, 0);
612     rb_define_method(rb_mDigest_Instance, "hexdigest", rb_digest_instance_hexdigest, -1);
613     rb_define_method(rb_mDigest_Instance, "hexdigest!", rb_digest_instance_hexdigest_bang, 0);
614     rb_define_method(rb_mDigest_Instance, "to_s", rb_digest_instance_to_s, 0);
615     rb_define_method(rb_mDigest_Instance, "length", rb_digest_instance_length, 0);
616     rb_define_method(rb_mDigest_Instance, "size", rb_digest_instance_length, 0);
617
618     /*
619      * class Digest::Class
620      */
621     rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
622     rb_include_module(rb_cDigest_Class, rb_mDigest_Instance);
623
624     /* class methods */
625     rb_define_singleton_method(rb_cDigest_Class, "digest", rb_digest_class_s_digest, -1);
626     rb_define_singleton_method(rb_cDigest_Class, "hexdigest", rb_digest_class_s_hexdigest, -1);
627
628     id_metadata = rb_intern("metadata");
629
630     /* class Digest::Base < Digest::Class */
631     rb_cDigest_Base = rb_define_class_under(rb_mDigest, "Base", rb_cDigest_Class);
632
633     rb_define_alloc_func(rb_cDigest_Base, rb_digest_base_alloc);
634
635     rb_define_method(rb_cDigest_Base, "initialize_copy",  rb_digest_base_copy, 1);
636     rb_define_method(rb_cDigest_Base, "reset", rb_digest_base_reset, 0);
637     rb_define_method(rb_cDigest_Base, "update", rb_digest_base_update, 1);
638     rb_define_method(rb_cDigest_Base, "<<", rb_digest_base_update, 1);
639     rb_define_private_method(rb_cDigest_Base, "finish", rb_digest_base_finish, 0);
640     rb_define_method(rb_cDigest_Base, "digest_length", rb_digest_base_digest_length, 0);
641     rb_define_method(rb_cDigest_Base, "block_length", rb_digest_base_block_length, 0);
642 }