www.pudn.com > vcdtools-0_4-os2.zip > vcdisofs.c


#include 
#include 
#include "defaults.h"

/*
 * Make a (simple) ISO 9660 filesystem for a Video CD
 *
 * Many things in this program are just taken from mkisofs
 *
 * Structure of the filesystem
 *
 *     Block      Content
 *
 *     0-15       empty
 *     16         Primary Volume descriptor
 *     17         End Volume descriptor
 *     18         Path table (Intel Byte order) (must fit in 1 Sector)
 *     19         Path table (Motorola Byte order) (must fit in 1 Sector)
 *     20         Root directory
 *     21  ...    Other directories
 *     150 ...    Files in directory VCD
 *     210 ...    Other files
 */


/* Path table stuff. Note that this is simplified and only valid
   if there are no subdirectories below the directories in the
   root directory and if the path tables fit into 1 sector */

#define PATH_TABLE_L_EXTENT 18
#define PATH_TABLE_M_EXTENT 19

#define ISO_DIR_SIZE 2048

static char path_table_l[2048];
static char path_table_m[2048];
static int  path_table_size;

#define ROOT_DIR_EXTENT   20
#define START_FILE_EXTENT 210 /* for files not in directory VCD */

static int root_dir_len;
static char root_dir[ISO_DIR_SIZE];
static int cur_dir_extent;
static int cur_file_extent;

static char zero2048[2048] = { 0, };
static char buff2048[2048];

#define LEN2BLOCKS(x) ( ((x)+2047)>>11 )

/* Various files on the VCD */

static char entries_file[2048];
static char info_file[2048] = {
  'V', 'I', 'D', 'E', 'O', '_', 'C', 'D',
    1,   1, '1', ' ', ' ', ' ', ' ', ' ',
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  ' ', ' ',   0,   1,   0,   1,   0,   0,
};

static struct tm *t;

#define BCD(x) ( ((x)/10)*16 + (x)%10 )

static void set_721( char *pnt, unsigned int i)
{
     pnt[0] = i & 0xff;
     pnt[1] = (i >> 8) &  0xff;
}

static void set_722( char *pnt, unsigned int i)
{
     pnt[0] = (i >> 8) &  0xff;
     pnt[1] = i & 0xff;
}

static void set_723( char *pnt, unsigned int i)
{
     pnt[3] = pnt[0] = i & 0xff;
     pnt[2] = pnt[1] = (i >> 8) &  0xff;
}

static void set_731( char *pnt, unsigned int i)
{
     pnt[0] = i & 0xff;
     pnt[1] = (i >> 8) &  0xff;
     pnt[2] = (i >> 16) &  0xff;
     pnt[3] = (i >> 24) &  0xff;
}

static void set_732( char *pnt, unsigned int i)
{
     pnt[3] = i & 0xff;
     pnt[2] = (i >> 8) &  0xff;
     pnt[1] = (i >> 16) &  0xff;
     pnt[0] = (i >> 24) &  0xff;
}

static void set_733( char *pnt, unsigned int i)
{
     pnt[7] = pnt[0] = i & 0xff;
     pnt[6] = pnt[1] = (i >> 8) &  0xff;
     pnt[5] = pnt[2] = (i >> 16) &  0xff;
     pnt[4] = pnt[3] = (i >> 24) &  0xff;
}

static void set_str( char *pnt, char *src, unsigned int len)
{
     int i, l;
     l = strlen(src);

     for(i=0;i0;
       root_dir_entry += root_dir_entry[0] )
   {
      /* Skip the .. entry in the root directory */

      if (root_dir_entry[33]==1) continue;

      len = root_dir_entry[32];
      path_table_l[path_table_size] = len;
      path_table_m[path_table_size] = len;
      path_table_size += 2;

      extent =  root_dir_entry[2]      +
               (root_dir_entry[3]<< 8) +
               (root_dir_entry[4]<<16) +
               (root_dir_entry[5]<<24);
      set_731(path_table_l + path_table_size, extent);
      set_732(path_table_m + path_table_size, extent);
      path_table_size += 4;

      set_721(path_table_l + path_table_size, 1);
      set_722(path_table_m + path_table_size, 1);
      path_table_size += 2;

      for(j=0; j0) reclen += 14; /* RJ: I don't know for what - see below */

   if( (*dirlen) + reclen > dirsize )
   {
      fprintf(stderr,"Fatal Error: add_dirent - max dirsize exceeded\n");
      exit(1);
   }

   memset(dir+(*dirlen), 0, reclen);

   memset(&idr, 0 , sizeof(idr));

   idr.length[0] = reclen;
   idr.ext_attr_length[0] = 0;
   set_733(idr.extent,extent);
   set_733(idr.size,size);

   idr.date[0] = t->tm_year;
   idr.date[1] = t->tm_mon+1;
   idr.date[2] = t->tm_mday;
   idr.date[3] = t->tm_hour;
   idr.date[4] = t->tm_min;
   idr.date[5] = t->tm_sec;
   idr.date[6] = 0; /* This is in units of 15 minutes from GMT */

   idr.flags[0] = flags;
   idr.file_unit_size[0] = 0;
   idr.interleave[0] = 0;

   set_723(idr.volume_sequence_number,1);

   idr.name_len[0] = namelen;

   memcpy(dir+(*dirlen), &idr, 33);
   memcpy(dir+(*dirlen)+33, name, namelen);

   /* RJ: I don't know exactly what the following is good for,
          it is needed to play VCDs under windows.
          Since I don't know the meaning of some entries,
          this stuff is only added for the MPEG files.
          Other VCDs have it for every file */

   if(xa>0)
   {
      dir[*dirlen+reclen-10] = 0x15; /* ????? */
      dir[*dirlen+reclen- 9] = 0x55; /* ????? */
      dir[*dirlen+reclen- 8] = 'X';
      dir[*dirlen+reclen- 7] = 'A';
      dir[*dirlen+reclen- 6] = xa;
   }

   (*dirlen) += reclen;

}

static void make_ipd()
{
   char iso_time[17];
   int len;
   char name[1];

   memset(&ipd,0,sizeof(ipd));

   ipd.type[0] = 1;
   set_str(ipd.id,"CD001",5);
   ipd.version[0] = 1;

   set_str(ipd.system_id,CD_SYSTEM_ID,32);
   set_str(ipd.volume_id,CD_VOLUME_ID,32);

   set_733(ipd.volume_space_size,ISO_FS_BLOCKS);
   /* we leave ipd.escape_sequences = 0 */

   set_723(ipd.volume_set_size,1);
   set_723(ipd.volume_sequence_number,1);
   set_723(ipd.logical_block_size,2048);

   set_733(ipd.path_table_size,path_table_size);
   set_731(ipd.type_l_path_table,PATH_TABLE_L_EXTENT);
   set_731(ipd.opt_type_l_path_table,0);
   set_732(ipd.type_m_path_table,PATH_TABLE_M_EXTENT);
   set_732(ipd.opt_type_m_path_table,0);

   len = 0;
   name[0] = 0;
   add_dirent(ipd.root_directory_record, &len, 34,
              name, 1, ROOT_DIR_EXTENT, ISO_DIR_SIZE, 2, -1);
   if(len!=34)
   {
      fprintf(stderr,"Internal error in make_ipd\n");
      exit(1);
   }

   set_str(ipd.volume_set_id , CD_VOLUME_SET_ID , 128);
   set_str(ipd.publisher_id  , CD_PUBLISHER_ID  , 128);
   set_str(ipd.preparer_id   , CD_PREPARER_ID   , 128);
   set_str(ipd.application_id, CD_APPLICATION_ID, 128);

   set_str(ipd.copyright_file_id    , " ", 37);
   set_str(ipd.abstract_file_id     , " ", 37);
   set_str(ipd.bibliographic_file_id, " ", 37);

   sprintf(iso_time, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d00",
              1900+(t->tm_year), t->tm_mon+1, t->tm_mday,
              t->tm_hour, t->tm_min, t->tm_sec);
   iso_time[16] = 0; /* This is in binary! Units of 15 minutes from GMT */

   memcpy(ipd.creation_date,    iso_time,17);
   memcpy(ipd.modification_date,iso_time,17);
   memcpy(ipd.expiration_date,  "0000000000000000\0",17);
   memcpy(ipd.effective_date,   iso_time,17);

   ipd.file_structure_version[0] = 1;

   /*  The string CD-XA001 in this exact position indicates  */
   /*  that the disk contains XA sectors.                    */
   memcpy(ipd.application_data+141, "CD-XA001", 8);
}

static void init_iso_dir(char *dir, int *dirlen, int self, int parent)
{
   char name[1];

   memset(dir,0,ISO_DIR_SIZE);
   *dirlen = 0;

   /* add . and .. entries */

   name[0] = 0;
   add_dirent(dir, dirlen, ISO_DIR_SIZE, name, 1, self,   ISO_DIR_SIZE, 2, 0);

   name[0] = 1;
   add_dirent(dir, dirlen, ISO_DIR_SIZE, name, 1, parent, ISO_DIR_SIZE, 2, 0);
}

void add_CDI_dir()
{
   char dir[ISO_DIR_SIZE];
   int dirlen, len, i;

   cur_dir_extent++;

   if(cur_dir_extent>=150)
   { fprintf(stderr,"Fatal Error: too many dirs\n"); exit(1); }

   /* Initialize directory */

   init_iso_dir(dir, &dirlen, cur_dir_extent, ROOT_DIR_EXTENT);

   /* Add this directory to root directory */

   add_dirent(root_dir, &root_dir_len, ISO_DIR_SIZE,
              "CDI", 3, cur_dir_extent, ISO_DIR_SIZE, 2, 0);

   /* Add files */

   /* Since this directory is only used for CDI players
      which are hardly in use any more, we add only a bogus file
      CDI_VCD.APP consisting of 0's */

   /* CDI_VCD.APP */

   len = 2048;
   add_dirent(dir, &dirlen, ISO_DIR_SIZE,
              "CDI_VCD.APP;1", 13, cur_file_extent, len, 0, 0);
   for(i=0;i=150)
   { fprintf(stderr,"Fatal Error: too many dirs\n"); exit(1); }

   /* Initialize directory */

   init_iso_dir(dir, &dirlen, cur_dir_extent, ROOT_DIR_EXTENT);

   /* Add this directory to root directory */

   add_dirent(root_dir, &root_dir_len, ISO_DIR_SIZE,
              "MPEGAV", 6, cur_dir_extent, ISO_DIR_SIZE, 2, 0);

   /* Add files */

   /* RJ:
      This directory contains pointers to the MPEG files
      elsewhere (outside the ISO file system) on the disk.
      We have only to add the directory entries, not the
      files themselves.

      The length is also not the true length but the number
      of sectors muliplied by 2048
   */


   for(i=0;i=150)
   { fprintf(stderr,"Fatal Error: too many dirs\n"); exit(1); }

   /* Initialize directory */

   init_iso_dir(dir, &dirlen, cur_dir_extent, ROOT_DIR_EXTENT);

   /* Add this directory to root directory */

   add_dirent(root_dir, &root_dir_len, ISO_DIR_SIZE,
              "VCD", 3, cur_dir_extent, ISO_DIR_SIZE, 2, 0);

   /* Add files */

   /* RJ:
      I have no description how the files in this directory
      should look, all I have is:
      
      ENTRIES.VCD file (MUST be at sector 151)
      This file of one Sector contains the list of
      start positions of Entries in the MPEG
      Audio/Video Tracks on the disc. The
      Entry address values are used by the
      PSD playlist to access Play segments in
      the MPEG tracks. It's also used at linear
      playback for NEXT / PREVIOUS chapter.

      INFO.VCD file (MUST be at sector 150)
      This file of one sector contains the
      Video CD system identification
      and a provision to identify the discs
      belonging to one Album.  An Album is a
      series of discs which contain related
      Audio/Video programs. It also contains
      information associated with the Play
      Sequence Descriptor (PSD).

      LOT.VCD file (probably sectors 152-183)
      This 32 sectors file contains the List ID
      Offset Table (LOT). The LOT associates
      List ID numbers with the corresponding
      List Offset values.
      This file is optional and not added here!

      PSD.VCD file (probably sectors 184-xxx)
      This file contains the data for the Play
      Sequence Descriptor (PSD). The size of
      the PSD may be variable, up to a
      maximum of 256 sectors or 512 KB.
      This file is optional and not added here!
   */


   /* ENTRIES.VCD */

   len = 2048;
   memset(entries_file, 0, 2048);
   strncpy(entries_file,"ENTRYVCD",8);
   entries_file[ 8] = 1;
   entries_file[ 9] = 1;
   entries_file[10] = 0;
   entries_file[11] = num;
   for(i=0;i