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