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;i 0; 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; j 0) 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