00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <glib.h>
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <unistd.h>
00022 #include <sys/time.h>
00023 #include <errno.h>
00024
00025 #include "xmmsc/xmmsc_idnumbers.h"
00026 #include "xmmsc/xmmsc_ipc_transport.h"
00027 #include "xmmsc/xmmsc_ipc_msg.h"
00028
00029 #include "xmms/xmms_log.h"
00030
00031 #include "xmmspriv/xmms_ringbuf.h"
00032 #include "xmmspriv/xmms_ipc.h"
00033 #include "xmmspriv/xmms_playlist.h"
00034 #include "xmmspriv/xmms_config.h"
00035 #include "xmmspriv/xmms_bindata.h"
00036 #include "xmmspriv/xmms_utils.h"
00037
00038 struct xmms_bindata_St {
00039 xmms_object_t obj;
00040 const gchar *bindir;
00041 };
00042
00043 static xmms_bindata_t *global_bindata;
00044
00045 static void xmms_bindata_destroy (xmms_object_t *obj);
00046
00047 typedef unsigned char md5_byte_t;
00048 typedef unsigned int md5_word_t;
00049
00050
00051 typedef struct md5_state_s {
00052 md5_word_t count[2];
00053 md5_word_t abcd[4];
00054 md5_byte_t buf[64];
00055 } md5_state_t;
00056
00057
00058 static void md5_init (md5_state_t *pms);
00059 static void md5_append (md5_state_t *pms, const md5_byte_t *data, int nbytes);
00060 static void md5_finish (md5_state_t *pms, md5_byte_t digest[16]);
00061
00062 static gchar *xmms_bindata_build_path (xmms_bindata_t *bindata, const gchar *hash);
00063
00064 static gchar *xmms_bindata_add (xmms_bindata_t *bindata, GString *data, xmms_error_t *err);
00065 static xmmsv_t *xmms_bindata_retrieve (xmms_bindata_t *bindata, const gchar *hash, xmms_error_t *err);
00066 static void xmms_bindata_remove (xmms_bindata_t *bindata, const gchar *hash, xmms_error_t *);
00067 static GList *xmms_bindata_list (xmms_bindata_t *bindata, xmms_error_t *err);
00068 static gboolean _xmms_bindata_add (xmms_bindata_t *bindata, const guchar *data, gsize len, gchar hash[33], xmms_error_t *err);
00069
00070 XMMS_CMD_DEFINE (get_data, xmms_bindata_retrieve, xmms_bindata_t *, BIN, STRING, NONE);
00071 XMMS_CMD_DEFINE (add_data, xmms_bindata_add, xmms_bindata_t *, STRING, BIN, NONE);
00072 XMMS_CMD_DEFINE (remove_data, xmms_bindata_remove, xmms_bindata_t *, NONE, STRING, NONE);
00073 XMMS_CMD_DEFINE (list_data, xmms_bindata_list, xmms_bindata_t *, LIST, NONE, NONE);
00074
00075 xmms_bindata_t *
00076 xmms_bindata_init ()
00077 {
00078 gchar *tmp;
00079 xmms_bindata_t *obj;
00080 xmms_config_property_t *cv;
00081
00082 obj = xmms_object_new (xmms_bindata_t, xmms_bindata_destroy);
00083
00084 xmms_object_cmd_add (XMMS_OBJECT (obj),
00085 XMMS_IPC_CMD_ADD_DATA,
00086 XMMS_CMD_FUNC (add_data));
00087
00088 xmms_object_cmd_add (XMMS_OBJECT (obj),
00089 XMMS_IPC_CMD_REMOVE_DATA,
00090 XMMS_CMD_FUNC (remove_data));
00091
00092 xmms_object_cmd_add (XMMS_OBJECT (obj),
00093 XMMS_IPC_CMD_GET_DATA,
00094 XMMS_CMD_FUNC (get_data));
00095
00096 xmms_object_cmd_add (XMMS_OBJECT (obj),
00097 XMMS_IPC_CMD_LIST_DATA,
00098 XMMS_CMD_FUNC (list_data));
00099
00100 xmms_ipc_object_register (XMMS_IPC_OBJECT_BINDATA, XMMS_OBJECT (obj));
00101
00102 tmp = XMMS_BUILD_PATH ("bindata");
00103 cv = xmms_config_property_register ("bindata.path", tmp, NULL, NULL);
00104 g_free (tmp);
00105
00106 obj->bindir = xmms_config_property_get_string (cv);
00107
00108 if (!g_file_test (obj->bindir, G_FILE_TEST_IS_DIR)) {
00109 if (g_mkdir_with_parents (obj->bindir, 0755) == -1) {
00110 xmms_log_error ("Couldn't create bindir %s", obj->bindir);
00111 }
00112 }
00113
00114 global_bindata = obj;
00115
00116 return obj;
00117 }
00118
00119 static void
00120 xmms_bindata_destroy (xmms_object_t *obj)
00121 {
00122 xmms_ipc_object_unregister (XMMS_IPC_OBJECT_BINDATA);
00123 }
00124
00125 gchar *
00126 xmms_bindata_calculate_md5 (const guchar *data, guint size, gchar ret[33])
00127 {
00128 md5_state_t state;
00129 md5_byte_t digest[16];
00130 int di;
00131 static gchar hex[] = {
00132 '0', '1', '2', '3', '4', '5', '6', '7',
00133 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
00134 };
00135
00136 md5_init (&state);
00137 md5_append (&state, (const md5_byte_t *)data, size);
00138 md5_finish (&state, digest);
00139
00140 for (di = 0; di < 16; ++di) {
00141 ret[di * 2] = hex[digest[di] >> 4];
00142 ret[di * 2 + 1] = hex[digest[di] & 0x0f];
00143 }
00144 ret[32] = 0;
00145 return ret;
00146 }
00147
00148 static gchar *
00149 xmms_bindata_build_path (xmms_bindata_t *bindata, const gchar *hash)
00150 {
00151 return g_build_path (G_DIR_SEPARATOR_S, bindata->bindir, hash, NULL);
00152 }
00153
00154
00155 gboolean
00156 xmms_bindata_plugin_add (const guchar *data, gsize size, gchar hash[33])
00157 {
00158 xmms_error_t err;
00159 return _xmms_bindata_add (global_bindata, data, size, hash, &err);
00160 }
00161
00162 static gboolean
00163 _xmms_bindata_add (xmms_bindata_t *bindata, const guchar *data, gsize len, gchar hash[33], xmms_error_t *err)
00164 {
00165 const guchar *ptr;
00166 gsize left;
00167 gchar *path;
00168 FILE *fp;
00169
00170 xmms_bindata_calculate_md5 (data, len, hash);
00171
00172 path = xmms_bindata_build_path (bindata, hash);
00173
00174 if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
00175 XMMS_DBG ("file %s is already in bindata dir", hash);
00176 g_free (path);
00177 return TRUE;
00178 }
00179
00180 XMMS_DBG ("Creating %s", path);
00181 fp = fopen (path, "wb");
00182 if (!fp) {
00183 xmms_log_error ("Couldn't create %s", path);
00184 xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't create file on server!");
00185 g_free (path);
00186 return FALSE;
00187 }
00188
00189
00190 ptr = data;
00191 left = len;
00192
00193 while (left > 0) {
00194 size_t w;
00195
00196 w = fwrite (ptr, 1, left, fp);
00197 if (!w && ferror (fp)) {
00198 fclose (fp);
00199 unlink (path);
00200
00201 xmms_log_error ("Couldn't write data");
00202 xmms_error_set (err, XMMS_ERROR_GENERIC,
00203 "Couldn't write data!");
00204 g_free (path);
00205 return FALSE;
00206 }
00207
00208 left -= w;
00209 ptr += w;
00210 }
00211
00212 fclose (fp);
00213 g_free (path);
00214
00215 return TRUE;
00216 }
00217
00218 char *
00219 xmms_bindata_add (xmms_bindata_t *bindata, GString *data, xmms_error_t *err)
00220 {
00221 gchar hash[33];
00222 if (_xmms_bindata_add (bindata, (guchar *)data->str, data->len, hash, err))
00223 return g_strdup (hash);
00224 return NULL;
00225 }
00226
00227 static xmmsv_t *
00228 xmms_bindata_retrieve (xmms_bindata_t *bindata, const gchar *hash,
00229 xmms_error_t *err)
00230 {
00231 xmmsv_t *res;
00232 gchar *path;
00233 GString *str;
00234 FILE *fp;
00235
00236 path = xmms_bindata_build_path (bindata, hash);
00237
00238 fp = fopen (path, "rb");
00239 if (!fp) {
00240 xmms_log_error ("Requesting '%s' which is not on the server", hash);
00241 xmms_error_set (err, XMMS_ERROR_NOENT, "File not found!");
00242 g_free (path);
00243 return NULL;
00244 }
00245
00246 g_free (path);
00247
00248 str = g_string_new (NULL);
00249 while (!feof (fp)) {
00250 gchar buf[1024];
00251 gint l;
00252
00253 l = fread (buf, 1, 1024, fp);
00254 if (ferror (fp)) {
00255 g_string_free (str, TRUE);
00256 xmms_log_error ("Error reading bindata '%s'", hash);
00257 xmms_error_set (err, XMMS_ERROR_GENERIC, "Error reading file");
00258 return NULL;
00259 }
00260 g_string_append_len (str, buf, l);
00261 }
00262
00263 fclose (fp);
00264
00265 res = xmmsv_new_bin ((unsigned char *)str->str, str->len);
00266
00267 g_string_free (str, TRUE);
00268
00269 return res;
00270 }
00271
00272 static void
00273 xmms_bindata_remove (xmms_bindata_t *bindata, const gchar *hash,
00274 xmms_error_t *err)
00275 {
00276 gchar *path;
00277 path = xmms_bindata_build_path (bindata, hash);
00278 if (unlink (path) == -1) {
00279 xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't remove file");
00280 }
00281 g_free (path);
00282 return;
00283 }
00284
00285 static GList *
00286 xmms_bindata_list (xmms_bindata_t *bindata, xmms_error_t *err)
00287 {
00288 GList *entries = NULL;
00289 gchar *path;
00290 const gchar *file;
00291 GDir *dir;
00292
00293 path = xmms_bindata_build_path (bindata, NULL);
00294 dir = g_dir_open (path, 0, NULL);
00295 g_free (path);
00296
00297 if (!dir) {
00298 xmms_error_set (err, XMMS_ERROR_GENERIC,
00299 "Couldn't open bindata directory");
00300 return NULL;
00301 }
00302
00303 while ((file = g_dir_read_name (dir))) {
00304 entries = g_list_prepend (entries, xmmsv_new_string (file));
00305 }
00306
00307 g_dir_close (dir);
00308
00309 return entries;
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 #undef BYTE_ORDER
00376 #ifdef ARCH_IS_BIG_ENDIAN
00377 # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
00378 #else
00379 # define BYTE_ORDER 0
00380 #endif
00381
00382 #define T_MASK ((md5_word_t)~0)
00383 #define T1 (T_MASK ^ 0x28955b87)
00384 #define T2 (T_MASK ^ 0x173848a9)
00385 #define T3 0x242070db
00386 #define T4 (T_MASK ^ 0x3e423111)
00387 #define T5 (T_MASK ^ 0x0a83f050)
00388 #define T6 0x4787c62a
00389 #define T7 (T_MASK ^ 0x57cfb9ec)
00390 #define T8 (T_MASK ^ 0x02b96afe)
00391 #define T9 0x698098d8
00392 #define T10 (T_MASK ^ 0x74bb0850)
00393 #define T11 (T_MASK ^ 0x0000a44e)
00394 #define T12 (T_MASK ^ 0x76a32841)
00395 #define T13 0x6b901122
00396 #define T14 (T_MASK ^ 0x02678e6c)
00397 #define T15 (T_MASK ^ 0x5986bc71)
00398 #define T16 0x49b40821
00399 #define T17 (T_MASK ^ 0x09e1da9d)
00400 #define T18 (T_MASK ^ 0x3fbf4cbf)
00401 #define T19 0x265e5a51
00402 #define T20 (T_MASK ^ 0x16493855)
00403 #define T21 (T_MASK ^ 0x29d0efa2)
00404 #define T22 0x02441453
00405 #define T23 (T_MASK ^ 0x275e197e)
00406 #define T24 (T_MASK ^ 0x182c0437)
00407 #define T25 0x21e1cde6
00408 #define T26 (T_MASK ^ 0x3cc8f829)
00409 #define T27 (T_MASK ^ 0x0b2af278)
00410 #define T28 0x455a14ed
00411 #define T29 (T_MASK ^ 0x561c16fa)
00412 #define T30 (T_MASK ^ 0x03105c07)
00413 #define T31 0x676f02d9
00414 #define T32 (T_MASK ^ 0x72d5b375)
00415 #define T33 (T_MASK ^ 0x0005c6bd)
00416 #define T34 (T_MASK ^ 0x788e097e)
00417 #define T35 0x6d9d6122
00418 #define T36 (T_MASK ^ 0x021ac7f3)
00419 #define T37 (T_MASK ^ 0x5b4115bb)
00420 #define T38 0x4bdecfa9
00421 #define T39 (T_MASK ^ 0x0944b49f)
00422 #define T40 (T_MASK ^ 0x4140438f)
00423 #define T41 0x289b7ec6
00424 #define T42 (T_MASK ^ 0x155ed805)
00425 #define T43 (T_MASK ^ 0x2b10cf7a)
00426 #define T44 0x04881d05
00427 #define T45 (T_MASK ^ 0x262b2fc6)
00428 #define T46 (T_MASK ^ 0x1924661a)
00429 #define T47 0x1fa27cf8
00430 #define T48 (T_MASK ^ 0x3b53a99a)
00431 #define T49 (T_MASK ^ 0x0bd6ddbb)
00432 #define T50 0x432aff97
00433 #define T51 (T_MASK ^ 0x546bdc58)
00434 #define T52 (T_MASK ^ 0x036c5fc6)
00435 #define T53 0x655b59c3
00436 #define T54 (T_MASK ^ 0x70f3336d)
00437 #define T55 (T_MASK ^ 0x00100b82)
00438 #define T56 (T_MASK ^ 0x7a7ba22e)
00439 #define T57 0x6fa87e4f
00440 #define T58 (T_MASK ^ 0x01d3191f)
00441 #define T59 (T_MASK ^ 0x5cfebceb)
00442 #define T60 0x4e0811a1
00443 #define T61 (T_MASK ^ 0x08ac817d)
00444 #define T62 (T_MASK ^ 0x42c50dca)
00445 #define T63 0x2ad7d2bb
00446 #define T64 (T_MASK ^ 0x14792c6e)
00447
00448
00449 static void
00450 md5_process (md5_state_t *pms, const md5_byte_t *data )
00451 {
00452 md5_word_t
00453 a = pms->abcd[0], b = pms->abcd[1],
00454 c = pms->abcd[2], d = pms->abcd[3];
00455 md5_word_t t;
00456 #if BYTE_ORDER > 0
00457
00458 md5_word_t X[16];
00459 #else
00460
00461 md5_word_t xbuf[16];
00462 const md5_word_t *X;
00463 #endif
00464
00465 {
00466 #if BYTE_ORDER == 0
00467
00468
00469
00470
00471
00472 static const int w = 1;
00473
00474 if (*((const md5_byte_t *)&w))
00475 #endif
00476 #if BYTE_ORDER <= 0
00477 {
00478
00479
00480
00481
00482 if (!((data - (const md5_byte_t *)0) & 3)) {
00483
00484 X = (const md5_word_t *)data;
00485 } else {
00486
00487 memcpy (xbuf, data, 64);
00488 X = xbuf;
00489 }
00490 }
00491 #endif
00492 #if BYTE_ORDER == 0
00493 else
00494 #endif
00495 #if BYTE_ORDER >= 0
00496 {
00497
00498
00499
00500
00501 const md5_byte_t *xp = data;
00502 int i;
00503
00504 # if BYTE_ORDER == 0
00505 X = xbuf;
00506 # else
00507 # define xbuf X
00508 # endif
00509 for (i = 0; i < 16; ++i, xp += 4)
00510 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
00511 }
00512 #endif
00513 }
00514
00515 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
00516
00517
00518
00519
00520 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
00521 #define SET(a, b, c, d, k, s, Ti)\
00522 t = a + F (b,c,d) + X[k] + Ti;\
00523 a = ROTATE_LEFT (t, s) + b
00524
00525 SET (a, b, c, d, 0, 7, T1);
00526 SET (d, a, b, c, 1, 12, T2);
00527 SET (c, d, a, b, 2, 17, T3);
00528 SET (b, c, d, a, 3, 22, T4);
00529 SET (a, b, c, d, 4, 7, T5);
00530 SET (d, a, b, c, 5, 12, T6);
00531 SET (c, d, a, b, 6, 17, T7);
00532 SET (b, c, d, a, 7, 22, T8);
00533 SET (a, b, c, d, 8, 7, T9);
00534 SET (d, a, b, c, 9, 12, T10);
00535 SET (c, d, a, b, 10, 17, T11);
00536 SET (b, c, d, a, 11, 22, T12);
00537 SET (a, b, c, d, 12, 7, T13);
00538 SET (d, a, b, c, 13, 12, T14);
00539 SET (c, d, a, b, 14, 17, T15);
00540 SET (b, c, d, a, 15, 22, T16);
00541 #undef SET
00542
00543
00544
00545
00546 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
00547 #define SET(a, b, c, d, k, s, Ti)\
00548 t = a + G (b,c,d) + X[k] + Ti;\
00549 a = ROTATE_LEFT (t, s) + b
00550
00551 SET (a, b, c, d, 1, 5, T17);
00552 SET (d, a, b, c, 6, 9, T18);
00553 SET (c, d, a, b, 11, 14, T19);
00554 SET (b, c, d, a, 0, 20, T20);
00555 SET (a, b, c, d, 5, 5, T21);
00556 SET (d, a, b, c, 10, 9, T22);
00557 SET (c, d, a, b, 15, 14, T23);
00558 SET (b, c, d, a, 4, 20, T24);
00559 SET (a, b, c, d, 9, 5, T25);
00560 SET (d, a, b, c, 14, 9, T26);
00561 SET (c, d, a, b, 3, 14, T27);
00562 SET (b, c, d, a, 8, 20, T28);
00563 SET (a, b, c, d, 13, 5, T29);
00564 SET (d, a, b, c, 2, 9, T30);
00565 SET (c, d, a, b, 7, 14, T31);
00566 SET (b, c, d, a, 12, 20, T32);
00567 #undef SET
00568
00569
00570
00571
00572 #define H(x, y, z) ((x) ^ (y) ^ (z))
00573 #define SET(a, b, c, d, k, s, Ti)\
00574 t = a + H (b,c,d) + X[k] + Ti;\
00575 a = ROTATE_LEFT (t, s) + b
00576
00577 SET (a, b, c, d, 5, 4, T33);
00578 SET (d, a, b, c, 8, 11, T34);
00579 SET (c, d, a, b, 11, 16, T35);
00580 SET (b, c, d, a, 14, 23, T36);
00581 SET (a, b, c, d, 1, 4, T37);
00582 SET (d, a, b, c, 4, 11, T38);
00583 SET (c, d, a, b, 7, 16, T39);
00584 SET (b, c, d, a, 10, 23, T40);
00585 SET (a, b, c, d, 13, 4, T41);
00586 SET (d, a, b, c, 0, 11, T42);
00587 SET (c, d, a, b, 3, 16, T43);
00588 SET (b, c, d, a, 6, 23, T44);
00589 SET (a, b, c, d, 9, 4, T45);
00590 SET (d, a, b, c, 12, 11, T46);
00591 SET (c, d, a, b, 15, 16, T47);
00592 SET (b, c, d, a, 2, 23, T48);
00593 #undef SET
00594
00595
00596
00597
00598 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
00599 #define SET(a, b, c, d, k, s, Ti)\
00600 t = a + I (b,c,d) + X[k] + Ti;\
00601 a = ROTATE_LEFT (t, s) + b
00602
00603 SET (a, b, c, d, 0, 6, T49);
00604 SET (d, a, b, c, 7, 10, T50);
00605 SET (c, d, a, b, 14, 15, T51);
00606 SET (b, c, d, a, 5, 21, T52);
00607 SET (a, b, c, d, 12, 6, T53);
00608 SET (d, a, b, c, 3, 10, T54);
00609 SET (c, d, a, b, 10, 15, T55);
00610 SET (b, c, d, a, 1, 21, T56);
00611 SET (a, b, c, d, 8, 6, T57);
00612 SET (d, a, b, c, 15, 10, T58);
00613 SET (c, d, a, b, 6, 15, T59);
00614 SET (b, c, d, a, 13, 21, T60);
00615 SET (a, b, c, d, 4, 6, T61);
00616 SET (d, a, b, c, 11, 10, T62);
00617 SET (c, d, a, b, 2, 15, T63);
00618 SET (b, c, d, a, 9, 21, T64);
00619 #undef SET
00620
00621
00622
00623
00624 pms->abcd[0] += a;
00625 pms->abcd[1] += b;
00626 pms->abcd[2] += c;
00627 pms->abcd[3] += d;
00628 }
00629
00630 static void
00631 md5_init (md5_state_t *pms)
00632 {
00633 pms->count[0] = pms->count[1] = 0;
00634 pms->abcd[0] = 0x67452301;
00635 pms->abcd[1] = T_MASK ^ 0x10325476;
00636 pms->abcd[2] = T_MASK ^ 0x67452301;
00637 pms->abcd[3] = 0x10325476;
00638 }
00639
00640 static void
00641 md5_append (md5_state_t *pms, const md5_byte_t *data, int nbytes)
00642 {
00643 const md5_byte_t *p = data;
00644 int left = nbytes;
00645 int offset = (pms->count[0] >> 3) & 63;
00646 md5_word_t nbits = (md5_word_t)(nbytes << 3);
00647
00648 if (nbytes <= 0)
00649 return;
00650
00651
00652 pms->count[1] += nbytes >> 29;
00653 pms->count[0] += nbits;
00654 if (pms->count[0] < nbits)
00655 pms->count[1]++;
00656
00657
00658 if (offset) {
00659 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
00660
00661 memcpy (pms->buf + offset, p, copy);
00662 if (offset + copy < 64)
00663 return;
00664 p += copy;
00665 left -= copy;
00666 md5_process (pms, pms->buf);
00667 }
00668
00669
00670 for (; left >= 64; p += 64, left -= 64)
00671 md5_process (pms, p);
00672
00673
00674 if (left)
00675 memcpy (pms->buf, p, left);
00676 }
00677
00678 static void
00679 md5_finish (md5_state_t *pms, md5_byte_t digest[16])
00680 {
00681 static const md5_byte_t pad[64] = {
00682 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00683 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00684 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00686 };
00687 md5_byte_t data[8];
00688 int i;
00689
00690
00691 for (i = 0; i < 8; ++i)
00692 data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
00693
00694 md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
00695
00696 md5_append (pms, data, 8);
00697 for (i = 0; i < 16; ++i)
00698 digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
00699 }