static int write_mhni (Itdb_DB *db, Itdb_Thumb_Ipod_Item *item, iPodBuffer *buffer) { MhniHeader *mhni; unsigned int total_bytes; int bytes_written; iPodBuffer *sub_buffer; const Itdb_ArtworkFormat *format; if (item == NULL) { return -1; } mhni = (MhniHeader *)init_header (buffer, "mhni", sizeof (MhniHeader)); if (mhni == NULL) { return -1; } total_bytes = get_gint32 (mhni->header_len, buffer->byte_order); mhni->total_len = get_gint32 (total_bytes, buffer->byte_order); format = item->format; mhni->format_id = get_gint32 (format->format_id, buffer->byte_order); mhni->image_width = get_gint16 (item->width, buffer->byte_order); mhni->image_height = get_gint16 (item->height, buffer->byte_order); mhni->image_size = get_gint32 (item->size, buffer->byte_order); mhni->ithmb_offset = get_gint32 (item->offset, buffer->byte_order); mhni->vertical_padding = get_gint16 (item->vertical_padding, buffer->byte_order); mhni->horizontal_padding = get_gint16 (item->horizontal_padding, buffer->byte_order); sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes); if (sub_buffer == NULL) { return -1; } bytes_written = write_mhod_type_3 (item->filename, sub_buffer); ipod_buffer_destroy (sub_buffer); if (bytes_written == -1) { return -1; } total_bytes += bytes_written; mhni = ipod_buffer_get_pointer (buffer); mhni->total_len = get_gint32 (total_bytes, buffer->byte_order); /* Only update number of children when all went well to try to get * something somewhat consistent when there are errors */ mhni->num_children = get_gint32 (1, buffer->byte_order); dump_mhni (mhni); return total_bytes; }
static guchar * unpack_RGB_555 (guint16 *pixels, guint bytes_len, guint byte_order) { guchar *result; guint i; g_return_val_if_fail (bytes_len < 2*(G_MAXUINT/3), NULL); result = g_malloc ((bytes_len/2) * 3); for (i = 0; i < bytes_len/2; i++) { guint16 cur_pixel; /* FIXME: endianness */ cur_pixel = get_gint16 (pixels[i], byte_order); /* Unpack pixels */ result[3*i] = (cur_pixel & RED_MASK_555) >> RED_SHIFT_555; result[3*i+1] = (cur_pixel & GREEN_MASK_555) >> GREEN_SHIFT_555; result[3*i+2] = (cur_pixel & BLUE_MASK_555) >> BLUE_SHIFT_555; /* Normalize color values so that they use a [0..255] range */ result[3*i] <<= (8 - RED_BITS_555); result[3*i+1] <<= (8 - GREEN_BITS_555); result[3*i+2] <<= (8 - BLUE_BITS_555); } return result; }
static int write_mhsd (Itdb_DB *db, iPodBuffer *buffer, enum MhsdType type) { ArtworkDB_MhsdHeader *mhsd; unsigned int total_bytes; int bytes_written; iPodBuffer *sub_buffer; g_assert (type >= MHSD_TYPE_MHLI); g_assert (type <= MHSD_TYPE_MHLF); mhsd = (ArtworkDB_MhsdHeader *)init_header (buffer, "mhsd", sizeof (ArtworkDB_MhsdHeader)); if (mhsd == NULL) { return -1; } total_bytes = get_gint32 (mhsd->header_len, buffer->byte_order); mhsd->total_len = get_gint32 (total_bytes, buffer->byte_order); mhsd->index = get_gint16 (type, buffer->byte_order); bytes_written = -1; sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes); if (sub_buffer == NULL) { return -1; } switch (type) { case MHSD_TYPE_MHLI: bytes_written = write_mhli (db, sub_buffer); break; case MHSD_TYPE_MHLA: bytes_written = write_mhla (db, sub_buffer); break; case MHSD_TYPE_MHLF: bytes_written = write_mhlf (db, sub_buffer); break; } ipod_buffer_destroy (sub_buffer); if (bytes_written == -1) { return -1; } else { total_bytes += bytes_written; mhsd = ipod_buffer_get_pointer (buffer); mhsd->total_len = get_gint32 (total_bytes, buffer->byte_order); } dump_mhsd (mhsd); return total_bytes; }
static int write_mhod_type_1 (gchar *string, iPodBuffer *buffer) { ArtworkDB_MhodHeaderString *mhod; unsigned int total_bytes; int len; int padding; g_assert (string != NULL); total_bytes = sizeof (ArtworkDB_MhodHeaderString); mhod = (ArtworkDB_MhodHeaderString *)init_header (buffer, "mhod", total_bytes); if (mhod == NULL) { return -1; } mhod->total_len = get_gint32 (total_bytes, buffer->byte_order); /* Modify header length, since iTunes only puts the length of * MhodHeader in header_len */ mhod->header_len = get_gint32 (sizeof (ArtworkDB_MhodHeader), buffer->byte_order); mhod->encoding = get_gint32 (0x01, buffer->byte_order); len = strlen (string); mhod->string_len = get_gint32 (len, buffer->byte_order); padding = 4 - ( (total_bytes + len) % 4 ); if (padding == 4) padding = 0; mhod->padding_len = padding; mhod->type = get_gint16 (0x01, buffer->byte_order); /* Make sure we have enough free space to write the string */ ipod_buffer_maybe_grow (buffer, len + padding); mhod = ipod_buffer_get_pointer (buffer); if (mhod == NULL) { return -1; } memcpy (mhod->string, string, len); total_bytes += len + padding; mhod->total_len = get_gint32 (total_bytes, buffer->byte_order); dump_mhod_string (mhod); return total_bytes; }
static int write_mhod (Itdb_DB *db, Itdb_Thumb_Ipod_Item *thumb, iPodBuffer *buffer) { ArtworkDB_MhodHeader *mhod; unsigned int total_bytes; int bytes_written; iPodBuffer *sub_buffer; if (thumb == NULL) { return -1; } mhod = (ArtworkDB_MhodHeader *) init_header (buffer, "mhod", sizeof (ArtworkDB_MhodHeader)); if (mhod == NULL) { return -1; } total_bytes = sizeof (ArtworkDB_MhodHeader); mhod->total_len = get_gint32 (total_bytes, buffer->byte_order); mhod->type = get_gint16 (MHOD_TYPE_LOCATION, buffer->byte_order); sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes); if (sub_buffer == NULL) { return -1; } bytes_written = write_mhni (db, thumb, sub_buffer); ipod_buffer_destroy (sub_buffer); if (bytes_written == -1) { return -1; } total_bytes += bytes_written; mhod = ipod_buffer_get_pointer (buffer); mhod->total_len = get_gint32 (total_bytes, buffer->byte_order); dump_mhod (mhod); return total_bytes; }
static int write_mhba (Itdb_PhotoAlbum *album, iPodBuffer *buffer) { GList *it; MhbaHeader *mhba; iPodBuffer *sub_buffer; unsigned int total_bytes; unsigned int bytes_written; mhba = (MhbaHeader *)init_header (buffer, "mhba", sizeof (MhbaHeader)); if (mhba == NULL) { return -1; } mhba->num_mhods = get_gint32(1, buffer->byte_order); mhba->num_mhias = get_gint32(g_list_length (album->members), buffer->byte_order); mhba->album_id = get_gint32(album->album_id, buffer->byte_order); mhba->unk024 = get_gint32(album->unk024, buffer->byte_order); mhba->unk028 = get_gint16(album->unk028, buffer->byte_order); mhba->album_type = album->album_type; mhba->playmusic = album->playmusic; mhba->repeat = album->repeat; mhba->random = album->random; mhba->show_titles = album->show_titles; mhba->transition_direction = album->transition_direction; mhba->slide_duration = get_gint32(album->slide_duration, buffer->byte_order); mhba->transition_duration = get_gint32(album->transition_duration, buffer->byte_order); mhba->unk044 = get_gint32(album->unk044, buffer->byte_order); mhba->unk048 = get_gint32(album->unk048, buffer->byte_order); mhba->song_id = get_gint64(album->song_id, buffer->byte_order); mhba->prev_album_id = get_gint32(album->prev_album_id, buffer->byte_order); total_bytes = get_gint32 (mhba->header_len, buffer->byte_order); /* FIXME: Write other mhods */ /* Write album title */ sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes); if (sub_buffer == NULL) { return -1; } bytes_written = write_mhod_type_1 (album->name, sub_buffer); ipod_buffer_destroy (sub_buffer); if (bytes_written == -1) { return -1; } total_bytes += bytes_written; for (it = album->members; it != NULL; it = it->next) { Itdb_Artwork *photo = it->data; g_return_val_if_fail (photo, -1); sub_buffer = ipod_buffer_get_sub_buffer (buffer, total_bytes); if (sub_buffer == NULL) { return -1; } bytes_written = write_mhia (photo->id, sub_buffer); ipod_buffer_destroy (sub_buffer); if (bytes_written == -1) { return -1; } total_bytes += bytes_written; } mhba = ipod_buffer_get_pointer (buffer); mhba->total_len = get_gint32( total_bytes, buffer->byte_order ); dump_mhba ( mhba ); return total_bytes; }
static int write_mhod_type_3 (gchar *string, iPodBuffer *buffer) { ArtworkDB_MhodHeaderString *mhod; unsigned int total_bytes; glong len; const gint g2l = sizeof (gunichar2); gunichar2 *utf16, *strp; int i, padding; g_assert (string != NULL); total_bytes = sizeof (ArtworkDB_MhodHeaderString); mhod = (ArtworkDB_MhodHeaderString *) init_header (buffer, "mhod", total_bytes); if (mhod == NULL) { return -1; } mhod->total_len = get_gint32 (total_bytes, buffer->byte_order); /* Modify header length, since iTunes only puts the length of * MhodHeader in header_len */ mhod->header_len = get_gint32 (sizeof (ArtworkDB_MhodHeader), buffer->byte_order); mhod->type = get_gint16 (3, buffer->byte_order); /* FIXME: Tidy this up, combine cases more */ /* Some magic: endianess-reversed (BE) mobile phones use UTF8 * (version 1) with padding, standard iPods (LE) use UTF16 * (version 2).*/ switch (buffer->byte_order) { case G_LITTLE_ENDIAN: utf16 = g_utf8_to_utf16 (string, -1, NULL, &len, NULL); if (utf16 == NULL) { return -1; } mhod->encoding = 2; /* 8 bit field, no need to byteswap */ /* number of bytes of the string encoded in UTF-16 */ mhod->string_len = get_gint32 (g2l * len, buffer->byte_order); padding = 4 - ( (total_bytes + g2l*len) % 4 ); if (padding == 4) padding = 0; mhod->padding_len = padding; /* 8 bit field, no need to byteswap */ total_bytes += g2l*len + padding; /* Make sure we have enough free space to write the string */ ipod_buffer_maybe_grow (buffer, g2l*len + padding); mhod = ipod_buffer_get_pointer (buffer); if (mhod == NULL) { g_free (utf16); return -1; } strp = (gunichar2 *)mhod->string; for (i = 0; i < len; i++) { strp[i] = get_gint16 (utf16[i], buffer->byte_order); } g_free (utf16); memset (mhod->string + g2l*len, 0, padding); break; case G_BIG_ENDIAN: mhod->encoding = 1; /* 8 bit field, no need to byteswap */ /* FIXME: len isn't initialized */ mhod->string_len = get_gint32 (len, buffer->byte_order); /* pad string if necessary */ /* e.g. len = 7 bytes, len%4 = 3, 4-3=1 -> requires 1 byte padding */ padding = 4 - ( (total_bytes + len) % 4 ); if (padding == 4) padding = 0; mhod->padding_len = padding; /* 8 bit field, no need to byteswap */ /* Make sure we have enough free space to write the string */ ipod_buffer_maybe_grow (buffer, len+padding); mhod = ipod_buffer_get_pointer (buffer); if (mhod == NULL) { return -1; } memcpy (mhod->string, string, len); memset (mhod->string + len, 0, padding); total_bytes += (len+padding); } mhod->total_len = get_gint32 (total_bytes, buffer->byte_order); dump_mhod_string (mhod); return total_bytes; }