created: | 2011-05-25 |
---|---|
updated: | 2011-05-26 |
SanDisk’s portable audio player Sansa Clip+ and possibly others create a music database everytime new files are added to the device. The format is proprietary and there is no official documentation available from SanDisk. However in this post I’ll try to explain the structure of MTABLE.SYS and parts of RES_INFO.SYS which was obtained by reverse engineering.
Note that integer values are stored in little endian byte order.
The file MTABLE.SYS in the root directory of the Clip+ contains two sections, a tag database and lookup table, and has a fixed filesize.
The tag database starts at offset 0 and consists of a header and a (by design) limited number of entries. It contains track information like artist name, song title, album name and so on…
Its header is 28 bytes long and consists of seven data fields, each four bytes long.
Length | Description |
---|---|
4 | Length of tag database in bytes, including the following header data |
4 | # of songs in MUSIC folder or 0xfffffffe |
4 | 0x00 (unknown) |
4 | # of tracks in AUDIOBOOKS |
4 | # of recordings (both radio and voice) |
4 | 0x00 (unknown) |
4 | # of podcasts |
For each file that is recognized as playable audio file by the Clip+ an entry in the tag database is created. The high-level structure is quite easy to describe: An entry consists of a fixed size header followed by a fixed number of fields, each terminated with two null bytes (0x00) because some fields are UTF-16 encoded and thus one null byte wouldn’t be “enough”. An empty field is indicated by the value 0xffff.
A few notes regarding the table below:
Length | Description |
---|---|
2 | 0x00 (unknown) |
2 | String encoding
|
2 | File type/location
|
2 | File flags (bitmask)
|
2 | Some kind of song ID. The value increases for every recording and file uploaded with WMP. 0x0000 for files transfered in mass-storage mode. |
10 | 0x00 (unknown) |
– | Path of the file on the device, mmc:0:\MUSIC\ for example |
2 | 0x00 |
– | Filename |
2 | 0x00 |
max 64 | Song title |
2 | 0x00 |
max 32 | Artist name |
2 | 0x00 |
max 64 | Album name |
2 | 0x00 |
– | Genre |
2 | 0x00 |
2 | Year or 0xffff |
2 | 0x00 |
4 | CD number |
4 | Track number |
2 | 0x00 |
The lookup table seems to have a fixed start address at 0x0013a104 on the Clip+. It is used by the firmware to dynamically create both, the file browser and the artist/title/genre/… submenus.
Every entry in the lookup table contains a reference to an entry in the tag database that is used as label for the menu entry as well as two ID’s pointing to the next menu entry and the next menu level. See the figure on the right.
The table header is 64 bytes long and has the following structure:
Length | Description |
---|---|
2 | ID of the first artist |
2 | 0x00 |
2 | ID of the first album |
2 | 0x00 |
2 | ID of the first title |
2 | 0x00 |
2 | ID of the first genre |
2 | 0x00 |
2 | Unknown |
2 | 0x00 |
2 | Unknown |
2 | 0x00 |
2 | ID of the first audiobook |
2 | 0x00 |
2 | ID of the first recording |
2 | 0x00 |
2 | Unknown |
2 | 0x00 |
2 | Unknown |
2 | 0x00 |
2 | ID of the most recently added song |
2 | 0x00 |
2 | ID of the first podcast |
2 | 0x00 |
2 | ID of the file browser entry point (root directory contents) |
2 | 0x00 |
2 | Unknown |
2 | 0x00 |
2 | Unknown |
2 | 0x00 |
2 | # of entries in the lookup table |
2 | 0x00 |
A few remarks on the table below:
Length | Description |
---|---|
3 | Offset of field in tag database in bytes starting at file offset 0x4 |
1 | Flags
|
2 | ID of first entry of the next level or ID of rating table entry in RES_INFO.SYS if flags is 0x80. See below. |
2 | ID of the next entry, see remarks above for offset calculation. |
As you can see above the maximum size of the tag database is limited to 16MB by the three byte offset.
Not much information is known on RES_INFO.SYS yet. It is used to store the rating (1 to 5 stars) that you can give each song on the Clip+. But there are tables in there whose purpose is unknown at the moment.
The “rating table” starts at offset 0x77c and every entry is four bytes long. An entry looks like this:
Length | Description |
---|---|
1 | 0x00 (unknown) |
1 | 0x80 (unknown) |
1 | Rating from 0x00 (no rating) to 0x05 (five stars) |
1 | 0x00 (unknown) |
Calculating the file offset from ID’s works exactly as above: \(\mathrm{ID} \cdot 4 + \mathrm{77C_h}\). This is needed if the lookup table references an entry in the rating table.
I wrote about 400 lines of code in C – primarily to make reverse engineering easier. The program reads a MTABLE.SYS file and dumps the tag database as well as the lookup table. It is not written very well and lacks documentation, but might be good if you don’t want to start with nothing at all.
Download (2011-05-25)