summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog21
-rw-r--r--configure.ac19
-rw-r--r--docs/reference/tmpl/artwork.sgml96
-rw-r--r--docs/reference/tmpl/libgpod-unused.sgml70
-rw-r--r--src/Makefile.am4
-rw-r--r--src/db-artwork-writer.c247
-rw-r--r--src/gchecksum.c1417
-rw-r--r--src/gchecksum.h72
-rw-r--r--src/itdb_itunesdb.c4
-rw-r--r--src/ithumb-writer.c15
10 files changed, 1851 insertions, 114 deletions
diff --git a/ChangeLog b/ChangeLog
index 3e17c67..495ebb0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2008-06-02 Jorg Schuler <jcsjcs at users.sourceforge.net>
+
+ * src/gchecksum.c
+ src/gchecksum.h
+ src/Makefile.am
+ configure.ac: copied gchecksum from glib 2.16.3. It's used if we
+ compile on a system that does not have glib 2.16 or
+ higher. Testing is needed whether it's really pulled in in those
+ cases -- I'm using 2.16.3 myself.
+
+ * src/itdb_itunesdb.c (mk_mhit): write mhii_link.
+
+ * src/db-artwork-writer.c: code to handle sparse artwork
+ correctly.
+
+ (ipod_supports_sparse_artwork): currently hard-coded to
+ TRUE. Will be changed in the future to reflect the information
+ given in the SysInfoExtended. Change yourself if your iPod does
+ not support Sparse Artwork (sharing of thumbnails between
+ several tracks).
+
2008-06-01 Jorg Schuler <jcsjcs at users.sourceforge.net>
* src/itdb_thumb.c
diff --git a/configure.ac b/configure.ac
index 950a5bb..03e3b6c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,6 +76,25 @@ expanded_libdir=`(
eval echo $libdir
)`
+
+dnl **************************************************
+dnl we've copied gchecksum from glib 2.16. Only use the
+dnl copy if the version of glib on the system does not
+dnl provide it.
+dnl **************************************************
+
+AC_ARG_WITH(internal-gchecksum,
+ AC_HELP_STRING([--with-internal-gchecksum],
+ [Build using internal copy of gchecksum]),,
+ with_internal_gchecksum=no)
+
+if test "x$with_internal_gchecksum" = "xno"; then
+ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16.0, with_internal_gchecksum=no,
+ with_internal_gchecksum=yes)
+fi
+
+AM_CONDITIONAL(WITH_INTERNAL_GCHECKSUM, test "x$with_internal_gchecksum" = "xyes")
+
dnl **************************************************
dnl * sgutils is necessary to get the xml device file from the ipod
dnl **************************************************
diff --git a/docs/reference/tmpl/artwork.sgml b/docs/reference/tmpl/artwork.sgml
index 1f491bd..2ae5914 100644
--- a/docs/reference/tmpl/artwork.sgml
+++ b/docs/reference/tmpl/artwork.sgml
@@ -24,8 +24,9 @@ album/track artwork. For working with photos, see the
</para>
-@thumbnails:
+@thumbnail:
@id:
+@dbid:
@unk028:
@rating:
@unk036:
@@ -46,22 +47,8 @@ album/track artwork. For working with photos, see the
</para>
-@type:
-@filename:
-@image_data:
-@image_data_len:
-@pixbuf:
+@data_type:
@rotation:
-@offset:
-@size:
-@width:
-@height:
-@horizontal_padding:
-@vertical_padding:
-@reserved_int1:
-@reserved_int2:
-@reserved1:
-@reserved2:
<!-- ##### ENUM ItdbThumbType ##### -->
<para>
@@ -106,55 +93,6 @@ album/track artwork. For working with photos, see the
@artwork:
-<!-- ##### FUNCTION itdb_artwork_add_thumbnail ##### -->
-<para>
-
-</para>
-
-@artwork:
-@type:
-@filename:
-@rotation:
-@error:
-@Returns:
-
-
-<!-- ##### FUNCTION itdb_artwork_add_thumbnail_from_data ##### -->
-<para>
-
-</para>
-
-@artwork:
-@type:
-@image_data:
-@image_data_len:
-@rotation:
-@error:
-@Returns:
-
-
-<!-- ##### FUNCTION itdb_artwork_add_thumbnail_from_pixbuf ##### -->
-<para>
-
-</para>
-
-@artwork:
-@type:
-@pixbuf:
-@rotation:
-@error:
-@Returns:
-
-
-<!-- ##### FUNCTION itdb_artwork_remove_thumbnail ##### -->
-<para>
-
-</para>
-
-@artwork:
-@thumb:
-
-
<!-- ##### FUNCTION itdb_artwork_remove_thumbnails ##### -->
<para>
@@ -163,16 +101,6 @@ album/track artwork. For working with photos, see the
@artwork:
-<!-- ##### FUNCTION itdb_artwork_get_thumb_by_type ##### -->
-<para>
-
-</para>
-
-@artwork:
-@type:
-@Returns:
-
-
<!-- ##### FUNCTION itdb_thumb_get_gdk_pixbuf ##### -->
<para>
@@ -200,21 +128,3 @@ album/track artwork. For working with photos, see the
@thumb:
-<!-- ##### FUNCTION itdb_thumb_new ##### -->
-<para>
-
-</para>
-
-@Returns:
-
-
-<!-- ##### FUNCTION itdb_thumb_get_filename ##### -->
-<para>
-
-</para>
-
-@device:
-@thumb:
-@Returns:
-
-
diff --git a/docs/reference/tmpl/libgpod-unused.sgml b/docs/reference/tmpl/libgpod-unused.sgml
index e4b24dd..9513543 100644
--- a/docs/reference/tmpl/libgpod-unused.sgml
+++ b/docs/reference/tmpl/libgpod-unused.sgml
@@ -315,6 +315,60 @@ iTunesDB
</para>
+<!-- ##### FUNCTION itdb_artwork_add_thumbnail ##### -->
+<para>
+
+</para>
+
+@artwork:
+@type:
+@filename:
+@rotation:
+@error:
+@Returns:
+
+<!-- ##### FUNCTION itdb_artwork_add_thumbnail_from_data ##### -->
+<para>
+
+</para>
+
+@artwork:
+@type:
+@image_data:
+@image_data_len:
+@rotation:
+@error:
+@Returns:
+
+<!-- ##### FUNCTION itdb_artwork_add_thumbnail_from_pixbuf ##### -->
+<para>
+
+</para>
+
+@artwork:
+@type:
+@pixbuf:
+@rotation:
+@error:
+@Returns:
+
+<!-- ##### FUNCTION itdb_artwork_get_thumb_by_type ##### -->
+<para>
+
+</para>
+
+@artwork:
+@type:
+@Returns:
+
+<!-- ##### FUNCTION itdb_artwork_remove_thumbnail ##### -->
+<para>
+
+</para>
+
+@artwork:
+@thumb:
+
<!-- ##### FUNCTION itdb_file_error_quark ##### -->
<para>
@@ -322,3 +376,19 @@ iTunesDB
@Returns:
+<!-- ##### FUNCTION itdb_thumb_get_filename ##### -->
+<para>
+
+</para>
+
+@device:
+@thumb:
+@Returns:
+
+<!-- ##### FUNCTION itdb_thumb_new ##### -->
+<para>
+
+</para>
+
+@Returns:
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 49260f5..d840480 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,10 @@ libgpod_la_SOURCES = \
pixmaps.c \
sha1.c
+if WITH_INTERNAL_GCHECKSUM
+libgpod_la_SOURCES += gchecksum.c gchecksum.h
+endif
+
libgpod_la_LDFLAGS = -version-info $(LIBGPOD_SO_VERSION) -no-undefined
libgpodincludebase = $(includedir)/gpod-1.0
diff --git a/src/db-artwork-writer.c b/src/db-artwork-writer.c
index a24b0fd..cbf22fc 100644
--- a/src/db-artwork-writer.c
+++ b/src/db-artwork-writer.c
@@ -569,7 +569,7 @@ write_mhli (Itdb_DB *db, iPodBuffer *buffer )
iPodBuffer *sub_buffer;
if (buffer->db_type == DB_TYPE_ITUNES) {
song = (Itdb_Track*)it->data;
- if (!song->artwork->thumbnail || (song->artwork->id == 0)) {
+ if (!song->artwork->thumbnail || (song->artwork->dbid == 0)) {
it = it->next;
continue;
}
@@ -924,29 +924,242 @@ write_mhfd (Itdb_DB *db, iPodBuffer *buffer, int id_max)
return total_bytes;
}
-static unsigned int
+
+static gboolean
+ipod_supports_sparse_artwork (Itdb_Device *device)
+{
+ return TRUE;
+}
+
+
+/* renumber the artwork IDs for all tracks containing artwork and with
+ an ID of != 0 */
+/* if the iPod does not support sparse artwork, renumber consecutively
+ and all artwork */
+/* returns the highest assigned ID or 0 if no IDs were used */
+static guint32
ipod_artwork_db_set_ids (Itdb_iTunesDB *db)
{
- GList *it;
- unsigned int max_id;
+ GList *gl;
+ const guint32 min_id = 0x64;
+ guint32 cur_id;
- max_id = 0;
- for (it = db->tracks; it != NULL; it = it->next) {
- Itdb_Track *song;
+ cur_id = min_id;
+
+ if (ipod_supports_sparse_artwork (db->device))
+ {
+ GHashTable *id_hash;
- song = (Itdb_Track *)it->data;
- if (max_id <= song->id) {
- max_id = song->id;
+ id_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ for (gl = db->tracks; gl != NULL; gl = gl->next)
+ {
+ Itdb_Track *song;
+ Itdb_Artwork *artwork;
+
+ song = gl->data;
+ g_return_val_if_fail (song, -1);
+
+ artwork = song->artwork;
+ g_return_val_if_fail (artwork, -1);
+
+ if (itdb_track_has_thumbnails (song) && (artwork->id != 0))
+ {
+ gpointer orig_key;
+ gpointer orig_val;
+
+ if (g_hash_table_lookup_extended (id_hash, GINT_TO_POINTER (artwork->id),
+ &orig_key, &orig_val))
+ { /* ID was encountered before */
+ artwork->id = GPOINTER_TO_INT (orig_val);
+ artwork->dbid = 0;
}
- if (song->artwork->thumbnail != NULL) {
- song->artwork->id = song->id;
+ else
+ { /* first time we see this ID */
+ g_hash_table_insert (id_hash, GINT_TO_POINTER (artwork->id),
+ GINT_TO_POINTER (cur_id));
+ artwork->id = cur_id++;
+ artwork->dbid = song->dbid;
}
+ song->mhii_link = artwork->id;
+ }
+ else
+ {
+ song->mhii_link = 0;
+ }
}
+ g_hash_table_destroy (id_hash);
+ }
+ else
+ { /* iPod does not support sparse artwork -- just renumber */
+ for (gl = db->tracks; gl != NULL; gl = gl->next)
+ {
+ Itdb_Track *song;
+
+ song = gl->data;
+ g_return_val_if_fail (song, -1);
+ g_return_val_if_fail (song->artwork, -1);
+
+ song->mhii_link = 0;
+
+ if (itdb_track_has_thumbnails (song))
+ {
+ song->artwork->id = cur_id++;
+ song->artwork->dbid = song->dbid;
+ }
+ song->mhii_link = song->artwork->id;
+ }
+ }
- return max_id;
+ if (cur_id == min_id)
+ return 0;
+ else
+ return cur_id-1;
}
-int
+
+
+/* for all tracks with new artwork (id == 0) do the following:
+ - try to identify if this artwork is identical to previous artwork
+ (within the same album)
+ - if no: assign new ID
+ - if yes: assign same ID
+
+ Returns the highest ID used.
+*/
+static guint32
+ipod_artwork_mark_new_doubles (Itdb_iTunesDB *itdb, guint max_id)
+{
+ GList *gl;
+ GHashTable *hash_file, *hash_memory, *hash_pixbuf;
+
+ hash_file = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ hash_memory = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ hash_pixbuf = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ for (gl=itdb->tracks; gl; gl=gl->next)
+ {
+ Itdb_Artwork *artwork;
+ Itdb_Track *track;
+
+ track= gl->data;
+ g_return_val_if_fail (track, max_id);
+ artwork = track->artwork;
+ g_return_val_if_fail (artwork, max_id);
+
+ if ((artwork->id == 0) && itdb_track_has_thumbnails (track))
+ {
+ const gchar *checkstring;
+ GHashTable *hash=NULL;
+ gpointer orig_val = NULL;
+ Itdb_Thumb *thumb = artwork->thumbnail;
+ GChecksum *checksum = g_checksum_new (G_CHECKSUM_SHA1);
+
+ /* use the album name as part of the checksum */
+ if (track->album && *track->album)
+ {
+ g_checksum_update (checksum,
+ (guchar *)track->album, strlen (track->album));
+ }
+
+ switch (thumb->data_type)
+ {
+ case ITDB_THUMB_TYPE_MEMORY:
+ {
+ Itdb_Thumb_Memory *mthumb = (Itdb_Thumb_Memory *)thumb;
+ g_checksum_update (checksum,
+ mthumb->image_data, mthumb->image_data_len);
+ hash = hash_memory;
+ break;
+ }
+ case ITDB_THUMB_TYPE_PIXBUF:
+ {
+ Itdb_Thumb_Pixbuf *pthumb = (Itdb_Thumb_Pixbuf *)thumb;
+ g_return_val_if_fail (pthumb->pixbuf, max_id);
+ g_checksum_update (checksum,
+ gdk_pixbuf_get_pixels (pthumb->pixbuf),
+ gdk_pixbuf_get_height (pthumb->pixbuf) * gdk_pixbuf_get_rowstride (pthumb->pixbuf));
+ hash = hash_pixbuf;
+ break;
+ }
+ case ITDB_THUMB_TYPE_FILE:
+ {
+ Itdb_Thumb_File *fthumb = (Itdb_Thumb_File *)thumb;
+ g_return_val_if_fail (fthumb->filename, max_id);
+ g_checksum_update (checksum,
+ (guchar *)fthumb->filename,
+ strlen (fthumb->filename));
+ hash = hash_file;
+ break;
+ }
+ case ITDB_THUMB_TYPE_INVALID:
+ /* programming error */
+ g_print ("encountered invalid thumb.\n");
+ g_return_val_if_reached (max_id);
+ break;
+ case ITDB_THUMB_TYPE_IPOD:
+ /* thumbs on the iPod are definitely not expected to
+ have an ID of 0 */
+ g_print ("encountered iPod thumb with ID = 0.\n");
+ g_return_val_if_reached (max_id);
+ break;
+ }
+
+ checkstring = g_checksum_get_string (checksum);
+ if (g_hash_table_lookup_extended (hash, checkstring, NULL, &orig_val))
+ { /* same artwork was used before */
+ Itdb_Artwork *previous_artwork = orig_val;
+ artwork->id = previous_artwork->id;
+ artwork->dbid = 0;
+ }
+ else
+ { /* first occurence of this artwork */
+ artwork->id = ++max_id;
+ artwork->dbid = track->dbid;
+ g_hash_table_insert (hash, g_strdup (checkstring), artwork);
+ }
+ track->mhii_link = artwork->id;
+ g_checksum_free (checksum);
+ }
+ }
+
+ g_hash_table_destroy (hash_memory);
+ g_hash_table_destroy (hash_file);
+ g_hash_table_destroy (hash_pixbuf);
+
+ return max_id;
+}
+
+
+/* returns the highest ID used */
+static guint32 itdb_prepare_thumbnails (Itdb_iTunesDB *itdb)
+{
+ gint max_id;
+
+ /* first renumber the old thumbnails to make sure we don't get too
+ * high */
+ max_id = ipod_artwork_db_set_ids (itdb);
+
+ if (ipod_supports_sparse_artwork (itdb->device))
+ {
+ /* go through all newly added artwork and pass out new IDs. the
+ same ID will be assigned to identical artwork within one album */
+ max_id = ipod_artwork_mark_new_doubles (itdb, max_id);
+
+ /* set the IDs again to make sure they are in the right order */
+ max_id = ipod_artwork_db_set_ids (itdb);
+ }
+
+ return max_id;
+}
+
+
+
+
+G_GNUC_INTERNAL int
ipod_write_artwork_db (Itdb_iTunesDB *itdb)
{
iPodBuffer *buf;
@@ -958,12 +1171,12 @@ ipod_write_artwork_db (Itdb_iTunesDB *itdb)
db.db_type = DB_TYPE_ITUNES;
db.db.itdb = itdb;
+ id_max = itdb_prepare_thumbnails (itdb);
+
/* First, let's write the .ithmb files, this will create the
* various thumbnails as well */
itdb_write_ithumb_files (&db);
- /* Now we can update the ArtworkDB file */
- id_max = ipod_artwork_db_set_ids (itdb);
filename = ipod_db_get_artwork_db_path (itdb_get_mountpoint (itdb));
if (filename == NULL) {
@@ -1037,7 +1250,7 @@ ipod_write_photo_db (Itdb_PhotoDB *photodb)
return 0;
}
#else
-int
+G_GNUC_INTERNAL int
ipod_write_artwork_db (Itdb_iTunesDB *itdb)
{
return -1;
diff --git a/src/gchecksum.c b/src/gchecksum.c
new file mode 100644
index 0000000..ded85ca
--- /dev/null
+++ b/src/gchecksum.c
@@ -0,0 +1,1417 @@
+/* gchecksum.h - data hashing functions
+ *
+ * Copyright (C) 2007 Emmanuele Bassi <ebassi@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "glibconfig.h"
+#include "gchecksum.h"
+#include "glib.h"
+#include "glibintl.h"
+
+#include "galias.h"
+
+#define IS_VALID_TYPE(type) ((type) >= G_CHECKSUM_MD5 && (type) <= G_CHECKSUM_SHA256)
+
+static const gchar hex_digits[] = "0123456789abcdef";
+
+#define MD5_DATASIZE 64
+#define MD5_DIGEST_LEN 16
+
+typedef struct
+{
+ guint32 buf[4];
+ guint32 bits[2];
+
+ guchar data[MD5_DATASIZE];
+
+ guchar digest[MD5_DIGEST_LEN];
+} Md5sum;
+
+#define SHA1_DATASIZE 64
+#define SHA1_DIGEST_LEN 20
+
+typedef struct
+{
+ guint32 buf[5];
+ guint32 bits[2];
+
+ /* we pack 64 unsigned chars into 16 32-bit unsigned integers */
+ guint32 data[16];
+
+ guchar digest[SHA1_DIGEST_LEN];
+} Sha1sum;
+
+#define SHA256_DATASIZE 64
+#define SHA256_DIGEST_LEN 32
+
+typedef struct
+{
+ guint32 buf[8];
+ guint32 bits[2];
+
+ guint8 data[SHA256_DATASIZE];
+
+ guchar digest[SHA256_DIGEST_LEN];
+} Sha256sum;
+
+struct _GChecksum
+{
+ GChecksumType type;
+
+ gchar *digest_str;
+
+ union {
+ Md5sum md5;
+ Sha1sum sha1;
+ Sha256sum sha256;
+ } sum;
+};
+
+/* we need different byte swapping functions because MD5 expects buffers
+ * to be little-endian, while SHA1 and SHA256 expect them in big-endian
+ * form.
+ */
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define md5_byte_reverse(buffer,length)
+#else
+/* assume that the passed buffer is integer aligned */
+static inline void
+md5_byte_reverse (guchar *buffer,
+ gulong length)
+{
+ guint32 bit;
+
+ do
+ {
+ bit = (guint32) ((unsigned) buffer[3] << 8 | buffer[2]) << 16 |
+ ((unsigned) buffer[1] << 8 | buffer[0]);
+ * (guint32 *) buffer = bit;
+ buffer += 4;
+ }
+ while (--length);
+}
+#endif /* G_BYTE_ORDER == G_LITTLE_ENDIAN */
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define sha_byte_reverse(buffer,length)
+#else
+static inline void
+sha_byte_reverse (guint32 *buffer,
+ gint length)
+{
+ length /= sizeof (guint32);
+ while (length--)
+ {
+ *buffer = ((guint32) (((*buffer & (guint32) 0x000000ffU) << 24) |
+ ((*buffer & (guint32) 0x0000ff00U) << 8) |
+ ((*buffer & (guint32) 0x00ff0000U) >> 8) |
+ ((*buffer & (guint32) 0xff000000U) >> 24)));
+ ++buffer;
+ }
+}
+#endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
+
+static gchar *
+digest_to_string (guint8 *digest,
+ gsize digest_len)
+{
+ gint len = digest_len * 2;
+ gint i;
+ gchar *retval;
+
+ retval = g_new (gchar, len + 1);
+
+ for (i = 0; i < digest_len; i++)
+ {
+ guint8 byte = digest[i];
+
+ retval[2 * i] = hex_digits[byte >> 4];
+ retval[2 * i + 1] = hex_digits[byte & 0xf];
+ }
+
+ retval[len] = 0;
+
+ return retval;
+}
+
+/*
+ * MD5 Checksum
+ */
+
+/* This MD5 digest computation is based on the equivalent code
+ * written by Colin Plumb. It came with this notice:
+ *
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+
+static void
+md5_sum_init (Md5sum *md5)
+{
+ /* arbitrary constants */
+ md5->buf[0] = 0x67452301;
+ md5->buf[1] = 0xefcdab89;
+ md5->buf[2] = 0x98badcfe;
+ md5->buf[3] = 0x10325476;
+
+ md5->bits[0] = md5->bits[1] = 0;
+}
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. md5_sum_update()
+ * blocks the data and converts bytes into longwords for this routine.
+ */
+static void
+md5_transform (guint32 buf[4],
+ guint32 const in[16])
+{
+ register guint32 a, b, c, d;
+
+/* The four core functions - F1 is optimized somewhat */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1 (z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define md5_step(f, w, x, y, z, data, s) \
+ ( w += f (x, y, z) + data, w = w << s | w >> (32 - s), w += x )
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ md5_step (F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ md5_step (F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ md5_step (F1, c, d, a, b, in[2] + 0x242070db, 17);
+ md5_step (F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ md5_step (F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ md5_step (F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ md5_step (F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ md5_step (F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ md5_step (F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ md5_step (F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ md5_step (F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ md5_step (F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ md5_step (F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ md5_step (F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ md5_step (F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ md5_step (F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ md5_step (F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ md5_step (F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ md5_step (F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ md5_step (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ md5_step (F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ md5_step (F2, d, a, b, c, in[10] + 0x02441453, 9);
+ md5_step (F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ md5_step (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ md5_step (F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ md5_step (F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ md5_step (F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ md5_step (F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ md5_step (F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ md5_step (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ md5_step (F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ md5_step (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ md5_step (F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ md5_step (F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ md5_step (F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ md5_step (F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ md5_step (F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ md5_step (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ md5_step (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ md5_step (F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ md5_step (F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ md5_step (F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ md5_step (F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ md5_step (F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ md5_step (F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ md5_step (F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ md5_step (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ md5_step (F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ md5_step (F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ md5_step (F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ md5_step (F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ md5_step (F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ md5_step (F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ md5_step (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ md5_step (F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ md5_step (F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ md5_step (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ md5_step (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ md5_step (F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ md5_step (F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ md5_step (F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ md5_step (F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ md5_step (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ md5_step (F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef md5_step
+}
+
+static void
+md5_sum_update (Md5sum *md5,
+ const guchar *data,
+ gsize length)
+{
+ guint32 bit;
+
+ bit = md5->bits[0];
+ md5->bits[0] = bit + ((guint32) length << 3);
+
+ /* carry from low to high */
+ if (md5->bits[0] < bit)
+ md5->bits[1] += 1;
+
+ md5->bits[1] += length >> 29;
+
+ /* bytes already in Md5sum->data */
+ bit = (bit >> 3) & 0x3f;
+
+ /* handle any leading odd-sized chunks */
+ if (bit)
+ {
+ guchar *p = (guchar *) md5->data + bit;
+
+ bit = MD5_DATASIZE - bit;
+ if (length < bit)
+ {
+ memcpy (p, data, length);
+ return;
+ }
+
+ memcpy (p, data, bit);
+
+ md5_byte_reverse (md5->data, 16);
+ md5_transform (md5->buf, (guint32 *) md5->data);
+
+ data += bit;
+ length -= bit;
+ }
+
+ /* process data in 64-byte chunks */
+ while (length >= MD5_DATASIZE)
+ {
+ memcpy (md5->data, data, MD5_DATASIZE);
+
+ md5_byte_reverse (md5->data, 16);
+ md5_transform (md5->buf, (guint32 *) md5->data);
+
+ data += MD5_DATASIZE;
+ length -= MD5_DATASIZE;
+ }
+
+ /* handle any remaining bytes of data */
+ memcpy (md5->data, data, length);
+}
+
+/* closes a checksum */
+static void
+md5_sum_close (Md5sum *md5)
+{
+ guint count;
+ guchar *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (md5->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80.
+ * This is safe since there is always at least one byte free
+ */
+ p = md5->data + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = MD5_DATASIZE - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8)
+ {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset (p, 0, count);
+
+ md5_byte_reverse (md5->data, 16);
+ md5_transform (md5->buf, (guint32 *) md5->data);
+
+ /* Now fill the next block with 56 bytes */
+ memset (md5->data, 0, MD5_DATASIZE - 8);
+ }
+ else
+ {
+ /* Pad block to 56 bytes */
+ memset (p, 0, count - 8);
+ }
+
+ md5_byte_reverse (md5->data, 14);
+
+ /* Append length in bits and transform */
+ ((guint32 *) md5->data)[14] = md5->bits[0];
+ ((guint32 *) md5->data)[15] = md5->bits[1];
+
+ md5_transform (md5->buf, (guint32 *) md5->data);
+ md5_byte_reverse ((guchar *) md5->buf, 4);
+
+ memcpy (md5->digest, md5->buf, 16);
+
+ /* Reset buffers in case they contain sensitive data */
+ memset (md5->buf, 0, sizeof (md5->buf));
+ memset (md5->data, 0, sizeof (md5->data));
+}
+
+static gchar *
+md5_sum_to_string (Md5sum *md5)
+{
+ return digest_to_string (md5->digest, MD5_DIGEST_LEN);
+}
+
+static void
+md5_sum_digest (Md5sum *md5,
+ guint8 *digest)
+{
+ gint i;
+
+ for (i = 0; i < MD5_DIGEST_LEN; i++)
+ digest[i] = md5->digest[i];
+}
+
+/*
+ * SHA-1 Checksum
+ */
+
+/* The following implementation comes from D-Bus dbus-sha.c. I've changed
+ * it to use GLib types and to work more like the MD5 implementation above.
+ * I left the comments to have an history of this code.
+ * -- Emmanuele Bassi, ebassi@gnome.org
+ */
+
+/* The following comments have the history of where this code
+ * comes from. I actually copied it from GNet in GNOME CVS.
+ * - hp@redhat.com
+ */
+
+/*
+ * sha.h : Implementation of the Secure Hash Algorithm
+ *
+ * Part of the Python Cryptography Toolkit, version 1.0.0
+ *
+ * Copyright (C) 1995, A.M. Kuchling
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+/* SHA: NIST's Secure Hash Algorithm */
+
+/* Based on SHA code originally posted to sci.crypt by Peter Gutmann
+ in message <30ajo5$oe8@ccu2.auckland.ac.nz>.
+ Modified to test for endianness on creation of SHA objects by AMK.
+ Also, the original specification of SHA was found to have a weakness
+ by NSA/NIST. This code implements the fixed version of SHA.
+*/
+
+/* Here's the first paragraph of Peter Gutmann's posting:
+
+The following is my SHA (FIPS 180) code updated to allow use of the "fixed"
+SHA, thanks to Jim Gillogly and an anonymous contributor for the information on
+what's changed in the new version. The fix is a simple change which involves
+adding a single rotate in the initial expansion function. It is unknown
+whether this is an optimal solution to the problem which was discovered in the
+SHA or whether it's simply a bandaid which fixes the problem with a minimum of
+effort (for example the reengineering of a great many Capstone chips).
+*/
+
+static void
+sha1_sum_init (Sha1sum *sha1)
+{
+ /* initialize constants */
+ sha1->buf[0] = 0x67452301L;
+ sha1->buf[1] = 0xEFCDAB89L;
+ sha1->buf[2] = 0x98BADCFEL;
+ sha1->buf[3] = 0x10325476L;
+ sha1->buf[4] = 0xC3D2E1F0L;
+
+ /* initialize bits */
+ sha1->bits[0] = sha1->bits[1] = 0;
+}
+
+/* The SHA f()-functions. */
+
+#define f1(x,y,z) (z ^ (x & (y ^ z))) /* Rounds 0-19 */
+#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39 */
+#define f3(x,y,z) (( x & y) | (z & (x | y))) /* Rounds 40-59 */
+#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79 */
+
+/* The SHA Mysterious Constants */
+#define K1 0x5A827999L /* Rounds 0-19 */
+#define K2 0x6ED9EBA1L /* Rounds 20-39 */
+#define K3 0x8F1BBCDCL /* Rounds 40-59 */
+#define K4 0xCA62C1D6L /* Rounds 60-79 */
+
+/* 32-bit rotate left - kludged with shifts */
+#define ROTL(n,X) (((X) << n ) | ((X) >> (32 - n)))
+
+/* The initial expanding function. The hash function is defined over an
+ 80-word expanded input array W, where the first 16 are copies of the input
+ data, and the remaining 64 are defined by
+
+ W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
+
+ This implementation generates these values on the fly in a circular
+ buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+ optimization.
+
+ The updated SHA changes the expanding function by adding a rotate of 1
+ bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
+ for this information */
+
+#define expand(W,i) (W[ i & 15 ] = ROTL (1, (W[ i & 15] ^ \
+ W[(i - 14) & 15] ^ \
+ W[(i - 8) & 15] ^ \
+ W[(i - 3) & 15])))
+
+
+/* The prototype SHA sub-round. The fundamental sub-round is:
+
+ a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
+ b' = a;
+ c' = ROTL( 30, b );
+ d' = c;
+ e' = d;
+
+ but this is implemented by unrolling the loop 5 times and renaming the
+ variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
+ This code is then replicated 20 times for each of the 4 functions, using
+ the next 20 values from the W[] array each time */
+
+#define subRound(a, b, c, d, e, f, k, data) \
+ (e += ROTL (5, a) + f(b, c, d) + k + data, b = ROTL (30, b))
+
+static void
+sha1_transform (guint32 buf[5],
+ guint32 in[16])
+{
+ guint32 A, B, C, D, E;
+
+ A = buf[0];
+ B = buf[1];
+ C = buf[2];
+ D = buf[3];
+ E = buf[4];
+
+ /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+ subRound (A, B, C, D, E, f1, K1, in[0]);
+ subRound (E, A, B, C, D, f1, K1, in[1]);
+ subRound (D, E, A, B, C, f1, K1, in[2]);
+ subRound (C, D, E, A, B, f1, K1, in[3]);
+ subRound (B, C, D, E, A, f1, K1, in[4]);
+ subRound (A, B, C, D, E, f1, K1, in[5]);
+ subRound (E, A, B, C, D, f1, K1, in[6]);
+ subRound (D, E, A, B, C, f1, K1, in[7]);
+ subRound (C, D, E, A, B, f1, K1, in[8]);
+ subRound (B, C, D, E, A, f1, K1, in[9]);
+ subRound (A, B, C, D, E, f1, K1, in[10]);
+ subRound (E, A, B, C, D, f1, K1, in[11]);
+ subRound (D, E, A, B, C, f1, K1, in[12]);
+ subRound (C, D, E, A, B, f1, K1, in[13]);
+ subRound (B, C, D, E, A, f1, K1, in[14]);
+ subRound (A, B, C, D, E, f1, K1, in[15]);
+ subRound (E, A, B, C, D, f1, K1, expand (in, 16));
+ subRound (D, E, A, B, C, f1, K1, expand (in, 17));
+ subRound (C, D, E, A, B, f1, K1, expand (in, 18));
+ subRound (B, C, D, E, A, f1, K1, expand (in, 19));
+
+ subRound (A, B, C, D, E, f2, K2, expand (in, 20));
+ subRound (E, A, B, C, D, f2, K2, expand (in, 21));
+ subRound (D, E, A, B, C, f2, K2, expand (in, 22));
+ subRound (C, D, E, A, B, f2, K2, expand (in, 23));
+ subRound (B, C, D, E, A, f2, K2, expand (in, 24));
+ subRound (A, B, C, D, E, f2, K2, expand (in, 25));
+ subRound (E, A, B, C, D, f2, K2, expand (in, 26));
+ subRound (D, E, A, B, C, f2, K2, expand (in, 27));
+ subRound (C, D, E, A, B, f2, K2, expand (in, 28));
+ subRound (B, C, D, E, A, f2, K2, expand (in, 29));
+ subRound (A, B, C, D, E, f2, K2, expand (in, 30));
+ subRound (E, A, B, C, D, f2, K2, expand (in, 31));
+ subRound (D, E, A, B, C, f2, K2, expand (in, 32));
+ subRound (C, D, E, A, B, f2, K2, expand (in, 33));
+ subRound (B, C, D, E, A, f2, K2, expand (in, 34));
+ subRound (A, B, C, D, E, f2, K2, expand (in, 35));
+ subRound (E, A, B, C, D, f2, K2, expand (in, 36));
+ subRound (D, E, A, B, C, f2, K2, expand (in, 37));
+ subRound (C, D, E, A, B, f2, K2, expand (in, 38));
+ subRound (B, C, D, E, A, f2, K2, expand (in, 39));
+
+ subRound (A, B, C, D, E, f3, K3, expand (in, 40));
+ subRound (E, A, B, C, D, f3, K3, expand (in, 41));
+ subRound (D, E, A, B, C, f3, K3, expand (in, 42));
+ subRound (C, D, E, A, B, f3, K3, expand (in, 43));
+ subRound (B, C, D, E, A, f3, K3, expand (in, 44));
+ subRound (A, B, C, D, E, f3, K3, expand (in, 45));
+ subRound (E, A, B, C, D, f3, K3, expand (in, 46));
+ subRound (D, E, A, B, C, f3, K3, expand (in, 47));
+ subRound (C, D, E, A, B, f3, K3, expand (in, 48));
+ subRound (B, C, D, E, A, f3, K3, expand (in, 49));
+ subRound (A, B, C, D, E, f3, K3, expand (in, 50));
+ subRound (E, A, B, C, D, f3, K3, expand (in, 51));
+ subRound (D, E, A, B, C, f3, K3, expand (in, 52));
+ subRound (C, D, E, A, B, f3, K3, expand (in, 53));
+ subRound (B, C, D, E, A, f3, K3, expand (in, 54));
+ subRound (A, B, C, D, E, f3, K3, expand (in, 55));
+ subRound (E, A, B, C, D, f3, K3, expand (in, 56));
+ subRound (D, E, A, B, C, f3, K3, expand (in, 57));
+ subRound (C, D, E, A, B, f3, K3, expand (in, 58));
+ subRound (B, C, D, E, A, f3, K3, expand (in, 59));
+
+ subRound (A, B, C, D, E, f4, K4, expand (in, 60));
+ subRound (E, A, B, C, D, f4, K4, expand (in, 61));
+ subRound (D, E, A, B, C, f4, K4, expand (in, 62));
+ subRound (C, D, E, A, B, f4, K4, expand (in, 63));
+ subRound (B, C, D, E, A, f4, K4, expand (in, 64));
+ subRound (A, B, C, D, E, f4, K4, expand (in, 65));
+ subRound (E, A, B, C, D, f4, K4, expand (in, 66));
+ subRound (D, E, A, B, C, f4, K4, expand (in, 67));
+ subRound (C, D, E, A, B, f4, K4, expand (in, 68));
+ subRound (B, C, D, E, A, f4, K4, expand (in, 69));
+ subRound (A, B, C, D, E, f4, K4, expand (in, 70));
+ subRound (E, A, B, C, D, f4, K4, expand (in, 71));
+ subRound (D, E, A, B, C, f4, K4, expand (in, 72));
+ subRound (C, D, E, A, B, f4, K4, expand (in, 73));
+ subRound (B, C, D, E, A, f4, K4, expand (in, 74));
+ subRound (A, B, C, D, E, f4, K4, expand (in, 75));
+ subRound (E, A, B, C, D, f4, K4, expand (in, 76));
+ subRound (D, E, A, B, C, f4, K4, expand (in, 77));
+ subRound (C, D, E, A, B, f4, K4, expand (in, 78));
+ subRound (B, C, D, E, A, f4, K4, expand (in, 79));
+
+ /* Build message digest */
+ buf[0] += A;
+ buf[1] += B;
+ buf[2] += C;
+ buf[3] += D;
+ buf[4] += E;
+}
+
+#undef K1
+#undef K2
+#undef K3
+#undef K4
+#undef f1
+#undef f2
+#undef f3
+#undef f4
+#undef ROTL
+#undef expand
+#undef subRound
+
+static void
+sha1_sum_update (Sha1sum *sha1,
+ const guchar *buffer,
+ gsize count)
+{
+ guint32 tmp;
+ guint dataCount;
+
+ /* Update bitcount */
+ tmp = sha1->bits[0];
+ if ((sha1->bits[0] = tmp + ((guint32) count << 3) ) < tmp)
+ sha1->bits[1] += 1; /* Carry from low to high */
+ sha1->bits[1] += count >> 29;
+
+ /* Get count of bytes already in data */
+ dataCount = (guint) (tmp >> 3) & 0x3F;
+
+ /* Handle any leading odd-sized chunks */
+ if (dataCount)
+ {
+ guchar *p = (guchar *) sha1->data + dataCount;
+
+ dataCount = SHA1_DATASIZE - dataCount;
+ if (count < dataCount)
+ {
+ memcpy (p, buffer, count);
+ return;
+ }
+
+ memcpy (p, buffer, dataCount);
+
+ sha_byte_reverse (sha1->data, SHA1_DATASIZE);
+ sha1_transform (sha1->buf, sha1->data);
+
+ buffer += dataCount;
+ count -= dataCount;
+ }
+
+ /* Process data in SHA1_DATASIZE chunks */
+ while (count >= SHA1_DATASIZE)
+ {
+ memcpy (sha1->data, buffer, SHA1_DATASIZE);
+
+ sha_byte_reverse (sha1->data, SHA1_DATASIZE);
+ sha1_transform (sha1->buf, sha1->data);
+
+ buffer += SHA1_DATASIZE;
+ count -= SHA1_DATASIZE;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy (sha1->data, buffer, count);
+}
+
+/* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern
+ 1 0* (64-bit count of bits processed, MSB-first) */
+static void
+sha1_sum_close (Sha1sum *sha1)
+{
+ gint count;
+ guchar *data_p;
+
+ /* Compute number of bytes mod 64 */
+ count = (gint) ((sha1->bits[0] >> 3) & 0x3f);
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ data_p = (guchar *) sha1->data + count;
+ *data_p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = SHA1_DATASIZE - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8)
+ {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset (data_p, 0, count);
+
+ sha_byte_reverse (sha1->data, SHA1_DATASIZE);
+ sha1_transform (sha1->buf, sha1->data);
+
+ /* Now fill the next block with 56 bytes */
+ memset (sha1->data, 0, SHA1_DATASIZE - 8);
+ }
+ else
+ {
+ /* Pad block to 56 bytes */
+ memset (data_p, 0, count - 8);
+ }
+
+ /* Append length in bits and transform */
+ sha1->data[14] = sha1->bits[1];
+ sha1->data[15] = sha1->bits[0];
+
+ sha_byte_reverse (sha1->data, SHA1_DATASIZE - 8);
+ sha1_transform (sha1->buf, sha1->data);
+ sha_byte_reverse (sha1->buf, SHA1_DIGEST_LEN);
+
+ memcpy (sha1->digest, sha1->buf, SHA1_DIGEST_LEN);
+
+ /* Reset buffers in case they contain sensitive data */
+ memset (sha1->buf, 0, sizeof (sha1->buf));
+ memset (sha1->data, 0, sizeof (sha1->data));
+}
+
+static gchar *
+sha1_sum_to_string (Sha1sum *sha1)
+{
+ return digest_to_string (sha1->digest, SHA1_DIGEST_LEN);
+}
+
+static void
+sha1_sum_digest (Sha1sum *sha1,
+ guint8 *digest)
+{
+ gint i;
+
+ for (i = 0; i < SHA1_DIGEST_LEN; i++)
+ digest[i] = sha1->digest[i];
+}
+
+/*
+ * SHA-256 Checksum
+ */
+
+/* adapted from the SHA256 implementation in gsk/src/hash/gskhash.c.
+ *
+ * Copyright (C) 2006 Dave Benson
+ * Released under the terms of the GNU Lesser General Public License
+ */
+
+static void
+sha256_sum_init (Sha256sum *sha256)
+{
+ sha256->buf[0] = 0x6a09e667;
+ sha256->buf[1] = 0xbb67ae85;
+ sha256->buf[2] = 0x3c6ef372;
+ sha256->buf[3] = 0xa54ff53a;
+ sha256->buf[4] = 0x510e527f;
+ sha256->buf[5] = 0x9b05688c;
+ sha256->buf[6] = 0x1f83d9ab;
+ sha256->buf[7] = 0x5be0cd19;
+
+ sha256->bits[0] = sha256->bits[1] = 0;
+}
+
+#define GET_UINT32(n,b,i) G_STMT_START{ \
+ (n) = ((guint32) (b)[(i) ] << 24) \
+ | ((guint32) (b)[(i) + 1] << 16) \
+ | ((guint32) (b)[(i) + 2] << 8) \
+ | ((guint32) (b)[(i) + 3] ); } G_STMT_END
+
+#define PUT_UINT32(n,b,i) G_STMT_START{ \
+ (b)[(i) ] = (guint8) ((n) >> 24); \
+ (b)[(i) + 1] = (guint8) ((n) >> 16); \
+ (b)[(i) + 2] = (guint8) ((n) >> 8); \
+ (b)[(i) + 3] = (guint8) ((n) ); } G_STMT_END
+
+static void
+sha256_transform (guint32 buf[8],
+ guint8 const data[64])
+{
+ guint32 temp1, temp2, W[64];
+ guint32 A, B, C, D, E, F, G, H;
+
+ GET_UINT32 (W[0], data, 0);
+ GET_UINT32 (W[1], data, 4);
+ GET_UINT32 (W[2], data, 8);
+ GET_UINT32 (W[3], data, 12);
+ GET_UINT32 (W[4], data, 16);
+ GET_UINT32 (W[5], data, 20);
+ GET_UINT32 (W[6], data, 24);
+ GET_UINT32 (W[7], data, 28);
+ GET_UINT32 (W[8], data, 32);
+ GET_UINT32 (W[9], data, 36);
+ GET_UINT32 (W[10], data, 40);
+ GET_UINT32 (W[11], data, 44);
+ GET_UINT32 (W[12], data, 48);
+ GET_UINT32 (W[13], data, 52);
+ GET_UINT32 (W[14], data, 56);
+ GET_UINT32 (W[15], data, 60);
+
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR (x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR (x, 7) ^ ROTR (x,18) ^ SHR (x, 3))
+#define S1(x) (ROTR (x,17) ^ ROTR (x,19) ^ SHR (x,10))
+#define S2(x) (ROTR (x, 2) ^ ROTR (x,13) ^ ROTR (x,22))
+#define S3(x) (ROTR (x, 6) ^ ROTR (x,11) ^ ROTR (x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t) (W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16])
+
+#define P(a,b,c,d,e,f,g,h,x,K) G_STMT_START { \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; } G_STMT_END
+
+ A = buf[0];
+ B = buf[1];
+ C = buf[2];
+ D = buf[3];
+ E = buf[4];
+ F = buf[5];
+ G = buf[6];
+ H = buf[7];
+
+ P (A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98);
+ P (H, A, B, C, D, E, F, G, W[ 1], 0x71374491);
+ P (G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF);
+ P (F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5);
+ P (E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B);
+ P (D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1);
+ P (C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4);
+ P (B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5);
+ P (A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98);
+ P (H, A, B, C, D, E, F, G, W[ 9], 0x12835B01);
+ P (G, H, A, B, C, D, E, F, W[10], 0x243185BE);
+ P (F, G, H, A, B, C, D, E, W[11], 0x550C7DC3);
+ P (E, F, G, H, A, B, C, D, W[12], 0x72BE5D74);
+ P (D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE);
+ P (C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7);
+ P (B, C, D, E, F, G, H, A, W[15], 0xC19BF174);
+ P (A, B, C, D, E, F, G, H, R(16), 0xE49B69C1);
+ P (H, A, B, C, D, E, F, G, R(17), 0xEFBE4786);
+ P (G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6);
+ P (F, G, H, A, B, C, D, E, R(19), 0x240CA1CC);
+ P (E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F);
+ P (D, E, F, G, H, A, B, C, R(21), 0x4A7484AA);
+ P (C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC);
+ P (B, C, D, E, F, G, H, A, R(23), 0x76F988DA);
+ P (A, B, C, D, E, F, G, H, R(24), 0x983E5152);
+ P (H, A, B, C, D, E, F, G, R(25), 0xA831C66D);
+ P (G, H, A, B, C, D, E, F, R(26), 0xB00327C8);
+ P (F, G, H, A, B, C, D, E, R(27), 0xBF597FC7);
+ P (E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3);
+ P (D, E, F, G, H, A, B, C, R(29), 0xD5A79147);
+ P (C, D, E, F, G, H, A, B, R(30), 0x06CA6351);
+ P (B, C, D, E, F, G, H, A, R(31), 0x14292967);
+ P (A, B, C, D, E, F, G, H, R(32), 0x27B70A85);
+ P (H, A, B, C, D, E, F, G, R(33), 0x2E1B2138);
+ P (G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC);
+ P (F, G, H, A, B, C, D, E, R(35), 0x53380D13);
+ P (E, F, G, H, A, B, C, D, R(36), 0x650A7354);
+ P (D, E, F, G, H, A, B, C, R(37), 0x766A0ABB);
+ P (C, D, E, F, G, H, A, B, R(38), 0x81C2C92E);
+ P (B, C, D, E, F, G, H, A, R(39), 0x92722C85);
+ P (A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1);
+ P (H, A, B, C, D, E, F, G, R(41), 0xA81A664B);
+ P (G, H, A, B, C, D, E, F, R(42), 0xC24B8B70);
+ P (F, G, H, A, B, C, D, E, R(43), 0xC76C51A3);
+ P (E, F, G, H, A, B, C, D, R(44), 0xD192E819);
+ P (D, E, F, G, H, A, B, C, R(45), 0xD6990624);
+ P (C, D, E, F, G, H, A, B, R(46), 0xF40E3585);
+ P (B, C, D, E, F, G, H, A, R(47), 0x106AA070);
+ P (A, B, C, D, E, F, G, H, R(48), 0x19A4C116);
+ P (H, A, B, C, D, E, F, G, R(49), 0x1E376C08);
+ P (G, H, A, B, C, D, E, F, R(50), 0x2748774C);
+ P (F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5);
+ P (E, F, G, H, A, B, C, D, R(52), 0x391C0CB3);
+ P (D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A);
+ P (C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F);
+ P (B, C, D, E, F, G, H, A, R(55), 0x682E6FF3);
+ P (A, B, C, D, E, F, G, H, R(56), 0x748F82EE);
+ P (H, A, B, C, D, E, F, G, R(57), 0x78A5636F);
+ P (G, H, A, B, C, D, E, F, R(58), 0x84C87814);
+ P (F, G, H, A, B, C, D, E, R(59), 0x8CC70208);
+ P (E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA);
+ P (D, E, F, G, H, A, B, C, R(61), 0xA4506CEB);
+ P (C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7);
+ P (B, C, D, E, F, G, H, A, R(63), 0xC67178F2);
+
+#undef SHR
+#undef ROTR
+#undef S0
+#undef S1
+#undef S2
+#undef S3
+#undef F0
+#undef F1
+#undef R
+#undef P
+
+ buf[0] += A;
+ buf[1] += B;
+ buf[2] += C;
+ buf[3] += D;
+ buf[4] += E;
+ buf[5] += F;
+ buf[6] += G;
+ buf[7] += H;
+}
+
+static void
+sha256_sum_update (Sha256sum *sha256,
+ const guchar *buffer,
+ gsize length)
+{
+ guint32 left, fill;
+ const guint8 *input = buffer;
+
+ if (length == 0)
+ return;
+
+ left = sha256->bits[0] & 0x3F;
+ fill = 64 - left;
+
+ sha256->bits[0] += length;
+ sha256->bits[0] &= 0xFFFFFFFF;
+
+ if (sha256->bits[0] < length)
+ sha256->bits[1]++;
+
+ if (left > 0 && length >= fill)
+ {
+ memcpy ((sha256->data + left), input, fill);
+
+ sha256_transform (sha256->buf, sha256->data);
+ length -= fill;
+ input += fill;
+
+ left = 0;
+ }
+
+ while (length >= SHA256_DATASIZE)
+ {
+ sha256_transform (sha256->buf, input);
+
+ length -= 64;
+ input += 64;
+ }
+
+ if (length)
+ memcpy (sha256->data + left, input, length);
+}
+
+static guint8 sha256_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void
+sha256_sum_close (Sha256sum *sha256)
+{
+ guint32 last, padn;
+ guint32 high, low;
+ guint8 msglen[8];
+
+ high = (sha256->bits[0] >> 29)
+ | (sha256->bits[1] << 3);
+ low = (sha256->bits[0] << 3);
+
+ PUT_UINT32 (high, msglen, 0);
+ PUT_UINT32 (low, msglen, 4);
+
+ last = sha256->bits[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ sha256_sum_update (sha256, sha256_padding, padn);
+ sha256_sum_update (sha256, msglen, 8);
+
+ PUT_UINT32 (sha256->buf[0], sha256->digest, 0);
+ PUT_UINT32 (sha256->buf[1], sha256->digest, 4);
+ PUT_UINT32 (sha256->buf[2], sha256->digest, 8);
+ PUT_UINT32 (sha256->buf[3], sha256->digest, 12);
+ PUT_UINT32 (sha256->buf[4], sha256->digest, 16);
+ PUT_UINT32 (sha256->buf[5], sha256->digest, 20);
+ PUT_UINT32 (sha256->buf[6], sha256->digest, 24);
+ PUT_UINT32 (sha256->buf[7], sha256->digest, 28);
+}
+
+#undef PUT_UINT32
+#undef GET_UINT32
+
+static gchar *
+sha256_sum_to_string (Sha256sum *sha256)
+{
+ return digest_to_string (sha256->digest, SHA256_DIGEST_LEN);
+}
+
+static void
+sha256_sum_digest (Sha256sum *sha256,
+ guint8 *digest)
+{
+ gint i;
+
+ for (i = 0; i < SHA256_DIGEST_LEN; i++)
+ digest[i] = sha256->digest[i];
+}
+
+
+/*
+ * Public API
+ */
+
+/**
+ * g_checksum_type_get_length:
+ * @checksum_type: a #GChecksumType
+ *
+ * Gets the length in bytes of digests of type @checksum_type
+ *
+ * Return value: the checksum length, or -1 if @checksum_type is
+ * not supported.
+ *
+ * Since: 2.16
+ */
+gssize
+g_checksum_type_get_length (GChecksumType checksum_type)
+{
+ gssize len = -1;
+
+ switch (checksum_type)
+ {
+ case G_CHECKSUM_MD5:
+ len = MD5_DIGEST_LEN;
+ break;
+ case G_CHECKSUM_SHA1:
+ len = SHA1_DIGEST_LEN;
+ break;
+ case G_CHECKSUM_SHA256:
+ len = SHA256_DIGEST_LEN;
+ break;
+ default:
+ len = -1;
+ break;
+ }
+
+ return len;
+}
+
+/**
+ * g_checksum_new:
+ * @checksum_type: the desired type of checksum
+ *
+ * Creates a new #GChecksum, using the checksum algorithm @checksum_type.
+ * If the @checksum_type is not known, %NULL is returned.
+ * A #GChecksum can be used to compute the checksum, or digest, of an
+ * arbitrary binary blob, using different hashing algorithms.
+ *
+ * A #GChecksum works by feeding a binary blob through g_checksum_update()
+ * until there is data to be checked; the digest can then be extracted
+ * using g_checksum_get_string(), which will return the checksum as a
+ * hexadecimal string; or g_checksum_get_digest(), which will return a
+ * vector of raw bytes. Once either g_checksum_get_string() or
+ * g_checksum_get_digest() have been called on a #GChecksum, the checksum
+ * will be closed and it won't be possible to call g_checksum_update()
+ * on it anymore.
+ *
+ * Return value: the newly created #GChecksum, or %NULL.
+ * Use g_checksum_free() to free the memory allocated by it.
+ *
+ * Since: 2.16
+ */
+GChecksum *
+g_checksum_new (GChecksumType checksum_type)
+{
+ GChecksum *checksum;
+
+ if (! IS_VALID_TYPE (checksum_type))
+ return NULL;
+
+ checksum = g_slice_new0 (GChecksum);
+ checksum->type = checksum_type;
+
+ switch (checksum_type)
+ {
+ case G_CHECKSUM_MD5:
+ md5_sum_init (&(checksum->sum.md5));
+ break;
+ case G_CHECKSUM_SHA1:
+ sha1_sum_init (&(checksum->sum.sha1));
+ break;
+ case G_CHECKSUM_SHA256:
+ sha256_sum_init (&(checksum->sum.sha256));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return checksum;
+}
+
+/**
+ * g_checksum_copy:
+ * @checksum: the #GChecksum to copy
+ *
+ * Copies a #GChecksum. If @checksum has been closed, by calling
+ * g_checksum_get_string() or g_checksum_get_digest(), the copied
+ * checksum will be closed as well.
+ *
+ * Return value: the copy of the passed #GChecksum. Use g_checksum_free()
+ * when finished using it.
+ *
+ * Since: 2.16
+ */
+GChecksum *
+g_checksum_copy (const GChecksum *checksum)
+{
+ GChecksum *copy;
+
+ g_return_val_if_fail (checksum != NULL, NULL);
+
+ copy = g_slice_new (GChecksum);
+ *copy = *checksum;
+
+ copy->digest_str = g_strdup (checksum->digest_str);
+
+ return copy;
+}
+
+/**
+ * g_checksum_free:
+ * @checksum: a #GChecksum
+ *
+ * Frees the memory allocated for @checksum.
+ *
+ * Since: 2.16
+ */
+void
+g_checksum_free (GChecksum *checksum)
+{
+ if (G_LIKELY (checksum))
+ {
+ g_free (checksum->digest_str);
+
+ g_slice_free (GChecksum, checksum);
+ }
+}
+
+/**
+ * g_checksum_update:
+ * @checksum: a #GChecksum
+ * @data: buffer used to compute the checksum
+ * @length: size of the buffer, or -1 if it is a null-terminated string.
+ *
+ * Feeds @data into an existing #GChecksum. The checksum must still be
+ * open, that is g_checksum_get_string() or g_checksum_get_digest() must
+ * not have been called on @checksum.
+ *
+ * Since: 2.16
+ */
+void
+g_checksum_update (GChecksum *checksum,
+ const guchar *data,
+ gssize length)
+{
+ g_return_if_fail (checksum != NULL);
+ g_return_if_fail (data != NULL);
+
+ if (length < 0)
+ length = strlen (data);
+
+ if (checksum->digest_str)
+ {
+ g_warning ("The checksum `%s' has been closed and cannot be updated "
+ "anymore.",
+ checksum->digest_str);
+ return;
+ }
+
+ switch (checksum->type)
+ {
+ case G_CHECKSUM_MD5:
+ md5_sum_update (&(checksum->sum.md5), data, length);
+ break;
+ case G_CHECKSUM_SHA1:
+ sha1_sum_update (&(checksum->sum.sha1), data, length);
+ break;
+ case G_CHECKSUM_SHA256:
+ sha256_sum_update (&(checksum->sum.sha256), data, length);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * g_checksum_get_string:
+ * @checksum: a #GChecksum
+ *
+ * Gets the digest as an hexadecimal string.
+ *
+ * Once this function has been called the #GChecksum can no longer be
+ * updated with g_checksum_update().
+ *
+ * Return value: the hexadecimal representation of the checksum. The
+ * returned string is owned by the checksum and should not be modified
+ * or freed.
+ *
+ * Since: 2.16
+ */
+G_CONST_RETURN gchar *
+g_checksum_get_string (GChecksum *checksum)
+{
+ gchar *str = NULL;
+
+ g_return_val_if_fail (checksum != NULL, NULL);
+
+ if (checksum->digest_str)
+ return checksum->digest_str;
+
+ switch (checksum->type)
+ {
+ case G_CHECKSUM_MD5:
+ md5_sum_close (&(checksum->sum.md5));
+ str = md5_sum_to_string (&(checksum->sum.md5));
+ break;
+ case G_CHECKSUM_SHA1:
+ sha1_sum_close (&(checksum->sum.sha1));
+ str = sha1_sum_to_string (&(checksum->sum.sha1));
+ break;
+ case G_CHECKSUM_SHA256:
+ sha256_sum_close (&(checksum->sum.sha256));
+ str = sha256_sum_to_string (&(checksum->sum.sha256));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ checksum->digest_str = str;
+
+ return checksum->digest_str;
+}
+
+/**
+ * g_checksum_get_digest:
+ * @checksum: a #GChecksum
+ * @buffer: output buffer
+ * @digest_len: an inout parameter. The caller initializes it to the size of @buffer.
+ * After the call it contains the length of the digest.
+ *
+ * Gets the digest from @checksum as a raw binary vector and places it
+ * into @buffer. The size of the digest depends on the type of checksum.
+ *
+ * Once this function has been called, the #GChecksum is closed and can
+ * no longer be updated with g_checksum_update().
+ *
+ * Since: 2.16
+ */
+void
+g_checksum_get_digest (GChecksum *checksum,
+ guint8 *buffer,
+ gsize *digest_len)
+{
+ gboolean checksum_open = FALSE;
+ gchar *str = NULL;
+ gsize len;
+
+ g_return_if_fail (checksum != NULL);
+
+ len = g_checksum_type_get_length (checksum->type);
+ g_return_if_fail (*digest_len >= len);
+
+ checksum_open = !!(checksum->digest_str == NULL);
+
+ switch (checksum->type)
+ {
+ case G_CHECKSUM_MD5:
+ if (checksum_open)
+ {
+ md5_sum_close (&(checksum->sum.md5));
+ str = md5_sum_to_string (&(checksum->sum.md5));
+ }
+ md5_sum_digest (&(checksum->sum.md5), buffer);
+ break;
+ case G_CHECKSUM_SHA1:
+ if (checksum_open)
+ {
+ sha1_sum_close (&(checksum->sum.sha1));
+ str = sha1_sum_to_string (&(checksum->sum.sha1));
+ }
+ sha1_sum_digest (&(checksum->sum.sha1), buffer);
+ break;
+ case G_CHECKSUM_SHA256:
+ if (checksum_open)
+ {
+ sha256_sum_close (&(checksum->sum.sha256));
+ str = sha256_sum_to_string (&(checksum->sum.sha256));
+ }
+ sha256_sum_digest (&(checksum->sum.sha256), buffer);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (str)
+ checksum->digest_str = str;
+
+ *digest_len = len;
+}
+
+/**
+ * g_compute_checksum_for_data:
+ * @checksum_type: a #GChecksumType
+ * @data: binary blob to compute the digest of
+ * @length: length of @data
+ *
+ * Computes the checksum for a binary @data of @length. This is a
+ * convenience wrapper for g_checksum_new(), g_checksum_get_string()
+ * and g_checksum_free().
+ *
+ * Return value: the digest of the binary data as a string in hexadecimal.
+ * The returned string should be freed with g_free() when done using it.
+ *
+ * Since: 2.16
+ */
+gchar *
+g_compute_checksum_for_data (GChecksumType checksum_type,
+ const guchar *data,
+ gsize length)
+{
+ GChecksum *checksum;
+ gchar *retval;
+
+ g_return_val_if_fail (IS_VALID_TYPE (checksum_type), NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (length > 1, NULL);
+
+ checksum = g_checksum_new (checksum_type);
+ if (!checksum)
+ return NULL;
+
+ g_checksum_update (checksum, data, length);
+ retval = g_strdup (g_checksum_get_string (checksum));
+ g_checksum_free (checksum);
+
+ return retval;
+}
+
+/**
+ * g_compute_checksum_for_string:
+ * @checksum_type: a #GChecksumType
+ * @str: the string to compute the checksum of
+ * @length: the length of the string, or -1 if the string is null-terminated.
+ *
+ * Computes the checksum of a string.
+ *
+ * Return value: the checksum as a hexadecimal string. The returned string
+ * should be freed with g_free() when done using it.
+ *
+ * Since: 2.16
+ */
+gchar *
+g_compute_checksum_for_string (GChecksumType checksum_type,
+ const gchar *str,
+ gssize length)
+{
+ g_return_val_if_fail (IS_VALID_TYPE (checksum_type), NULL);
+ g_return_val_if_fail (str != NULL, NULL);
+
+ if (length < 0)
+ length = strlen (str);
+
+ return g_compute_checksum_for_data (checksum_type, (const guchar *) str, length);
+}
+
+#define __G_CHECKSUM_C__
+#include "galiasdef.c"
diff --git a/src/gchecksum.h b/src/gchecksum.h
new file mode 100644
index 0000000..8f7d808
--- /dev/null
+++ b/src/gchecksum.h
@@ -0,0 +1,72 @@
+/* gchecksum.h - data hashing functions
+ *
+ * Copyright (C) 2007 Emmanuele Bassi <ebassi@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_CHECKSUM_H__
+#define __G_CHECKSUM_H__
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GChecksumType:
+ * @G_CHECKSUM_MD5: Use the MD5 hashing algorithm
+ * @G_CHECKSUM_SHA1: Use the SHA-1 hashing algorithm
+ * @G_CHECKSUM_SHA256: Use the SHA-256 hashing algorithm
+ *
+ * The hashing algorithm to be used by #GChecksum when performing the
+ * digest of some data.
+ *
+ * Note that the #GChecksumType enumeration may be extended at a later
+ * date to include new hashing algorithm types.
+ *
+ * Since: 2.16
+ */
+typedef enum {
+ G_CHECKSUM_MD5,
+ G_CHECKSUM_SHA1,
+ G_CHECKSUM_SHA256
+} GChecksumType;
+
+typedef struct _GChecksum GChecksum;
+
+gssize g_checksum_type_get_length (GChecksumType checksum_type);
+
+GChecksum * g_checksum_new (GChecksumType checksum_type);
+GChecksum * g_checksum_copy (const GChecksum *checksum);
+void g_checksum_free (GChecksum *checksum);
+void g_checksum_update (GChecksum *checksum,
+ const guchar *data,
+ gssize length);
+G_CONST_RETURN gchar *g_checksum_get_string (GChecksum *checksum);
+void g_checksum_get_digest (GChecksum *checksum,
+ guint8 *buffer,
+ gsize *digest_len);
+
+gchar *g_compute_checksum_for_data (GChecksumType checksum_type,
+ const guchar *data,
+ gsize length);
+gchar *g_compute_checksum_for_string (GChecksumType checksum_type,
+ const gchar *str,
+ gssize length);
+
+G_END_DECLS
+
+#endif /* __G_CHECKSUM_H__ */
diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c
index e6d0ced..5e0eaca 100644
--- a/src/itdb_itunesdb.c
+++ b/src/itdb_itunesdb.c
@@ -3645,8 +3645,8 @@ static void mk_mhit (WContents *cts, Itdb_Track *track)
put16lint (cts, track->gapless_track_flag);
put16lint (cts, track->gapless_album_flag);
put32_n0 (cts, 23);
- put32lint (cts, track->id); /* Needed on fat nanos/ipod classic to get art
- * in the right sidepane (mhii_link) */
+ put32lint (cts, track->mhii_link); /* Needed on fat nanos/ipod classic to get art
+ * in the right sidepane (mhii_link) */
put32_n0 (cts, 8); /* padding */
}
diff --git a/src/ithumb-writer.c b/src/ithumb-writer.c
index 936c4b3..a5629c3 100644
--- a/src/ithumb-writer.c
+++ b/src/ithumb-writer.c
@@ -1,5 +1,4 @@
-/* Time-stamp: <2008-05-30 21:49:11 jcs>
- *
+/*
* Copyright (C) 2005 Christophe Fergeau
*
* URL: http://www.gtkpod.org/libgpod.html
@@ -1295,10 +1294,17 @@ ithmb_rearrange_existing_thumbnails (Itdb_DB *db,
Itdb_Track *track = gl->data;
g_return_val_if_fail (track, FALSE);
+ g_return_val_if_fail (track->artwork, FALSE);
thumb = track->artwork->thumbnail;
if (!itdb_track_has_thumbnails (track)) {
+ /* skip: track has no thumbnails */
continue;
}
+ if (track->artwork->dbid == 0) {
+ /* skip: sparse artwork, has already been
+ written */
+ continue;
+ }
if (thumb->data_type == ITDB_THUMB_TYPE_IPOD) {
Itdb_Thumb_Ipod_Item *item;
item = itdb_thumb_ipod_get_item_by_type (thumb,
@@ -1440,6 +1446,11 @@ itdb_write_ithumb_files (Itdb_DB *db)
if (!itdb_track_has_thumbnails (track)) {
continue;
}
+ if (track->artwork->dbid == 0) {
+ /* Use sparse artwork -- already written
+ elsewhere */
+ continue;
+ }
type = track->artwork->thumbnail->data_type;
if (type != ITDB_THUMB_TYPE_IPOD) {
GList *it;