FANDOM


IntroductionEdit

iriver H10 media database, which is necessary for playback and navigation in MUSIC mode, consists of a number of files: H10DB.hdr, H10DB.dat, and H10DB_*.idx (typically H10DB_@DEV.idx, H10DB_FPTH.idx, H10DB_FNAM.idx, H10DB_FRMT.idx, H10DB_TIT2.idx, H10DB_TPE1.idx, H10DB_TALB.idx, H10DB_TCON.idx, H10DB_@DU3.idx, H10DB_@DU4.idx, H10DB_@DU5.idx, H10DB_TRCK.idx, H10DB_@DU1.idx, and H10DB_@DU2.idx). These files are generated by EasyH10, iriver Plus, or Windows Media Player 10 and stored in \System\DATA folder in H10 player's hard disc drive. Even H10 player updates media database during the playback to store dynamic information such as recent playback time, user ratings, and playback counts.

H10DB.dat is a list of records that store music information. Each record has 24 (= 2 + 22) fields such as track title, artist, album, genre, year, genre, rating, recent play time, play count, etc. The MUSIC mode of iriver H10 player does not read music information from actual files but relies only on these records for displaying music information. When a user listens to the music with a player, the number of records increases because, whenever a music file is about to be played, H10 player duplicates the record for the file, adds the duplicated new record into the list, and inactivate the original record. Therefore, H10DB.dat may contain a number of inactive records.

H10DB.hdr stores general information among H10 media database such as: the number of records in H10DB.dat; the number of inactive records; path to H10DB.dat; offsets to all records and fields in H10DB.dat (for quick access); and field descriptor that defines 22 fields in H10DB.dat record. The structure of H10DB.hdr slightly differs depending on the firmware type (UMS or MTP) and HDD capacity (5/6GB or 20GB).

H10DB_*.idx (typically 14 files) store sorted indexes that point to H10DB.dat records. Each file has a different sorting order. For example, H10DB_FPTH.idx sorts records in alphabetical order of file paths; H10DB_TIT2.idx in alphabetical order of track titles; H10DB_TPE1.idx in alphabetical order of track artists; H10DB_@DU3.idx in numerical order of user ratings; H10DB_TRCK.idx in numerical order of track number, etc. These sorted indexes are used for displaying music tracks in different orders: e.g., alphabetical order of track title/artist/album; and numerical order of track number in an album. Since the H10 firmware seems to implement an efficient search method such as binary search, all indexes must be arranged in proper orders as the firmware assumes. If not, a player may lose sight of some music files, show duplicated entries, or show wrong information because of the inconsistency.

This document describes the structure of H10 media database. Since the information is obtained from reverse engineering and analysis, it may not be correct. We have already developed a tool (EasyH10 CUI version with -D option) to dump the content of a database in a text. If you are interested, we suggest you to use it to view an actual database at hand.

TypedefsEdit

This document defines four types for explanation. Values in uint16_t, uint32_t, and ucs2_char_t are stored in little endian byte-order.

uint8_t 
8 bit unsigned integer
uint16_t 
16 bit unsigned integer (little endian)
uint32_t 
32 bit unsigned integer (little endian)
ucs2_char_t 
16 bit UCS-2 character (little endian)

ConstantsEdit

The document uses the following constants.

#define	H10DB_MAX_PATH		256

#if	H10_MODEL == INTERNATIONAL			/* H10 International models. */
#define	H10DB_HDR_PADDING	1032
#elif	H10_MODEL == NORTHAMERICAN			/* H10 North American models. */
#define	H10DB_HDR_PADDING	0
#endif

#if	H10_CAPACITY == 5000 || H10_CAPACITY == 6000	/* H10 5GB and 6GB models. */
#define	H10DB_MAX_DAT_ENTRIES	4000
#elif	H10_CAPACITY == 20000				/* H10 20GB models. */
#define	H10DB_MAX_DAT_ENTRIES	8000
#endif

H10DB.hdrEdit

H10DB.hdr stores general information among H10 media database such as: the number of records in H10DB.dat; the number of inactive records; path to H10DB.dat; offsets to all records and fields in H10DB.dat (for quick access); and field descriptor that defines 22 fields in H10DB.dat record. The structure of H10DB.hdr slightly differs depending on the firmware type (UMS or MTP) and HDD capacity (5/6GB or 20GB).

DefinitionEdit

typedef struct {
	uint32_t	id;
	uint32_t	field_type;
	uint32_t	max_length;
	uint32_t	unknown5;
	uint32_t	unknown6;
	uint32_t	has_index;
	uint32_t	unknown7;
	uint32_t	unknown8;
	ucs2_char_t	idx_pathname[H10DB_MAX_PATH];
} h10db_fd_t;

typedef struct {
	uint32_t	unknown1;
	uint32_t	unknown2;
	ucs2_char_t	pathname_dat[H10DB_MAX_PATH];
	uint32_t	unknown3;
	ucs2_char_t	pathname_hdr[H10DB_MAX_PATH];
	uint32_t	unknown4;
	uint32_t	num_dat_records;
	uint32_t	num_dat_inactive_records;
	uint32_t	num_dat_fields;
	h10db_fd_t	fd[num_dat_fields];
	uint32_t	max_dat_field_offsets[num_dat_fields];
	uint32_t	dat_size;
	uint8_t		padding[H10DB_HDR_PADDING];
	uint16_t	dat_field_offset[num_dat_fields][H10DB_MAX_DAT_ENTRIES];
	uint32_t	dat_record_offset[H10DB_MAX_DAT_ENTRIES+1];
} h10db_hdr_t;
 
h10db_hdr_t hdr;

SemanticsEdit

h10db_hdr_tEdit

unknown1 
an integer value reserved as zero.
unknown2 
an integer value reserved as zero.
pathname_dat 
a UCS-2 null-terminated string that specifies the path and file name of H10DB.dat. The typical value of this field is "System\DATA\H10DB.dat".
unknown3 
an integer value reserved as one.
pathname_hdr 
a UCS-2 null-terminated string that specifies the path and file name of H10DB.hdr. The typical value of this field is "System\DATA\H10DB.hdr".
unknown4 
an integer value reserved for an unknown purpose. The typical value of this field is 0x00000428 (for the international players) or 0x00000D10 (for the North Americal players).
num_dat_records 
an integer value that indicates the number of records in H10DB.dat. This figure includes inactivated records.
num_dat_inactive_records 
an integer value that indicates the number of inactive (unused) records in H10DB.dat. The number of actual music files is calculated by (num_dat_records - num_dat_inactive_records).
num_dat_fields 
an integer value that specifies the number of fields in an database entry. The value seems to be fixed as 22.
fd 
an array of 22 field descriptors. See the semantics of field descriptor (h10db_fd_t).
max_dat_field_offsets 
an array of 22 integer values. Given an integer value i, max_dat_field_offsets[i] indicates the latest offset position of field #i within a record. These values can be calculated as follows:
max_dat_field_offset[0] = 8;
max_dat_field_offset[i+1] = max_dat_field_offset[i] + (fd[i].field_type == 1 ? fd[i].max_length*sizeof(ucs2_char_t) : fd[i].max_length);
The international H10 players have the following values:
max_dat_field_offset = {8, 12, 268, 524, 528, 608, 688, 768, 808, 812, 816, 820, 824, 828, 832, 836, 840, 844, 848, 852, 932, 936};
dat_size 
an integer value that indicates file size of H10DB.dat
padding 
filled by zero for the international players.
dat_field_offset 
a two-dimentional array of integer values that indicate offset positions of fields for each record. See the explanation in dat_record_offset.
dat_record_offset 
an array of (H10DB_MAX_DAT_ENTRIES+1) integer values that indicate offset position for each record. Given an integer value i no larger than num_dat_records, hdr.dat_record_offset[i] represents the offset position where record #i begins in H10DB.dat. hdr.dat_record_offset[num_dat_records] must be equal to dat_size. Given an integer value j, (hdr.dat_record_offset[i] + hdr.dat_field_offset[i][j]) represents the offset position where field #j of record #i begins in H10DB.dat.

h10db_fd_tEdit

id 
an integer value that represents an identifier of a field.
field_type 
an integer value that specifies the field type (1: UCS-2; 2: uint32_t). This value also indicates calculation method of check value used in H10DB_*.idx (1: CRC-32; 2: copy of actual value).
max_length 
an integer value that specifies the maximum size or length of the field. If (field_type == 1), this value must be interpreted as maximum number of UCS-2 characters. If (field_type == 2), it must be interpreted as size in bytes. Therefore, if (field_type == 1), multiplying it by sizeof(ucs2_char_t) gives the size in bytes.
unknown5 
an integer value reserved as zero.
unknown6 
an integer value reserved as zero.
has_index 
an integer value that implies the existence of sorted index (H10DB_*.idx) for this field.
unknown7 
an integer value reserved as zero.
unknown8 
an integer value reserved as zero.
idx_pathname 
a UCS-2 null-terminated string that represents a path/file name to an index file. This value is empty string if (has_index == 0).

The following code shows the actual field descriptor used in the international players.

h10db_fd_t fd[] = {
    {0x0000F001, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_@DEV.idx"},
    {0x0000F002, 1, 128, 0, 0, 1, 0, 0, L"System\DATA\H10DB_FPTH.idx"},
    {0x0000F003, 1, 128, 0, 0, 1, 0, 0, L"System\DATA\H10DB_FNAM.idx"},
    {0x0000F00A, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_FRMT.idx"},
    {0x0000002E, 1,  40, 0, 0, 1, 0, 0, L"System\DATA\H10DB_TIT2.idx"},
    {0x0000003C, 1,  40, 0, 0, 1, 0, 0, L"System\DATA\H10DB_TPE1.idx"},
    {0x0000001C, 1,  40, 0, 0, 1, 0, 0, L"System\DATA\H10DB_TALB.idx"},
    {0x0000001F, 1,  20, 0, 0, 1, 0, 0, L"System\DATA\H10DB_TCON.idx"},
    {0x0000E002, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_@DU3.idx"},
    {0x0000E003, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_@DU4.idx"},
    {0x0000E004, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_@DU5.idx"},
    {0x0000E005, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x00000043, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_TRCK.idx"},
    {0x0000004E, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x0000F009, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x0000F007, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x0000F006, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x0000F005, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x0000E000, 2,   4, 0, 0, 1, 0, 0, L"System\DATA\H10DB_@DU1.idx"},
    {0x0000E001, 1,  40, 0, 0, 1, 0, 0, L"System\DATA\H10DB_@DU2.idx"},
    {0x00000083, 2,   4, 0, 0, 0, 0, 0, L""},
    {0x00000084, 1,  64, 0, 0, 0, 0, 0, L""},
};

H10DB.datEdit

H10DB.dat is a list of records that store music information. Each record has 24 (= 2 + 22) fields such as track title, artist, album, genre, year, genre, rating, recent play time, play count, etc. The MUSIC mode of iriver H10 player does not read music information from actual files but relies only on these records for displaying music information. When a user listens to the music with a player, the number of records increases because, whenever a music file is about to be played, H10 player duplicates the record for the file, adds the duplicated new record into the list, and inactivate the original record. Therefore, H10DB.dat may contain a number of inactive records.

UCS-2 string in H10DB.dat has variable size (length) to save the disk space. The actual size (in bytes) should be calculated from hdr.dat_field_offset. For example, Given a record #i, the size of file_path (field #1) UCS-2 string field is calculated as the following:

(hdr.dat_field_offset[i][1+1] - hdr.dat_field_offset[i][1])

Similarly, the size of title (field #4) UCS-2 string should be calculated as the following:

(hdr.dat_field_offset[i][4+1] - hdr.dat_field_offset[i][4])

DefinitionEdit

typedef struct {
	uint32_t	status;
	uint32_t	unknown1;

	uint32_t	unknown2;		/* field # 0 */
	ucs2_char_t	file_path[];		/* field # 1 */
	ucs2_char_t	file_name[];		/* field # 2 */
	uint32_t	media_type;		/* field # 3 */
	ucs2_char_t	title[];		/* field # 4 */
	ucs2_char_t	artist[];		/* field # 5 */
	ucs2_char_t	album[];		/* field # 6 */
	ucs2_char_t	genre[];		/* field # 7 */
	uint32_t	rating;			/* field # 8 */
	uint32_t	revision;		/* field # 9 */
	uint32_t	recent_play;		/* field #10 */
	uint32_t	unknown3;		/* field #11 */
	uint32_t	number;			/* field #12 */
	uint32_t	year;			/* field #13 */
	uint32_t	filesize;		/* field #14 */
	uint32_t	duration;		/* field #15 */
	uint32_t	samplerate;		/* field #16 */
	uint32_t	bitrate;		/* field #17 */
	uint32_t	unknown4;		/* field #18 */
	ucs2_char_t	unknown5[];		/* field #19 */
	uint32_t	unknown6;		/* field #20 */
	ucs2_char_t	unknown7[];		/* field #21 */
};

h10db_dat_t dat[hdr.num_dat_records];

SemanticsEdit

status 
an integer that specifies whether this element is active (0) or not (1).
unknown1 
an integer value reserved as zero.
unknown2 
an integer value reserved as zero.
file_path 
a UCS-2 string (variable-length) that represents path to a music file.
file_name 
a UCS-2 string (variable-length) that represents name of a music file.
media_type 
an integer value reserved as zero.
title 
a UCS-2 string (variable-length) that represents track title.
artist 
a UCS-2 string (variable-length) that represents track artist.
album 
a UCS-2 string (variable-length) that represents track album.
genre 
a UCS-2 string (variable-length) that represents track genre.
rating 
an integer value that indicates rating set by a user.
revision 
an integer value that represents the play count.
recent_play 
an interger value that represents recent playback time. This value is elapsed seconds from "Sat Jan 01 00:00:00 2000".
unknown3 
an integer value reserved as zero.
number 
an integer value that represents track number.
year 
an integer value that represents track year.
filesize 
an integer value that represents file size in bytes.
duration 
an integer value that represents track length in seconds.
samplerate 
an integer value that represents sample rate in [Hz].
bitrate 
an integer value that represents bitrate in [bps].
unknown4 
an integer value reserved as zero.
unknown5 
a UCS-2 string (variable-length) used for unknown purpose. The typical value is empty string.
unknown6 
an integer value reserved as zero.
unknown7 
a UCS-2 string (variable-length) used for unknown purpose. The typical value is empty string.

H10DB_*.idxEdit

H10DB_*.idx (typically 14 files) store sorted indexes that point to H10DB.dat records. Each file has a different sorting order. For example, H10DB_FPTH.idx sorts records in alphabetical order of file paths; H10DB_TIT2.idx in alphabetical order of track titles; H10DB_TPE1.idx in alphabetical order of track artists; H10DB_@DU3.idx in numerical order of user ratings; H10DB_TRCK.idx in numerical order of track number, etc. These sorted indexes are used for displaying music tracks in different orders: e.g., alphabetical order of track title/artist/album; and numerical order of track number in an album. Since the H10 firmware seems to implement an efficient search method such as binary search, all indexes must be arranged in proper orders as the firmware assumes. If not, a player may lose sight of some music files, show duplicated entries, or show wrong information because of the inconsistency.

The following table shows a list of index files and respective sorting order and check_value type obtained from H10 [5GB] International firmware 2.05. This table can be obtained from field descriptor in H10DB.hdr.

Index file name relevant field in H10DB record sorting order check_value type
H10DB_@DEV.idx unknown2 numerical actual value
H10DB_FPTH.idx file_path alphabetical CRC-32
H10DB_FNAM.idx file_name alphabetical CRC-32
H10DB_FRMT.idx media_type numerical actual value
H10DB_TIT2.idx title alphabetical CRC-32
H10DB_TPE1.idx artist alphabetical CRC-32
H10DB_TALB.idx album alphabetical CRC-32
H10DB_TCON.idx genre alphabetical CRC-32
H10DB_@DU3.idx rating numerical actual value
H10DB_@DU4.idx revision numerical actual value
H10DB_@DU5.idx recent_play numerical actual value
H10DB_TRCK.idx number numerical actual value
H10DB_@DU1.idx unknwon4 numerical actual value
H10DB_@DU2.idx unknown5 alphabetical CRC-32

DefinitionEdit

Each H10DB_*.idx file consists of an array whose element is described as h10db_idx_t:

typedef struct {
	uint32_t status;
	uint32_t entry_index;
	uint32_t check_value;
} h10db_idx_t;

h10db_idx_t idx[hdr.num_dat_records];

SemanticsEdit

status 
an integer value that specifies whether this element is active (0) or not (1).
entry_index 
a zero-based index value (integer) that points to a record in the media database (i.e., dat[entry_index]).
check_value 
an integer value that stores either CRC-32 (for UCS-2 string field) or actual value (for uint32_t field) of a relevant field in a record.

How to calculate CRC-32 value Edit

CRC-32 value of UCS-2 string is calculated with the following parameters:

#define POLYNOMIAL             0x04C11DB7
#define INITIAL_REMAINDER      0x00000000
#define FINAL_XOR_VALUE        0x00000000
#define REFLECT_DATA           1
#define REFLECT_REMAINDER      1
#define CHECK_VALUE            0x2DFD2D88

Before calculating a CRC value, all UCS-2 characters in a string must be lower-cased.

How to lower-case UCS-2 characters Edit

There is an ambiguity for converting upper-case characters into lower-case characters in terms of the treatment of European characters (e.g., À and à Δ and δ ) As the result of our experiments, EasyH10 implements the following function to convert only US-ASCII characters.

ucs2_char_t ucs2lower(ucs2_char_t ch)
{
	/* iriver only converts what-is-called US-ASCII characters. */
	if (!(ch & 0xFF80)) {
		ch = tolower(ch);
	}
	return ch;
}

Note for sorting UCS-2 strings Edit

The following function (ucs2comp) implements a comparison function used for sorting UCS-2 string values. In addition to converting lower-case characters to upper-case, we must move empty string latter than any other values.

#define	COMP(a, b)	((a)>(b))-((a)<(b))

ucs2_char_t ucs2upper(ucs2_char_t ch)
{
	/* iriver only converts what we call one-bytes characters. */
	/* We must limit the range of case conversion. */
	if (!(ch & 0xFF80)) {
		ch = toupper(ch);
	}
	return ch;
}

int ucs2icmp(const ucs2_char_t* x, const ucs2_char_t* y)
{
	ucs2_char_t a, b;

	do {
		a = ucs2upper(*x);
		b = ucs2upper(*y);
		if (!*x || !*y) {
			break;
		}
		x++;
		y++;
	} while (a == b);
	return COMP(a, b);
}

int ucs2comp(ucs2_char_t* x, ucs2_char_t* y)
{
	/* It seems to be safer to move elements latter that have empty value. */
	/* We must ignore case during sorting, or H10 fails to recognize music files. */
	if (!x || !*x) {
		return ((!y || !*y) ? 0 : 1);
	} else {
		return ((!y || !*y) ? -1 : ucs2icmp(x, y));
	}
}

About this document Edit

Acknowledgement Edit

I thank Badger for the structure information of H10DB.hdr, Toby Corkindale for the experimental implementation of database construction written in Perl (iriver.pm), and Jevin for the CRC calculation in a MisticRiver thread, H10 database reverse ingeneering.

License Edit

This document was initially written by Nyaochi, an author of EasyH10 software. It is released under GNU Free Documentation License (GFDL).

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.