Sansa Clip+ music database

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.

MTABLE.SYS

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.

Tag database

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:

  1. It looks like the file flags are bitmasks. I’m not sure about string encoding and file type/location yet, but it wouldn’t make sense anyway.
  2. The firmware uses different and sometimes even variable string encodings. While path and filename are always treated as plain bytestrings (i.e. no encoding) CD and track number as well as the year are always ASCII encoded. Artist, album and genre can be both, ASCII or UTF-16 encoded, depending on the corresponding flag. And finally the title is always UTF-16 encoded.
  3. CD number and track number share one field. I’m not sure how many bytes are allocated for each of them, but I’ve seen lengths from one byte (containing just a “0” for empty track/CD numbers) up to eight bytes in total.
Length Description
2 0x00 (unknown)
2

String encoding

0x0200
Text is UTF-16 encoded
0x0400
Artist, album and genre ASCII encoded
2

File type/location

0x0001
MUSIC
0x0005
RECORD
0x000b
PODCASTS
0x000c
AUDIOBOOKS
2

File flags (bitmask)

0x4000
Unknown. Recordings (after database refresh) and files uploaded with Windows Media Player (WMP) have this flag
0x9000

File deleted.

When deleting files on the player the database is not regenerated. Instead the firmware flags the corresponding tag database entry as “deleted”.

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

Lookup table

mtable.png

Relationship between MTABLE.SYS and user interface

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:

  1. Example: If flags is 0x41 and the path pointed to by the offset is mmc:0:\AUDIBLE\ the resulting label would be AUDIBLE as the second (zero-based indices!) path component is extracted. 0x40 has not been seen in the wild yet and the maximum directory depth is 14 as 0x4f is used to display the filename.
  2. To calculate the file offset from an ID in the lookup table use this formula: \(\mathrm{ID} \cdot 8 + \mathrm{tableoffset} + \mathrm{headersize}\). Both, tableoffset and headersize are fixed.
  3. 0xfffe is an invalid ID.
Length Description
3 Offset of field in tag database in bytes starting at file offset 0x4
1

Flags

0x01
Tag database field is ASCII encoded
0x02
Tag database field is UTF-16 encoded
0x4X
Folder. The four least significant bits are some kind of level counter that is used to extract the Xth part of the file’s path. If X is 0xf the filename itself is shown. See remarks above.
0x80
File. Not shown to the user. Used internally to get the path of the selected file.
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.

RES_INFO.SYS

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.

Download

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)