00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "ruby.h"
00015 #include "../digest.h"
00016
00017 static ID id_digest;
00018
00019 static VALUE
00020 bubblebabble_str_new(VALUE str_digest)
00021 {
00022 char *digest;
00023 size_t digest_len;
00024 VALUE str;
00025 char *p;
00026 size_t i, j, seed = 1;
00027 static const char vowels[] = {
00028 'a', 'e', 'i', 'o', 'u', 'y'
00029 };
00030 static const char consonants[] = {
00031 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n',
00032 'p', 'r', 's', 't', 'v', 'z', 'x'
00033 };
00034
00035 StringValue(str_digest);
00036 digest = RSTRING_PTR(str_digest);
00037 digest_len = RSTRING_LEN(str_digest);
00038
00039 if ((LONG_MAX - 2) / 3 < (digest_len | 1)) {
00040 rb_raise(rb_eRuntimeError, "digest string too long");
00041 }
00042
00043 str = rb_str_new(0, (digest_len | 1) * 3 + 2);
00044 p = RSTRING_PTR(str);
00045
00046 i = j = 0;
00047 p[j++] = 'x';
00048
00049 for (;;) {
00050 unsigned char byte1, byte2;
00051
00052 if (i >= digest_len) {
00053 p[j++] = vowels[seed % 6];
00054 p[j++] = consonants[16];
00055 p[j++] = vowels[seed / 6];
00056 break;
00057 }
00058
00059 byte1 = digest[i++];
00060 p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6];
00061 p[j++] = consonants[(byte1 >> 2) & 15];
00062 p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6];
00063
00064 if (i >= digest_len) {
00065 break;
00066 }
00067
00068 byte2 = digest[i++];
00069 p[j++] = consonants[(byte2 >> 4) & 15];
00070 p[j++] = '-';
00071 p[j++] = consonants[byte2 & 15];
00072
00073 seed = (seed * 5 + byte1 * 7 + byte2) % 36;
00074 }
00075
00076 p[j] = 'x';
00077
00078 return str;
00079 }
00080
00081
00082
00083
00084
00085
00086
00087 static VALUE
00088 rb_digest_s_bubblebabble(VALUE klass, VALUE str)
00089 {
00090 return bubblebabble_str_new(str);
00091 }
00092
00093
00094
00095
00096
00097
00098
00099 static VALUE
00100 rb_digest_class_s_bubblebabble(int argc, VALUE *argv, VALUE klass)
00101 {
00102 return bubblebabble_str_new(rb_funcall2(klass, id_digest, argc, argv));
00103 }
00104
00105
00106
00107
00108
00109
00110
00111 static VALUE
00112 rb_digest_instance_bubblebabble(VALUE self)
00113 {
00114 return bubblebabble_str_new(rb_funcall(self, id_digest, 0));
00115 }
00116
00117
00118
00119
00120
00121 void
00122 Init_bubblebabble(void)
00123 {
00124 VALUE mDigest, mDigest_Instance, cDigest_Class;
00125
00126 rb_require("digest");
00127
00128 mDigest = rb_path2class("Digest");
00129 mDigest_Instance = rb_path2class("Digest::Instance");
00130 cDigest_Class = rb_path2class("Digest::Class");
00131
00132
00133 rb_define_module_function(mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
00134
00135
00136 rb_define_singleton_method(cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1);
00137
00138
00139 rb_define_method(mDigest_Instance, "bubblebabble", rb_digest_instance_bubblebabble, 0);
00140
00141 id_digest = rb_intern("digest");
00142 }
00143