• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/xmms/bindata.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
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; /* 8-bit byte */
00048 typedef unsigned int md5_word_t; /* 32-bit word */
00049 
00050 /* Define the state of the MD5 Algorithm. */
00051 typedef struct md5_state_s {
00052     md5_word_t count[2]; /* message length in bits, lsw first */
00053     md5_word_t abcd[4];  /* digest buffer */
00054     md5_byte_t buf[64];  /* accumulate block */
00055 } md5_state_t;
00056 
00057 /* Initialize the algorithm. */
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 /** Add binary data from a plugin */
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     /* write the data to the file */
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   Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
00314 
00315   This software is provided 'as-is', without any express or implied
00316   warranty.  In no event will the authors be held liable for any damages
00317   arising from the use of this software.
00318 
00319   Permission is granted to anyone to use this software for any purpose,
00320   including commercial applications, and to alter it and redistribute it
00321   freely, subject to the following restrictions:
00322 
00323   1. The origin of this software must not be misrepresented; you must not
00324      claim that you wrote the original software. If you use this software
00325      in a product, an acknowledgment in the product documentation would be
00326      appreciated but is not required.
00327   2. Altered source versions must be plainly marked as such, and must not be
00328      misrepresented as being the original software.
00329   3. This notice may not be removed or altered from any source distribution.
00330 
00331   L. Peter Deutsch
00332   ghost@aladdin.com
00333 
00334  */
00335 /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
00336 /*
00337   Independent implementation of MD5 (RFC 1321).
00338 
00339   This code implements the MD5 Algorithm defined in RFC 1321, whose
00340   text is available at
00341     http://www.ietf.org/rfc/rfc1321.txt
00342   The code is derived from the text of the RFC, including the test suite
00343   (section A.5) but excluding the rest of Appendix A.  It does not include
00344   any code or documentation that is identified in the RFC as being
00345   copyrighted.
00346 
00347   The original and principal author of md5.c is L. Peter Deutsch
00348   <ghost@aladdin.com>.  Other authors are noted in the change history
00349   that follows (in reverse chronological order):
00350 
00351   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
00352     either statically or dynamically; added missing #include <string.h>
00353     in library.
00354   2002-03-11 lpd Corrected argument list for main(), and added int return
00355     type, in test program and T value program.
00356   2002-02-21 lpd Added missing #include <stdio.h> in test program.
00357   2000-07-03 lpd Patched to eliminate warnings about "constant is
00358     unsigned in ANSI C, signed in traditional"; made test program
00359     self-checking.
00360   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
00361   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
00362   1999-05-03 lpd Original version.
00363  */
00364 
00365 /*
00366  * This package supports both compile-time and run-time determination of CPU
00367  * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
00368  * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
00369  * defined as non-zero, the code will be compiled to run only on big-endian
00370  * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
00371  * run on either big- or little-endian CPUs, but will run slightly less
00372  * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
00373  */
00374 
00375 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
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 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
00384 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
00385 #define T3    0x242070db
00386 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
00387 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
00388 #define T6    0x4787c62a
00389 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
00390 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
00391 #define T9    0x698098d8
00392 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
00393 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
00394 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
00395 #define T13    0x6b901122
00396 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
00397 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
00398 #define T16    0x49b40821
00399 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
00400 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
00401 #define T19    0x265e5a51
00402 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
00403 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
00404 #define T22    0x02441453
00405 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
00406 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
00407 #define T25    0x21e1cde6
00408 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
00409 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
00410 #define T28    0x455a14ed
00411 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
00412 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
00413 #define T31    0x676f02d9
00414 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
00415 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
00416 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
00417 #define T35    0x6d9d6122
00418 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
00419 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
00420 #define T38    0x4bdecfa9
00421 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
00422 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
00423 #define T41    0x289b7ec6
00424 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
00425 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
00426 #define T44    0x04881d05
00427 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
00428 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
00429 #define T47    0x1fa27cf8
00430 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
00431 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
00432 #define T50    0x432aff97
00433 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
00434 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
00435 #define T53    0x655b59c3
00436 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
00437 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
00438 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
00439 #define T57    0x6fa87e4f
00440 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
00441 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
00442 #define T60    0x4e0811a1
00443 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
00444 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
00445 #define T63    0x2ad7d2bb
00446 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
00447 
00448 
00449 static void
00450 md5_process (md5_state_t *pms, const md5_byte_t *data /*[64]*/)
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     /* Define storage only for big-endian CPUs. */
00458     md5_word_t X[16];
00459 #else
00460     /* Define storage for little-endian or both types of CPUs. */
00461     md5_word_t xbuf[16];
00462     const md5_word_t *X;
00463 #endif
00464 
00465     {
00466 #if BYTE_ORDER == 0
00467     /*
00468      * Determine dynamically whether this is a big-endian or
00469      * little-endian machine, since we can use a more efficient
00470      * algorithm on the latter.
00471      */
00472     static const int w = 1;
00473 
00474     if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
00475 #endif
00476 #if BYTE_ORDER <= 0 /* little-endian */
00477     {
00478         /*
00479          * On little-endian machines, we can process properly aligned
00480          * data without copying it.
00481          */
00482         if (!((data - (const md5_byte_t *)0) & 3)) {
00483             /* data are properly aligned */
00484             X = (const md5_word_t *)data;
00485         } else {
00486             /* not aligned */
00487             memcpy (xbuf, data, 64);
00488             X = xbuf;
00489         }
00490     }
00491 #endif
00492 #if BYTE_ORDER == 0
00493     else /* dynamic big-endian */
00494 #endif
00495 #if BYTE_ORDER >= 0 /* big-endian */
00496     {
00497         /*
00498          * On big-endian machines, we must arrange the bytes in the
00499          * right order.
00500          */
00501         const md5_byte_t *xp = data;
00502         int i;
00503 
00504 #  if BYTE_ORDER == 0
00505         X = xbuf;/* (dynamic only) */
00506 #  else
00507 #    define xbuf X /* (static only) */
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     /* Round 1. */
00518     /* Let [abcd k s i] denote the operation
00519        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
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     /* Do the following 16 operations. */
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     /* Round 2. */
00544     /* Let [abcd k s i] denote the operation
00545        a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
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      /* Do the following 16 operations. */
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     /* Round 3. */
00570     /* Let [abcd k s t] denote the operation
00571        a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
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      /* Do the following 16 operations. */
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     /* Round 4. */
00596     /* Let [abcd k s t] denote the operation
00597        a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
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      /* Do the following 16 operations. */
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     /* Then perform the following additions. (That is increment each
00622         of the four registers by the value it had before this block
00623         was started.) */
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] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
00636     pms->abcd[2] = /*0x98badcfe*/ 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     /* Update the message length. */
00652     pms->count[1] += nbytes >> 29;
00653     pms->count[0] += nbits;
00654     if (pms->count[0] < nbits)
00655         pms->count[1]++;
00656 
00657     /* Process an initial partial block. */
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     /* Process full blocks. */
00670     for (; left >= 64; p += 64, left -= 64)
00671         md5_process (pms, p);
00672 
00673     /* Process a final partial block. */
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     /* Save the length before padding. */
00691     for (i = 0; i < 8; ++i)
00692         data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
00693     /* Pad to 56 bytes mod 64. */
00694     md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
00695     /* Append the length. */
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 }

Generated on Wed Feb 9 2011 for XMMS2 by  doxygen 1.7.1