Search
lxdream.org :: lxdream/src/drivers/cdrom/cd_cdi.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/drivers/cdrom/cd_cdi.c
changeset 1298:d0eb2307b847
prev1180:f2b9f4ef1987
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
file annotate diff log raw
nkeynes@31
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@31
     3
 *
nkeynes@31
     4
 * CDI CD-image file support
nkeynes@31
     5
 *
nkeynes@31
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@31
     7
 *
nkeynes@31
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@31
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@31
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@31
    11
 * (at your option) any later version.
nkeynes@31
    12
 *
nkeynes@31
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@31
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@31
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@31
    16
 * GNU General Public License for more details.
nkeynes@31
    17
 */
nkeynes@1
    18
nkeynes@1
    19
#include <stdlib.h>
nkeynes@1
    20
#include <stdio.h>
nkeynes@1
    21
#include <stdint.h>
nkeynes@759
    22
#include <string.h>
nkeynes@1
    23
#include <fcntl.h>
nkeynes@1
    24
#include <errno.h>
nkeynes@1
    25
#include <sys/stat.h>
nkeynes@1097
    26
#include "drivers/cdrom/cdimpl.h"
nkeynes@1
    27
nkeynes@168
    28
#define CDI_V2_ID 0x80000004
nkeynes@168
    29
#define CDI_V3_ID 0x80000005
nkeynes@168
    30
#define CDI_V35_ID 0x80000006
nkeynes@168
    31
nkeynes@168
    32
nkeynes@168
    33
static gboolean cdi_image_is_valid( FILE *f );
nkeynes@1097
    34
static gboolean cdi_image_read_toc( cdrom_disc_t disc, ERROR *err );
nkeynes@168
    35
nkeynes@1097
    36
struct cdrom_disc_factory cdi_disc_factory = { "DiscJuggler", "cdi",
nkeynes@1097
    37
        cdi_image_is_valid, NULL, cdi_image_read_toc };
nkeynes@1
    38
nkeynes@347
    39
static const char TRACK_START_MARKER[20] = { 0,0,1,0,0,0,255,255,255,255,
nkeynes@736
    40
        0,0,1,0,0,0,255,255,255,255 };
nkeynes@1298
    41
//static const char EXT_MARKER[9] = {0,255,255,255,255,255,255,255,255 };
nkeynes@1
    42
nkeynes@1
    43
struct cdi_trailer {
nkeynes@1
    44
    uint32_t cdi_version;
nkeynes@1
    45
    uint32_t header_offset;
nkeynes@1
    46
};
nkeynes@1
    47
nkeynes@1
    48
struct cdi_track_data {
nkeynes@1
    49
    uint32_t pregap_length;
nkeynes@1
    50
    uint32_t length;
nkeynes@1
    51
    char unknown2[6];
nkeynes@1
    52
    uint32_t mode;
nkeynes@1
    53
    char unknown3[0x0c];
nkeynes@1
    54
    uint32_t start_lba;
nkeynes@1
    55
    uint32_t total_length;
nkeynes@1
    56
    char unknown4[0x10];
nkeynes@1
    57
    uint32_t sector_size;
nkeynes@1
    58
    char unknown5[0x1D];
nkeynes@1
    59
} __attribute__((packed));
nkeynes@1
    60
nkeynes@168
    61
gboolean cdi_image_is_valid( FILE *f )
nkeynes@1
    62
{
nkeynes@168
    63
    int len;
nkeynes@168
    64
    struct cdi_trailer trail;
nkeynes@1
    65
nkeynes@168
    66
    fseek( f, -8, SEEK_END );
nkeynes@168
    67
    len = ftell(f)+8;
nkeynes@168
    68
    fread( &trail, sizeof(trail), 1, f );
nkeynes@168
    69
    if( trail.header_offset >= len ||
nkeynes@736
    70
            trail.header_offset == 0 )
nkeynes@736
    71
        return FALSE;
nkeynes@453
    72
    return trail.cdi_version == CDI_V2_ID || trail.cdi_version == CDI_V3_ID ||
nkeynes@736
    73
    trail.cdi_version == CDI_V35_ID;
nkeynes@168
    74
}
nkeynes@168
    75
nkeynes@1109
    76
#define RETURN_PARSE_ERROR( ... ) do { SET_ERROR(err, LX_ERR_FILE_INVALID, __VA_ARGS__); return FALSE; } while(0)
nkeynes@1097
    77
nkeynes@1097
    78
static gboolean cdi_image_read_toc( cdrom_disc_t disc, ERROR *err )
nkeynes@168
    79
{
nkeynes@422
    80
    int i,j;
nkeynes@168
    81
    uint16_t session_count;
nkeynes@168
    82
    uint16_t track_count;
nkeynes@168
    83
    int total_tracks = 0;
nkeynes@422
    84
    int posn = 0;
nkeynes@1
    85
    long len;
nkeynes@1
    86
    struct cdi_trailer trail;
nkeynes@1
    87
    char marker[20];
nkeynes@1
    88
nkeynes@1097
    89
    FILE *f = cdrom_disc_get_base_file(disc);
nkeynes@168
    90
    fseek( f, -8, SEEK_END );
nkeynes@168
    91
    len = ftell(f)+8;
nkeynes@168
    92
    fread( &trail, sizeof(trail), 1, f );
nkeynes@168
    93
    if( trail.header_offset >= len ||
nkeynes@1097
    94
            trail.header_offset == 0 ) {
nkeynes@1097
    95
        RETURN_PARSE_ERROR( "Invalid CDI image" );
nkeynes@1097
    96
    }
nkeynes@736
    97
nkeynes@453
    98
    if( trail.cdi_version != CDI_V2_ID && trail.cdi_version != CDI_V3_ID &&
nkeynes@736
    99
            trail.cdi_version != CDI_V35_ID ) {
nkeynes@1097
   100
        RETURN_PARSE_ERROR( "Invalid CDI image" );
nkeynes@453
   101
    }
nkeynes@1
   102
nkeynes@453
   103
    if( trail.cdi_version == CDI_V35_ID ) {
nkeynes@999
   104
        fseek( f, -(long)trail.header_offset, SEEK_END );
nkeynes@453
   105
    } else {
nkeynes@736
   106
        fseek( f, trail.header_offset, SEEK_SET );
nkeynes@453
   107
    }
nkeynes@168
   108
    fread( &session_count, sizeof(session_count), 1, f );
nkeynes@736
   109
nkeynes@168
   110
    for( i=0; i< session_count; i++ ) {        
nkeynes@736
   111
        fread( &track_count, sizeof(track_count), 1, f );
nkeynes@1180
   112
        if( (i != session_count-1 && track_count < 1) || track_count > 99 ) {
nkeynes@1180
   113
            RETURN_PARSE_ERROR("Invalid number of tracks (%d), bad cdi image", track_count);
nkeynes@1180
   114
        }
nkeynes@736
   115
        if( track_count + total_tracks > 99 ) {
nkeynes@1180
   116
            RETURN_PARSE_ERROR("Invalid number of tracks in disc, bad cdi image" );
nkeynes@736
   117
        }
nkeynes@168
   118
        for( j=0; j<track_count; j++ ) {
nkeynes@1
   119
            struct cdi_track_data trk;
nkeynes@168
   120
            uint32_t new_fmt = 0;
nkeynes@736
   121
            uint8_t fnamelen = 0;
nkeynes@168
   122
            fread( &new_fmt, sizeof(new_fmt), 1, f );
nkeynes@1
   123
            if( new_fmt != 0 ) { /* Additional data 3.00.780+ ?? */
nkeynes@736
   124
                fseek( f, 8, SEEK_CUR ); /* Skip */
nkeynes@1
   125
            }
nkeynes@168
   126
            fread( marker, 20, 1, f );
nkeynes@347
   127
            if( memcmp( marker, TRACK_START_MARKER, 20) != 0 ) {
nkeynes@1097
   128
                RETURN_PARSE_ERROR( "Track start marker not found, error reading cdi image" );
nkeynes@736
   129
            }
nkeynes@736
   130
            fseek( f, 4, SEEK_CUR );
nkeynes@168
   131
            fread( &fnamelen, 1, 1, f );
nkeynes@168
   132
            fseek( f, (int)fnamelen, SEEK_CUR ); /* skip over the filename */
nkeynes@736
   133
            fseek( f, 19, SEEK_CUR );
nkeynes@736
   134
            fread( &new_fmt, sizeof(new_fmt), 1, f );
nkeynes@736
   135
            if( new_fmt == 0x80000000 ) {
nkeynes@736
   136
                fseek( f, 10, SEEK_CUR );
nkeynes@736
   137
            } else {
nkeynes@736
   138
                fseek( f, 2, SEEK_CUR );
nkeynes@736
   139
            }
nkeynes@168
   140
            fread( &trk, sizeof(trk), 1, f );
nkeynes@1097
   141
            disc->track[total_tracks].sessionno = i+1;
nkeynes@1097
   142
            disc->track[total_tracks].lba = trk.start_lba;
nkeynes@1097
   143
            cdrom_count_t sector_count = trk.length;
nkeynes@1097
   144
            sector_mode_t mode;
nkeynes@736
   145
            switch( trk.mode ) {
nkeynes@736
   146
            case 0:
nkeynes@1097
   147
                mode = SECTOR_CDDA;
nkeynes@1023
   148
                disc->track[total_tracks].flags = 0x01;
nkeynes@736
   149
                if( trk.sector_size != 2 ) {
nkeynes@1097
   150
                    RETURN_PARSE_ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
nkeynes@736
   151
                }
nkeynes@736
   152
                break;
nkeynes@736
   153
            case 1:
nkeynes@1097
   154
                mode = SECTOR_MODE1;
nkeynes@1023
   155
                disc->track[total_tracks].flags = 0x41;
nkeynes@736
   156
                if( trk.sector_size != 0 ) {
nkeynes@1097
   157
                    RETURN_PARSE_ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
nkeynes@736
   158
                }
nkeynes@736
   159
                break;
nkeynes@736
   160
            case 2:
nkeynes@1023
   161
                disc->track[total_tracks].flags = 0x41;
nkeynes@736
   162
                switch( trk.sector_size ) {
nkeynes@736
   163
                case 0:
nkeynes@1097
   164
                    mode = SECTOR_MODE2_FORM1;
nkeynes@736
   165
                    break;
nkeynes@736
   166
                case 1:
nkeynes@1097
   167
                    mode = SECTOR_SEMIRAW_MODE2;
nkeynes@736
   168
                    break;
nkeynes@736
   169
                case 2:
nkeynes@736
   170
                default:
nkeynes@1097
   171
                    RETURN_PARSE_ERROR( "Invalid combination of mode %d with size %d", trk.mode, trk.sector_size );
nkeynes@736
   172
                }
nkeynes@736
   173
                break;
nkeynes@1097
   174
            default:
nkeynes@1097
   175
                RETURN_PARSE_ERROR( "Unsupported track mode %d", trk.mode );
nkeynes@736
   176
            }
nkeynes@1097
   177
            uint32_t offset = posn +
nkeynes@1097
   178
                    trk.pregap_length * CDROM_SECTOR_SIZE(mode);
nkeynes@1097
   179
            disc->track[total_tracks].source = file_sector_source_new_source( disc->base_source, mode, offset, sector_count );
nkeynes@1097
   180
            posn += trk.total_length * CDROM_SECTOR_SIZE(mode);
nkeynes@736
   181
            total_tracks++;
nkeynes@1180
   182
            if( trail.cdi_version != CDI_V2_ID ) {
nkeynes@1180
   183
                uint32_t extmarker;
nkeynes@1180
   184
                fseek( f, 5, SEEK_CUR );
nkeynes@1180
   185
                fread( &extmarker, sizeof(extmarker), 1, f);
nkeynes@1180
   186
                if( extmarker == 0xFFFFFFFF )  {
nkeynes@1180
   187
                    fseek( f, 78, SEEK_CUR );
nkeynes@1180
   188
                }
nkeynes@736
   189
            }
nkeynes@736
   190
        }
nkeynes@736
   191
        fseek( f, 12, SEEK_CUR );
nkeynes@1180
   192
        if( trail.cdi_version != CDI_V2_ID ) {
nkeynes@1180
   193
            fseek( f, 1, SEEK_CUR );
nkeynes@1180
   194
        }
nkeynes@1
   195
    }
nkeynes@1097
   196
nkeynes@1023
   197
    disc->track_count = total_tracks;
nkeynes@1097
   198
    disc->session_count = session_count;
nkeynes@1097
   199
    return TRUE;
nkeynes@1
   200
}
.