Title   : Media Descriptor File (MDF/MDS) file format.
Written : 2005.03.28.
Updated : 2005.04.02.
Version : 1.2.
License : Copyright (c) 2005. All rights reserved.
          ALL USE AT OWN RISK!
Author  : Henrik Stokseth <hensto AT c2i DOT net>



MDF files are equal to BIN and IMG files. (as confirmed with a 'cmp' test)
CUE and MDS files have different format. This documentation uses version
1.2 of the MDS file format. If you have any additional info please send me
an email. You should note that the information contained herein can be
misleading but not intentionally so.

Data structures found in the MDS file:

An MDS file's structure consists of the following stuff ...

QUANTITY:   SIZE: OBJECT:               |
1           112   Header.               |
num_entries 80    Data blocks.          |
num_entries 8     Extra blocks.         |
1           22    Footer.               V

Each section should immediately follow each other but it is recommended to
check that ofs_entries is indeed 0x70 and that the ofs_footers points to
the correct place which is ofs_entries + num_entries * sizeof(mds_datablock) +
num_entries * sizeof(mds_extrablock).

This file format design makes it easy to look up individual entries by
indexing the file content as you simpy load them into ready structures.

mds_header *header;
mds_datablock *datablock;
mds_extrablock *extrablock;
mds_footer *footer;


for (int entry=0; entry < header->num_entries; entry++) {
   if(datablock[entry].track < MDS_TRACKMODE_AUDIO) {
      printf("track: %u, sector: %u, sectors: %u.\n", datablock[entry].track, \
             datablock[entry].sector, extrablock[entry].sectors)

You get the idea ...

It is possible earlier versions of the fileformat didn't have the
extra-blocks, but instead calculated number of sectors per track by
taking the difference between starting sectors and using the difference
between num_sectors and last track's starting sectors.

*** HEADER ***

#define __PACKED__ __attribute__ ((packed))

typedef struct mds_header {
   unsigned char  signature[16] __PACKED__; /* 0x0000 "MEDIA DESCRIPTOR"                           */
   unsigned char  version[3]    __PACKED__; /* 0x0010 Fileformat version?                          */
   unsigned char  dummy         __PACKED__; /* 0x0013 (unknown)                                    */
   unsigned short version2[3]   __PACKED__; /* 0x0014 Fileformat version?                          */
   unsigned char  dummy2[48]    __PACKED__; /* 0x0020 (unknown)                                    */
   signed   long  pregap_corr   __PACKED__; /* 0x0058 Pregap correction. ALBA. (0=TAO, -150=DAO)   */
   unsigned long  num_sectors   __PACKED__; /* 0x005c Total number of sectors in image.            */
   unsigned short dummy4        __PACKED__; /* 0x0060 (unknown)                                    */
   unsigned char  num_entries   __PACKED__; /* 0x0062 Number of lead-in+regular track data blocks. */
   unsigned char  num_leadin    __PACKED__; /* 0x0063 Number of lead-in track data blocks?         */
   unsigned char  num_sessions  __PACKED__; /* 0x0064 Total number of sessions in image?           */
   unsigned char  dummy5        __PACKED__; /* 0x0065 (unknown)                                    */
   unsigned char  num_tracks    __PACKED__; /* 0x0066 Number of regular track data blocks.         */
   unsigned char  dummy6[5]     __PACKED__; /* 0x0067 (unknown)                                    */
   unsigned long  ofs_entries   __PACKED__; /* 0x006c Offset of lead-in+regular track data blocks. */
} mds_header;

sizeof(mds_header) == 112 (0x70)


#define MDS_TRACKMODE_UNKNOWN     0x00
#define MDS_TRACKMODE_AUDIO       0xA9 /* sector size = 2352      */
#define MDS_TRACKMODE_MODE1       0xAA /* sector size = 2048      */
#define MDS_TRACKMODE_MODE2       0xAB /* sector size = 2336      */
#define MDS_TRACKMODE_MODE2_FORM1 0xAC /* sector size = 2048      */
#define MDS_TRACKMODE_MODE2_FORM2 0xAD /* sector size = 2324 (+4) */

#define MDS_LEAD-IN_TRACK_FIRST    0xA0 /* info about first track */
#define MDS_LEAD-IN_TRACK_LAST     0xA1 /* info about last track  */
#define MDS_LEAN-IN_TRACK_LEADOUT  0xA2 /* info about lead-out    */

typedef struct mds_datablock {
   unsigned short mode          __PACKED__; /* 0x0000 Track mode.                                */
   unsigned short flags         __PACKED__; /* 0x0002 Track flags?                               */
   unsigned char  track         __PACKED__; /* 0x0004 Track number. (>0x99 is lead-in track)     */
   unsigned char  dummy[4]      __PACKED__; /* 0x0005 (unknown)                                  */
   unsigned char  min           __PACKED__; /* 0x0009 (if track >= 0xA0 -> info about track ###) */
                                            /*        (if track = 0xA2 -> min. @ lead-out)       */
   unsigned char  sec           __PACKED__; /* 0x000a (if track = 0xA2 -> sec. @ lead-out)       */
   unsigned char  frame         __PACKED__; /* 0x000b (if track = 0xA2 -> frame @ lead-out)      */
   unsigned long  ofs_extra     __PACKED__; /* 0x000c Start offset of this track's extra block.  */
   unsigned short sector_size   __PACKED__; /* 0x0010 Sector size.                               */
   unsigned char  dummy2[18]    __PACKED__; /* 0x0012 (unknown)                                  */
   unsigned long  sector        __PACKED__; /* 0x0024 Track start sector. PLBA.                  */
   unsigned long long offset    __PACKED__; /* 0x0028 Track start offset.                        */
   unsigned char  session       __PACKED__; /* 0x0030 Session or index?                          */
   unsigned char  dummy3[3]     __PACKED__; /* 0x0031 (unknown)                                  */
   unsigned long  ofs_footer    __PACKED__; /* 0x0034 Start offset of footer.                    */
   unsigned char  dummy4[24]    __PACKED__; /* 0x0038 (unknown)                                  */
} mds_datablock;

sizeof(mds_datablock) == 80 (0x50)

Track number is in the range of 0x01 to 0x99. Numbers from 0xA0 to 0xA2 means that
the data block refers to the lead-in track of the disc. Track mode should be set
to 0x00 in this case.
Track 0xA0 gives information about the first track of the image, where min is the
number of the first track in the image.
Track 0xA1 gives information about the last track of the image, where min is the
number of the last track in the image.
Track 0xA2 gives information about the lead-out track, where min, sec and frame is
set to the MSF of the lead-out track.

NOTE: sec is two seconds more than calc. from sector number. Is this because
of pregap, since a pregap of 150 frames equals to 2 seconds? In either case
there's no pregap in the image file so you would either have add the
pregap_corr or calculate a new MSF from sector count in order to get correct
MSFs for the cd-image.


typedef struct mds_extrablock {
   unsigned long pregap         __PACKED__; /* 0x0000 Number of sectors in pregap.               */
   unsigned long sectors        __PACKED__; /* 0x0004 Number of sectors in track.                */
} mds_extrablock;

sizeof(mds_extrablock) == 8 (0x08)

*** FOOTER ***

typedef struct mds_footer {
   unsigned long ofs_filename   __PACKED__; /* 0x0000 Start offset of image filename.            */
   unsigned char filename[18]   __PACKED__; /* 0x0018 (use ofs_filename! max size: 18 (17+\0)    */
} mds_footer;

sizeof(mds_footer) == 22 (0x16)