diff --git a/.cvsignore b/.cvsignore index 505dc07a..5cb96c1d 100644 --- a/.cvsignore +++ b/.cvsignore @@ -13,5 +13,6 @@ libcdio*.tar.gz libtool libcdio.pc libcdio.spec +libiso9660.pc ltmain.sh stamp-h1 diff --git a/Makefile.am b/Makefile.am index 79e78001..b251ddef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.11 2003/08/09 11:52:00 rocky Exp $ +# $Id: Makefile.am,v 1.12 2003/08/17 05:31:19 rocky Exp $ # # Copyright (C) 2003 Rocky Bernstein # @@ -27,7 +27,7 @@ SUBDIRS = doc include lib src test # pkg-config(1) related rules pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libcdio.pc +pkgconfig_DATA = libiso9660.pc libcdio.pc $(pkgconfig_DATA): config.status diff --git a/configure.ac b/configure.ac index 3604277d..55aadb47 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. -AC_REVISION([$Id: configure.ac,v 1.32 2003/08/16 22:09:31 rocky Exp $])dnl +AC_REVISION([$Id: configure.ac,v 1.33 2003/08/17 05:31:19 rocky Exp $])dnl AC_INIT(lib/cdio.c) AM_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE(libcdio, 0.63) @@ -183,8 +183,10 @@ AC_HAVE_HEADERS( stdbool.h stdlib.h stdint.h stdio.h string.h strings.h linux/v LIBCDIO_CFLAGS='-I$(top_srcdir)/lib/ -I$(top_srcdir)/include/' LIBCDIO_LIBS='$(top_builddir)/lib/libcdio.la' +LIBISO9660_LIBS='$(top_builddir)/lib/libiso9660.la' AC_SUBST(LIBCDIO_CFLAGS) AC_SUBST(LIBCDIO_LIBS) +AC_SUBST(LIBISO9660_LIBS) ACLOCAL_AMFLAGS='-I .' AC_SUBST(ACLOCAL_AMFLAGS) @@ -288,10 +290,11 @@ AC_CONFIG_COMMANDS([checks], [chmod +x test/check_cue.sh; chmod +x test/check_nrg.sh ]) -AC_OUTPUT([ \ +AC_CONFIG_FILES([ \ Makefile \ libcdio.pc \ libcdio.spec \ + libiso9660.pc \ include/Makefile \ include/cdio/Makefile \ include/cdio/version.h \ @@ -303,5 +306,6 @@ AC_OUTPUT([ \ test/check_common_fn \ test/Makefile \ ]) +AC_OUTPUT echo "Using CD-ROM drivers: $cd_drivers" diff --git a/include/cdio/Makefile.am b/include/cdio/Makefile.am index fbf95869..467165d2 100644 --- a/include/cdio/Makefile.am +++ b/include/cdio/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.6 2003/08/16 15:34:58 rocky Exp $ +# $Id: Makefile.am,v 1.7 2003/08/17 05:31:19 rocky Exp $ # # Copyright (C) 2003 Rocky Bernstein # @@ -22,8 +22,15 @@ # libcdioincludedir=$(includedir)/cdio -libcdioinclude_HEADERS = cdio.h cd_types.h logging.h sector.h \ - types.h util.h version.h +libcdioinclude_HEADERS = \ + cdio.h \ + cd_types.h \ + iso9660.h \ + logging.h \ + sector.h \ + types.h \ + util.h \ + version.h EXTRA_DIST = version.h.in BUILT_SOURCES = version.h diff --git a/include/cdio/iso9660.h b/include/cdio/iso9660.h new file mode 100644 index 00000000..635d0c62 --- /dev/null +++ b/include/cdio/iso9660.h @@ -0,0 +1,151 @@ +/* + $Id: iso9660.h,v 1.1 2003/08/17 05:31:19 rocky Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel + Copyright (C) 2003 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __CDIO_ISO9660_H__ +#define __CDIO_ISO9660_H__ + +/* Will eventually need/use glib.h */ +#include + +#define MIN_TRACK_SIZE 4*75 + +#define MIN_ISO_SIZE MIN_TRACK_SIZE + +#define ISO_BLOCKSIZE 2048 + +#define LEN_ISONAME 31 +#define MAX_ISONAME 37 + +#define MAX_ISOPATHNAME 255 + +#define ISO_FILE 0 +#define ISO_VD_PRIMARY 1 +#define ISO_DIRECTORY 2 +#define ISO_STANDARD_ID "CD001" + + +#define ISO_PVD_SECTOR 16 +#define ISO_EVD_SECTOR 17 + +enum strncpy_pad_check { + ISO9660_NOCHECK = 0, + ISO9660_7BIT, + ISO9660_ACHARS, + ISO9660_DCHARS +}; + +char * +iso9660_strncpy_pad(char dst[], const char src[], size_t len, + enum strncpy_pad_check _check); + +int +iso9660_isdchar (int c); + +int +iso9660_isachar (int c); + +/* file/dirname's */ +bool +iso9660_pathname_valid_p (const char pathname[]); + +bool +iso9660_dirname_valid_p (const char pathname[]); + +char * +iso9660_pathname_isofy (const char pathname[], uint16_t version); + +/* volume descriptors */ + +void +iso9660_set_pvd (void *pd, const char volume_id[], const char application_id[], + const char publisher_id[], const char preparer_id[], + uint32_t iso_size, const void *root_dir, + uint32_t path_table_l_extent, uint32_t path_table_m_extent, + uint32_t path_table_size); + +void +iso9660_set_evd (void *pd); + +/* directory tree */ + +void +iso9660_dir_init_new (void *dir, uint32_t self, uint32_t ssize, + uint32_t parent, uint32_t psize); + +void +iso9660_dir_init_new_su (void *dir, uint32_t self, uint32_t ssize, + const void *ssu_data, unsigned ssu_size, + uint32_t parent, uint32_t psize, + const void *psu_data, unsigned psu_size); + +void +iso9660_dir_add_entry_su (void *dir, const char name[], uint32_t extent, + uint32_t size, uint8_t flags, const void *su_data, + unsigned su_size); + +unsigned +iso9660_dir_calc_record_size (unsigned namelen, unsigned int su_len); + +/* pathtable */ + +void +iso9660_pathtable_init (void *pt); + +unsigned int +iso9660_pathtable_get_size (const void *pt); + +uint16_t +iso9660_pathtable_l_add_entry (void *pt, const char name[], uint32_t extent, + uint16_t parent); + +uint16_t +iso9660_pathtable_m_add_entry (void *pt, const char name[], uint32_t extent, + uint16_t parent); + +lsn_t +iso9660_get_root_lsn(struct iso_primary_descriptor const *pvd); + +uint8_t +iso9660_get_pvd_type(struct iso_primary_descriptor const *pvd); + +const char * +iso9660_get_pvd_id(struct iso_primary_descriptor const *pvd); + +int +iso9660_get_pvd_space_size(struct iso_primary_descriptor const *pvd); + +int +iso9660_get_pvd_block_size(struct iso_primary_descriptor const *pvd) ; + +int +iso9660_get_pvd_version(struct iso_primary_descriptor const *pvd) ; + + +#endif /* __CDIO_ISO9660_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/cdio/types.h b/include/cdio/types.h index 43d88420..ccfd4641 100644 --- a/include/cdio/types.h +++ b/include/cdio/types.h @@ -1,5 +1,5 @@ /* - $Id: types.h,v 1.3 2003/06/07 10:44:14 rocky Exp $ + $Id: types.h,v 1.4 2003/08/17 05:31:19 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2002,2003 Rocky Bernstein @@ -217,6 +217,13 @@ extern "C" { Constant for invalid LSN */ #define CDIO_INVALID_LSN 0xFFFFFFFF + + /* Opaque types ... */ + + /* Defined fully in iso9660_private.h */ + typedef struct iso_primary_descriptor pvd_t; + + #ifdef __cplusplus } diff --git a/lib/Makefile.am b/lib/Makefile.am index 1ad68d7a..7ecee9d5 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.8 2003/08/16 15:34:58 rocky Exp $ +# $Id: Makefile.am,v 1.9 2003/08/17 05:31:19 rocky Exp $ # # Copyright (C) 2003 Rocky Bernstein # @@ -46,7 +46,10 @@ libcdio_sources = \ sector.c \ util.c -lib_LTLIBRARIES = libcdio.la +lib_LTLIBRARIES = libcdio.la libiso9660.la libcdio_la_SOURCES = $(libcdio_sources) +libiso9660_la_SOURCES = \ + iso9660.c \ + iso9660_private.h INCLUDES = -I$(LIBCDIO_CFLAGS) diff --git a/lib/cd_types.c b/lib/cd_types.c new file mode 100644 index 00000000..f98ee970 --- /dev/null +++ b/lib/cd_types.c @@ -0,0 +1,289 @@ +/* + $Id: cd_types.c,v 1.1 2003/08/17 05:31:19 rocky Exp $ + + Copyright (C) 2003 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + This tries to determine what kind of CD-image or filesystems on a + track we've got. +*/ +#include "config.h" + +#ifdef HAVE_STDIO_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include + +/* +Subject: -65- How can I read an IRIX (EFS) CD-ROM on a machine which + doesn't use EFS? +Date: 18 Jun 1995 00:00:01 EST + + You want 'efslook', at + ftp://viz.tamu.edu/pub/sgi/software/efslook.tar.gz. + +and +! Robert E. Seastrom 's software (with source +! code) for using an SGI CD-ROM on a Macintosh is at +! ftp://bifrost.seastrom.com/pub/mac/CDROM-Jumpstart.sit151.hqx. + +*/ + +static char buffer[6][CDIO_CD_FRAMESIZE_RAW]; /* for CD-Data */ + +/* Some interesting sector numbers stored in the above buffer. */ +#define ISO_SUPERBLOCK_SECTOR 16 /* buffer[0] */ +#define UFS_SUPERBLOCK_SECTOR 4 /* buffer[2] */ +#define BOOT_SECTOR 17 /* buffer[3] */ +#define VCD_INFO_SECTOR 150 /* buffer[4] */ + + +typedef struct signature +{ + unsigned int buf_num; + unsigned int offset; + const char *sig_str; + const char *description; +} signature_t; + +static signature_t sigs[] = + { +/*buffer[x] off look for description */ + {0, 1, "CD001", "ISO 9660"}, + {0, 1, "CD-I", "CD-I"}, + {0, 8, "CDTV", "CDTV"}, + {0, 8, "CD-RTOS", "CD-RTOS"}, + {0, 9, "CDROM", "HIGH SIERRA"}, + {0, 16, "CD-BRIDGE", "BRIDGE"}, + {0, 1024, "CD-XA001", "XA"}, + {1, 64, "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", "PHOTO CD"}, + {1, 0x438, "\x53\xef", "EXT2 FS"}, + {2, 1372, "\x54\x19\x01\x0", "UFS"}, + {3, 7, "EL TORITO", "BOOTABLE"}, + {4, 0, "VIDEO_CD", "VIDEO CD"}, + {4, 0, "SUPERVCD", "SVCD or Chaoji VCD"}, + { 0 } + }; + + +/* The below index into the above sigs array. Make sure things match. */ +#define INDEX_ISOFS 0 +#define INDEX_CD_I 1 +#define INDEX_CDTV 2 +#define INDEX_CD_RTOS 3 +#define INDEX_HS 4 +#define INDEX_BRIDGE 5 +#define INDEX_XA 6 +#define INDEX_PHOTO_CD 7 +#define INDEX_EXT2 8 +#define INDEX_UFS 9 +#define INDEX_BOOTABLE 10 +#define INDEX_VIDEO_CD 11 /* Video CD */ +#define INDEX_SVCD 12 /* CVD *or* SVCD */ + + +/* + Read a particular block into the global array to be used for further + analysis later. +*/ +static int +_cdio_read_block(CdIo *cdio, int superblock, uint32_t offset, uint8_t bufnum, + track_t track_num) +{ + unsigned int track_sec_count = cdio_get_track_sec_count(cdio, track_num); + memset(buffer[bufnum], 0, CDIO_CD_FRAMESIZE); + + if ( track_sec_count < superblock) { + cdio_debug("reading block %u skipped track %d has only %u sectors\n", + superblock, track_num, track_sec_count); + return -1; + } + + cdio_debug("about to read sector %u\n", offset+superblock); + + if (cdio_get_track_green(cdio, track_num)) { + if (0 > cdio_read_mode2_sector(cdio, buffer[bufnum], + offset+superblock, false)) + return -1; + } else { + if (0 > cdio_read_yellow_sector(cdio, buffer[bufnum], + offset+superblock, false)) + return -1; + } + + return 0; +} + +/* + Return true if the previously read-in buffer contains a "signature" that + matches index "num". + */ +static bool +_cdio_is_it(int num) +{ + signature_t *sigp=&sigs[num]; + int len=strlen(sigp->sig_str); + + /* TODO: check that num < largest sig. */ + return 0 == memcmp(&buffer[sigp->buf_num][sigp->offset], sigp->sig_str, len); +} + +static int +_cdio_is_hfs(void) +{ + return (0 == memcmp(&buffer[1][512],"PM",2)) || + (0 == memcmp(&buffer[1][512],"TS",2)) || + (0 == memcmp(&buffer[1][1024], "BD",2)); +} + +static int +_cdio_is_3do(void) +{ + return (0 == memcmp(&buffer[1][0],"\x01\x5a\x5a\x5a\x5a\x5a\x01", 7)) && + (0 == memcmp(&buffer[1][40], "CD-ROM", 6)); +} + +static int +_cdio_is_joliet(void) +{ + return 2 == buffer[3][0] && buffer[3][88] == 0x25 && buffer[3][89] == 0x2f; +} + +/* ISO 9660 volume space in M2F1_SECTOR_SIZE byte units */ +static int +_cdio_get_iso9660_fs_sec_count(void) +{ + return ((buffer[0][80] & 0xff) | + ((buffer[0][81] & 0xff) << 8) | + ((buffer[0][82] & 0xff) << 16) | + ((buffer[0][83] & 0xff) << 24)); +} + +static int +_cdio_get_joliet_level( void ) +{ + switch (buffer[3][90]) { + case 0x40: return 1; + case 0x43: return 2; + case 0x45: return 3; + } + return 0; +} + +/* + Try to determine what kind of CD-image and/or filesystem we + have at track track_num. Return information about the CD image + is returned in cdio_analysis and the return value. +*/ +cdio_fs_anal_t +cdio_guess_cd_type(/*in*/ CdIo *cdio, int start_session, track_t track_num, + /*out*/ cdio_analysis_t *cdio_analysis) +{ + int ret = 0; + + if ( _cdio_read_block(cdio, ISO_SUPERBLOCK_SECTOR, start_session, + 0, track_num) < 0 ) + return CDIO_FS_UNKNOWN; + + /* We have something that smells of a filesystem. */ + if (_cdio_is_it(INDEX_CD_I) && _cdio_is_it(INDEX_CD_RTOS) + && !_cdio_is_it(INDEX_BRIDGE) && !_cdio_is_it(INDEX_XA)) { + return CDIO_FS_INTERACTIVE; + } else { + /* read sector 0 ONLY, when NO greenbook CD-I !!!! */ + + if ( _cdio_read_block(cdio, 0, start_session, 1, track_num) < 0 ) + return ret; + + if (_cdio_is_it(INDEX_HS)) + ret |= CDIO_FS_HIGH_SIERRA; + else if (_cdio_is_it(INDEX_ISOFS)) { + if (_cdio_is_it(INDEX_CD_RTOS) && _cdio_is_it(INDEX_BRIDGE)) + ret = CDIO_FS_ISO_9660_INTERACTIVE; + else if (_cdio_is_hfs()) + ret = CDIO_FS_ISO_HFS; + else + ret = CDIO_FS_ISO_9660; + cdio_analysis->isofs_size = _cdio_get_iso9660_fs_sec_count(); + sprintf(cdio_analysis->iso_label, buffer[0]+40); + +#if 0 + if (_cdio_is_rockridge()) + ret |= CDIO_FS_ANAL_ROCKRIDGE; +#endif + + if (_cdio_read_block(cdio, BOOT_SECTOR, start_session, 3, track_num) < 0) + return ret; + + if (_cdio_is_joliet()) { + cdio_analysis->joliet_level = _cdio_get_joliet_level(); + ret |= CDIO_FS_ANAL_JOLIET; + } + if (_cdio_is_it(INDEX_BOOTABLE)) + ret |= CDIO_FS_ANAL_BOOTABLE; + + if (_cdio_is_it(INDEX_XA) && _cdio_is_it(INDEX_ISOFS) + && !_cdio_is_it(INDEX_PHOTO_CD)) { + + if ( _cdio_read_block(cdio, VCD_INFO_SECTOR, start_session, 4, + track_num) < 0 ) + return ret; + + if (_cdio_is_it(INDEX_BRIDGE) && _cdio_is_it(INDEX_CD_RTOS)) { + if (_cdio_is_it(INDEX_VIDEO_CD)) ret |= CDIO_FS_ANAL_VIDEOCDI; + else if (_cdio_is_it(INDEX_SVCD)) ret |= CDIO_FS_ANAL_SVCD; + } else if (_cdio_is_it(INDEX_SVCD)) ret |= CDIO_FS_ANAL_CVD; + + } + } + else if (_cdio_is_hfs()) ret |= CDIO_FS_HFS; + else if (_cdio_is_it(INDEX_EXT2)) ret |= CDIO_FS_EXT2; + else if (_cdio_is_3do()) ret |= CDIO_FS_3DO; + else { + if ( _cdio_read_block(cdio, UFS_SUPERBLOCK_SECTOR, start_session, 2, + track_num) < 0 ) + return ret; + + if (_cdio_is_it(INDEX_UFS)) + ret |= CDIO_FS_UFS; + else + ret |= CDIO_FS_UNKNOWN; + } + } + + /* other checks */ + if (_cdio_is_it(INDEX_XA)) ret |= CDIO_FS_ANAL_XA; + if (_cdio_is_it(INDEX_PHOTO_CD)) ret |= CDIO_FS_ANAL_PHOTO_CD; + if (_cdio_is_it(INDEX_CDTV)) ret |= CDIO_FS_ANAL_CDTV; + return ret; +} diff --git a/lib/iso9660.c b/lib/iso9660.c new file mode 100644 index 00000000..ca2bc0d0 --- /dev/null +++ b/lib/iso9660.c @@ -0,0 +1,703 @@ +/* + $Id: iso9660.c,v 1.1 2003/08/17 05:31:19 rocky Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel + Copyright (C) 2003 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +/* Public headers */ +#include +#include + +/* Private headers */ +#include "iso9660_private.h" +#include "cdio_assert.h" +#include "bytesex.h" + +static const char _rcsid[] = "$Id: iso9660.c,v 1.1 2003/08/17 05:31:19 rocky Exp $"; + +/* some parameters... */ +#define SYSTEM_ID "CD-RTOS CD-BRIDGE" +#define VOLUME_SET_ID "" + +static void +pathtable_get_size_and_entries(const void *pt, unsigned *size, + unsigned int *entries); + +static void +_idr_set_time (uint8_t _idr_date[], const struct tm *_tm) +{ + memset (_idr_date, 0, 7); + + if (!_tm) + return; + + _idr_date[0] = _tm->tm_year; + _idr_date[1] = _tm->tm_mon + 1; + _idr_date[2] = _tm->tm_mday; + _idr_date[3] = _tm->tm_hour; + _idr_date[4] = _tm->tm_min; + _idr_date[5] = _tm->tm_sec; + _idr_date[6] = 0x00; /* tz, GMT -48 +52 in 15min intervals */ +} + +static void +_pvd_set_time (char _pvd_date[], const struct tm *_tm) +{ + memset (_pvd_date, '0', 16); + _pvd_date[16] = (int8_t) 0; /* tz */ + + if (!_tm) + return; + + snprintf(_pvd_date, 17, + "%4.4d%2.2d%2.2d" "%2.2d%2.2d%2.2d" "%2.2d", + _tm->tm_year + 1900, _tm->tm_mon + 1, _tm->tm_mday, + _tm->tm_hour, _tm->tm_min, _tm->tm_sec, + 0 /* 1/100 secs */ ); + + _pvd_date[16] = (int8_t) 0; /* tz */ +} + +char * +iso9660_strncpy_pad(char dst[], const char src[], size_t len, + enum strncpy_pad_check _check) +{ + size_t rlen; + + cdio_assert (dst != NULL); + cdio_assert (src != NULL); + cdio_assert (len > 0); + + switch (_check) + { + int idx; + case ISO9660_NOCHECK: + break; + + case ISO9660_7BIT: + for (idx = 0; src[idx]; idx++) + if ((int8_t) src[idx] < 0) + { + cdio_warn ("string '%s' fails 7bit constraint (pos = %d)", + src, idx); + break; + } + break; + + case ISO9660_ACHARS: + for (idx = 0; src[idx]; idx++) + if (!iso9660_isachar (src[idx])) + { + cdio_warn ("string '%s' fails a-character constraint (pos = %d)", + src, idx); + break; + } + break; + + case ISO9660_DCHARS: + for (idx = 0; src[idx]; idx++) + if (!iso9660_isdchar (src[idx])) + { + cdio_warn ("string '%s' fails d-character constraint (pos = %d)", + src, idx); + break; + } + break; + + default: + cdio_assert_not_reached (); + break; + } + + rlen = strlen (src); + + if (rlen > len) + cdio_warn ("string '%s' is getting truncated to %d characters", + src, (unsigned) len); + + strncpy (dst, src, len); + if (rlen < len) + memset(dst+rlen, ' ', len-rlen); + return dst; +} + +int +iso9660_isdchar (int c) +{ + if (!IN (c, 0x30, 0x5f) + || IN (c, 0x3a, 0x40) + || IN (c, 0x5b, 0x5e)) + return false; + + return true; +} + +int +iso9660_isachar (int c) +{ + if (!IN (c, 0x20, 0x5f) + || IN (c, 0x23, 0x24) + || c == 0x40 + || IN (c, 0x5b, 0x5e)) + return false; + + return true; +} + +void +iso9660_set_evd(void *pd) +{ + struct iso_volume_descriptor ied; + + cdio_assert (sizeof(struct iso_volume_descriptor) == ISO_BLOCKSIZE); + + cdio_assert (pd != NULL); + + memset(&ied, 0, sizeof(ied)); + + ied.type = to_711(ISO_VD_END); + iso9660_strncpy_pad (ied.id, ISO_STANDARD_ID, sizeof(ied.id), ISO9660_DCHARS); + ied.version = to_711(ISO_VERSION); + + memcpy(pd, &ied, sizeof(ied)); +} + +/* important date to celebrate (for me at least =) + -- until user customization is implemented... */ +static const time_t _vcd_time = 269222400L; + +void +iso9660_set_pvd(void *pd, + const char volume_id[], + const char publisher_id[], + const char preparer_id[], + const char application_id[], + uint32_t iso_size, + const void *root_dir, + uint32_t path_table_l_extent, + uint32_t path_table_m_extent, + uint32_t path_table_size) +{ + struct iso_primary_descriptor ipd; + + cdio_assert (sizeof(struct iso_primary_descriptor) == ISO_BLOCKSIZE); + + cdio_assert (pd != NULL); + cdio_assert (volume_id != NULL); + cdio_assert (application_id != NULL); + + memset(&ipd,0,sizeof(ipd)); /* paranoia? */ + + /* magic stuff ... thatis CD XA marker... */ + strcpy(((char*)&ipd)+ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING); + + ipd.type = to_711(ISO_VD_PRIMARY); + iso9660_strncpy_pad (ipd.id, ISO_STANDARD_ID, 5, ISO9660_DCHARS); + ipd.version = to_711(ISO_VERSION); + + iso9660_strncpy_pad (ipd.system_id, SYSTEM_ID, 32, ISO9660_ACHARS); + iso9660_strncpy_pad (ipd.volume_id, volume_id, 32, ISO9660_DCHARS); + + ipd.volume_space_size = to_733(iso_size); + + ipd.volume_set_size = to_723(1); + ipd.volume_sequence_number = to_723(1); + ipd.logical_block_size = to_723(ISO_BLOCKSIZE); + + ipd.path_table_size = to_733(path_table_size); + ipd.type_l_path_table = to_731(path_table_l_extent); + ipd.type_m_path_table = to_732(path_table_m_extent); + + cdio_assert (sizeof(ipd.root_directory_record) == 34); + memcpy(ipd.root_directory_record, root_dir, sizeof(ipd.root_directory_record)); + ipd.root_directory_record[0] = 34; + + iso9660_strncpy_pad (ipd.volume_set_id, VOLUME_SET_ID, 128, ISO9660_DCHARS); + + iso9660_strncpy_pad (ipd.publisher_id, publisher_id, 128, ISO9660_ACHARS); + iso9660_strncpy_pad (ipd.preparer_id, preparer_id, 128, ISO9660_ACHARS); + iso9660_strncpy_pad (ipd.application_id, application_id, 128, ISO9660_ACHARS); + + iso9660_strncpy_pad (ipd.copyright_file_id , "", 37, ISO9660_DCHARS); + iso9660_strncpy_pad (ipd.abstract_file_id , "", 37, ISO9660_DCHARS); + iso9660_strncpy_pad (ipd.bibliographic_file_id, "", 37, ISO9660_DCHARS); + + _pvd_set_time (ipd.creation_date, gmtime (&_vcd_time)); + _pvd_set_time (ipd.modification_date, gmtime (&_vcd_time)); + _pvd_set_time (ipd.expiration_date, NULL); + _pvd_set_time (ipd.effective_date, NULL); + + ipd.file_structure_version = to_711(1); + + /* we leave ipd.application_data = 0 */ + + memcpy(pd, &ipd, sizeof(ipd)); /* copy stuff to arg ptr */ +} + +unsigned +iso9660_dir_calc_record_size(unsigned namelen, unsigned int su_len) +{ + unsigned length; + + length = sizeof(struct iso_directory_record); + length += namelen; + if (length % 2) /* pad to word boundary */ + length++; + length += su_len; + if (length % 2) /* pad to word boundary again */ + length++; + + return length; +} + +void +iso9660_dir_add_entry_su(void *dir, + const char name[], + uint32_t extent, + uint32_t size, + uint8_t flags, + const void *su_data, + unsigned su_size) +{ + struct iso_directory_record *idr = dir; + uint8_t *dir8 = dir; + unsigned offset = 0; + uint32_t dsize = from_733(idr->size); + int length, su_offset; + + cdio_assert (sizeof(struct iso_directory_record) == 33); + + if (!dsize && !idr->length) + dsize = ISO_BLOCKSIZE; /* for when dir lacks '.' entry */ + + cdio_assert (dsize > 0 && !(dsize % ISO_BLOCKSIZE)); + cdio_assert (dir != NULL); + cdio_assert (extent > 17); + cdio_assert (name != NULL); + cdio_assert (strlen(name) <= MAX_ISOPATHNAME); + + length = sizeof(struct iso_directory_record); + length += strlen(name); + length = _cdio_ceil2block (length, 2); /* pad to word boundary */ + su_offset = length; + length += su_size; + length = _cdio_ceil2block (length, 2); /* pad to word boundary again */ + + /* find the last entry's end */ + { + unsigned ofs_last_rec = 0; + + offset = 0; + while (offset < dsize) + { + if (!dir8[offset]) + { + offset++; + continue; + } + + offset += dir8[offset]; + ofs_last_rec = offset; + } + + cdio_assert (offset == dsize); + + offset = ofs_last_rec; + } + + /* be sure we don't cross sectors boundaries */ + offset = _cdio_ofs_add (offset, length, ISO_BLOCKSIZE); + offset -= length; + + cdio_assert (offset + length <= dsize); + + idr = (struct iso_directory_record*) &dir8[offset]; + + cdio_assert (offset+length < dsize); + + memset(idr, 0, length); + + idr->length = to_711(length); + idr->extent = to_733(extent); + idr->size = to_733(size); + + _idr_set_time (idr->date, gmtime (&_vcd_time)); + + idr->flags = to_711(flags); + + idr->volume_sequence_number = to_723(1); + + idr->name_len = to_711(strlen(name) ? strlen(name) : 1); /* working hack! */ + + memcpy(idr->name, name, from_711(idr->name_len)); + memcpy(&dir8[offset] + su_offset, su_data, su_size); +} + +void +iso9660_dir_init_new (void *dir, + uint32_t self, + uint32_t ssize, + uint32_t parent, + uint32_t psize) +{ + iso9660_dir_init_new_su (dir, self, ssize, NULL, 0, parent, psize, NULL, 0); +} + +void +iso9660_dir_init_new_su (void *dir, + uint32_t self, + uint32_t ssize, + const void *ssu_data, + unsigned ssu_size, + uint32_t parent, + uint32_t psize, + const void *psu_data, + unsigned psu_size) +{ + cdio_assert (ssize > 0 && !(ssize % ISO_BLOCKSIZE)); + cdio_assert (psize > 0 && !(psize % ISO_BLOCKSIZE)); + cdio_assert (dir != NULL); + + memset (dir, 0, ssize); + + /* "\0" -- working hack due to padding */ + iso9660_dir_add_entry_su (dir, "\0", self, ssize, ISO_DIRECTORY, ssu_data, + ssu_size); + + iso9660_dir_add_entry_su (dir, "\1", parent, psize, ISO_DIRECTORY, psu_data, + psu_size); +} + +void +iso9660_pathtable_init (void *pt) +{ + cdio_assert (sizeof (struct iso_path_table) == 8); + + cdio_assert (pt != NULL); + + memset (pt, 0, ISO_BLOCKSIZE); /* fixme */ +} + +static const struct iso_path_table* +pathtable_get_entry (const void *pt, unsigned entrynum) +{ + const uint8_t *tmp = pt; + unsigned offset = 0; + unsigned count = 0; + + cdio_assert (pt != NULL); + + while (from_711 (*tmp)) + { + if (count == entrynum) + break; + + cdio_assert (count < entrynum); + + offset += sizeof (struct iso_path_table); + offset += from_711 (*tmp); + if (offset % 2) + offset++; + tmp = (uint8_t *)pt + offset; + count++; + } + + if (!from_711 (*tmp)) + return NULL; + + return (const void *) tmp; +} + +void +pathtable_get_size_and_entries (const void *pt, + unsigned *size, + unsigned *entries) +{ + const uint8_t *tmp = pt; + unsigned offset = 0; + unsigned count = 0; + + cdio_assert (pt != NULL); + + while (from_711 (*tmp)) + { + offset += sizeof (struct iso_path_table); + offset += from_711 (*tmp); + if (offset % 2) + offset++; + tmp = (uint8_t *)pt + offset; + count++; + } + + if (size) + *size = offset; + + if (entries) + *entries = count; +} + +unsigned int +iso9660_pathtable_get_size (const void *pt) +{ + unsigned size = 0; + pathtable_get_size_and_entries (pt, &size, NULL); + return size; +} + +uint16_t +iso9660_pathtable_l_add_entry (void *pt, + const char name[], + uint32_t extent, + uint16_t parent) +{ + struct iso_path_table *ipt = + (struct iso_path_table*)((char *)pt + iso9660_pathtable_get_size (pt)); + size_t name_len = strlen (name) ? strlen (name) : 1; + unsigned entrynum = 0; + + cdio_assert (iso9660_pathtable_get_size (pt) < ISO_BLOCKSIZE); /*fixme */ + + memset (ipt, 0, sizeof (struct iso_path_table) + name_len); /* paranoia */ + + ipt->name_len = to_711 (name_len); + ipt->extent = to_731 (extent); + ipt->parent = to_721 (parent); + memcpy (ipt->name, name, name_len); + + pathtable_get_size_and_entries (pt, NULL, &entrynum); + + if (entrynum > 1) + { + const struct iso_path_table *ipt2 + = pathtable_get_entry (pt, entrynum - 2); + + cdio_assert (ipt2 != NULL); + + cdio_assert (from_721 (ipt2->parent) <= parent); + } + + return entrynum; +} + +uint16_t +iso9660_pathtable_m_add_entry (void *pt, + const char name[], + uint32_t extent, + uint16_t parent) +{ + struct iso_path_table *ipt = + (struct iso_path_table*)((char *)pt + iso9660_pathtable_get_size (pt)); + size_t name_len = strlen (name) ? strlen (name) : 1; + unsigned entrynum = 0; + + cdio_assert (iso9660_pathtable_get_size(pt) < ISO_BLOCKSIZE); /* fixme */ + + memset(ipt, 0, sizeof (struct iso_path_table) + name_len); /* paranoia */ + + ipt->name_len = to_711 (name_len); + ipt->extent = to_732 (extent); + ipt->parent = to_722 (parent); + memcpy (ipt->name, name, name_len); + + pathtable_get_size_and_entries (pt, NULL, &entrynum); + + if (entrynum > 1) + { + const struct iso_path_table *ipt2 + = pathtable_get_entry (pt, entrynum - 2); + + cdio_assert (ipt2 != NULL); + + cdio_assert (from_722 (ipt2->parent) <= parent); + } + + return entrynum; +} + +bool +iso9660_dirname_valid_p (const char pathname[]) +{ + const char *p = pathname; + int len; + + cdio_assert (pathname != NULL); + + if (*p == '/' || *p == '.' || *p == '\0') + return false; + + if (strlen (pathname) > MAX_ISOPATHNAME) + return false; + + len = 0; + for (; *p; p++) + if (iso9660_isdchar (*p)) + { + len++; + if (len > 8) + return false; + } + else if (*p == '/') + { + if (!len) + return false; + len = 0; + } + else + return false; /* unexpected char */ + + if (!len) + return false; /* last char may not be '/' */ + + return true; +} + +bool +iso9660_pathname_valid_p (const char pathname[]) +{ + const char *p = NULL; + + cdio_assert (pathname != NULL); + + if ((p = strrchr (pathname, '/'))) + { + bool rc; + char *_tmp = strdup (pathname); + + *strrchr (_tmp, '/') = '\0'; + + rc = iso9660_dirname_valid_p (_tmp); + + free (_tmp); + + if (!rc) + return false; + + p++; + } + else + p = pathname; + + if (strlen (pathname) > (MAX_ISOPATHNAME - 6)) + return false; + + { + int len = 0; + int dots = 0; + + for (; *p; p++) + if (iso9660_isdchar (*p)) + { + len++; + if (dots == 0 ? len > 8 : len > 3) + return false; + } + else if (*p == '.') + { + dots++; + if (dots > 1) + return false; + if (!len) + return false; + len = 0; + } + else + return false; + + if (dots != 1) + return false; + } + + return true; +} + +char * +iso9660_pathname_isofy (const char pathname[], uint16_t version) +{ + char tmpbuf[1024] = { 0, }; + + cdio_assert (strlen (pathname) < (sizeof (tmpbuf) - sizeof (";65535"))); + + snprintf (tmpbuf, sizeof(tmpbuf), "%s;%d", pathname, version); + + return strdup (tmpbuf); +} + +lsn_t +iso9660_get_root_lsn(struct iso_primary_descriptor const *pvd) +{ + if (NULL == pvd) + return CDIO_INVALID_LSN; + else { + struct iso_directory_record *idr = (void *) pvd->root_directory_record; + if (NULL == idr) return CDIO_INVALID_LSN; + return(from_733 (idr->extent)); + } +} + +uint8_t +iso9660_get_pvd_type(struct iso_primary_descriptor const *pvd) +{ + if (NULL == pvd) return 255; + return(pvd->type); +} + +const char * +iso9660_get_pvd_id(struct iso_primary_descriptor const *pvd) +{ + if (NULL == pvd) return "ERR"; + return(pvd->id); +} + +int +iso9660_get_pvd_space_size(struct iso_primary_descriptor const *pvd) +{ + if (NULL == pvd) return 0; + return from_733(pvd->volume_space_size); +} + +int +iso9660_get_pvd_block_size(struct iso_primary_descriptor const *pvd) +{ + if (NULL == pvd) return 0; + return from_723(pvd->logical_block_size); +} + +int +iso9660_get_pvd_version(struct iso_primary_descriptor const *pvd) +{ + if (NULL == pvd) return 0; + return pvd->version; +} + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/lib/iso9660_private.h b/lib/iso9660_private.h new file mode 100644 index 00000000..f330521a --- /dev/null +++ b/lib/iso9660_private.h @@ -0,0 +1,120 @@ +/* + $Id: iso9660_private.h,v 1.1 2003/08/17 05:31:19 rocky Exp $ + + Copyright (C) 2000 Herbert Valerio Riedel + Copyright (C) 2003 Rocky Bernstein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __CDIO_ISO9660_PRIVATE_H__ +#define __CDIO_ISO9660_PRIVATE_H__ + +#include + +#define ISO_VD_END 255 + +#define ISO_VERSION 1 + +#define ISO_XA_MARKER_STRING "CD-XA001" +#define ISO_XA_MARKER_OFFSET 1024 + +PRAGMA_BEGIN_PACKED + +struct iso_volume_descriptor { + uint8_t type; /* 711 */ + char id[5]; + uint8_t version; /* 711 */ + char data[2041]; +} GNUC_PACKED; + +#define struct_iso_volume_descriptor_SIZEOF ISO_BLOCKSIZE + +struct iso_primary_descriptor { + uint8_t type; /* 711 */ + char id[5]; + uint8_t version; /* 711 */ + char unused1[1]; + char system_id[32]; /* achars */ + char volume_id[32]; /* dchars */ + char unused2[8]; + uint64_t volume_space_size; /* 733 */ + char escape_sequences[32]; + uint32_t volume_set_size; /* 723 */ + uint32_t volume_sequence_number; /* 723 */ + uint32_t logical_block_size; /* 723 */ + uint64_t path_table_size; /* 733 */ + uint32_t type_l_path_table; /* 731 */ + uint32_t opt_type_l_path_table; /* 731 */ + uint32_t type_m_path_table; /* 732 */ + uint32_t opt_type_m_path_table; /* 732 */ + char root_directory_record[34]; /* 9.1 */ + char volume_set_id[128]; /* dchars */ + char publisher_id[128]; /* achars */ + char preparer_id[128]; /* achars */ + char application_id[128]; /* achars */ + char copyright_file_id[37]; /* 7.5 dchars */ + char abstract_file_id[37]; /* 7.5 dchars */ + char bibliographic_file_id[37]; /* 7.5 dchars */ + char creation_date[17]; /* 8.4.26.1 */ + char modification_date[17]; /* 8.4.26.1 */ + char expiration_date[17]; /* 8.4.26.1 */ + char effective_date[17]; /* 8.4.26.1 */ + uint8_t file_structure_version; /* 711 */ + char unused4[1]; + char application_data[512]; + char unused5[653]; +} GNUC_PACKED; + +#define struct_iso_primary_descriptor_SIZEOF ISO_BLOCKSIZE + +struct iso_path_table { + uint8_t name_len; /* 711 */ + uint8_t xa_len; /* 711 */ + uint32_t extent; /* 731/732 */ + uint16_t parent; /* 721/722 */ + char name[EMPTY_ARRAY_SIZE]; +} GNUC_PACKED; + +#define struct_iso_path_table_SIZEOF 8 + +struct iso_directory_record { + uint8_t length; /* 711 */ + uint8_t ext_attr_length; /* 711 */ + uint64_t extent; /* 733 */ + uint64_t size; /* 733 */ + uint8_t date[7]; /* 7 by 711 */ + uint8_t flags; + uint8_t file_unit_size; /* 711 */ + uint8_t interleave; /* 711 */ + uint32_t volume_sequence_number; /* 723 */ + uint8_t name_len; /* 711 */ + char name[EMPTY_ARRAY_SIZE]; +} GNUC_PACKED; + +#define struct_iso_directory_record_SIZEOF 33 + +PRAGMA_END_PACKED + +#endif /* __CDIO_ISO9660_PRIVATE_H__ */ + + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/libiso9660.pc.in b/libiso9660.pc.in new file mode 100644 index 00000000..259a13fe --- /dev/null +++ b/libiso9660.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libvcdinfo +Description: ISO9660 library +Version: @VERSION@ +Requires: glib-2.0 libcdio libvcd +Libs: -L${libdir} -liso9660 +Cflags: -I${includedir} diff --git a/test/.cvsignore b/test/.cvsignore index 4dcc4d1e..90f9ab80 100644 --- a/test/.cvsignore +++ b/test/.cvsignore @@ -1,8 +1,12 @@ +.deps +.libs Makefile Makefile.in check_cue.sh check_common_fn check_nrg.sh +testassert +testischar *.dump *.cue *.bin diff --git a/test/Makefile.am b/test/Makefile.am index 898743b9..3f3d2e5e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.3 2003/04/28 02:02:41 rocky Exp $ +# $Id: Makefile.am,v 1.4 2003/08/17 05:31:19 rocky Exp $ # # Copyright (C) 2003 Rocky Bernstein # @@ -20,8 +20,17 @@ # Things to regression testing #################################################### # +noinst_PROGRAMS = testassert testischar + +INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS) + +testassert_LDADD = $(LIBCDIO_LIBS) +testischar_LDADD = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) + check_SCRIPTS = check_nrg.sh check_cue.sh check_opts.sh +check_PROGRAMS = testischar testassert + check_DATA = vcd_demo.right \ videocd.right videocd.nrg \ cdda.right cdda.cue cdda.bin \ diff --git a/test/testassert.c b/test/testassert.c new file mode 100644 index 00000000..bc334a55 --- /dev/null +++ b/test/testassert.c @@ -0,0 +1,36 @@ +/* + $Id: testassert.c,v 1.1 2003/08/17 05:31:19 rocky Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +/* Private headers */ +#include "cdio_assert.h" + +int +main (int argc, const char *argv[]) +{ + cdio_assert (argc < 2); + + cdio_assert_not_reached (); + + return 0; +} diff --git a/test/testischar.c b/test/testischar.c new file mode 100644 index 00000000..718ef095 --- /dev/null +++ b/test/testischar.c @@ -0,0 +1,71 @@ +/* + $Id: testischar.c,v 1.1 2003/08/17 05:31:19 rocky Exp $ + + Copyright (C) 2001 Herbert Valerio Riedel + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* Tests ISO9660 character sets. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +int +main (int argc, const char *argv[]) +{ + int i, j; + + printf (" "); + + for (j = 0; j < 0x10; j++) + printf (" %1.1x", j); + + printf (" |"); + + for (j = 0; j < 0x10; j++) + printf (" %1.1x", j); + + printf ("\n"); + + for (i = 0; i < 0x10; i++) + { + + printf ("%1.1x ", i); + + for (j = 0; j < 0x10; j++) + { + int c = (j << 4) + i; + + printf (" %c", iso9660_isdchar (c) ? c : ' '); + } + + printf (" |"); + + for (j = 0; j < 0x10; j++) + { + int c = (j << 4) + i; + + printf (" %c", iso9660_isachar (c) ? c : ' '); + } + + printf ("\n"); + } + + return 0; +}