/*--------------------------------------------------------------------------*/ /* Copyright 2007-2008 Joe Lowe */ /* */ /* Permission is granted to any person obtaining a copy of this Software, */ /* to deal in the Software without restriction, including the rights to use,*/ /* copy, modify, merge, publish, distribute, sublicense, and sell copies of */ /* the Software. */ /* */ /* The above copyright and permission notice must be left intact in all */ /* copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS WITHOUT WARRANTY. */ /*--------------------------------------------------------------------------*/ /* file name: cfs.h */ /* created: 2008.04.01 */ /* */ /* On-disk structure definitions for ISO-9660/ECMA-119, Joliet extensions */ /* (Unicode file names), ISO-9660-1999 (UTF8 file names), and */ /* Compact File Set (restricted ISO-9660 usage). */ /*--------------------------------------------------------------------------*/ #ifndef CFS_H #define CFS_H /* The following type macros are intended only to enhance portability of this header file. Implementors are not expected to use the type macros in implementation code. Implementors should use the type names that fit the compiler/platform/style of the implementation. */ #define _CFS_CHAR8 char #define _CFS_INT8 signed char #define _CFS_UINT8 unsigned char #define _CFS_UINT16 unsigned short #define _CFS_UINT32 unsigned #define _CFS_C_ARRAYLEN(s) (sizeof(s)/sizeof((s)[0])) #define _CFS_C_STRLEN(s) (_CFS_C_ARRAYLEN(s)-1) #ifdef C_ASSERT #define _CFS_C_ASSERT(e) C_ASSERT(e) #else #define _CFS_C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] #endif #ifdef __cplusplus #define _CFS_INLINE inline #else #define _CFS_INLINE static #endif /* Byte order and alignment portability */ #if defined(PORTABLEINT_H) #define CFS_UINT16LE UINT16LE #define CFS_UINT32LE UINT32LE #define CFS_UINT32LEU UINT32LEU #define CFS_UINT16BE UINT16BE #define CFS_UINT32BE UINT32BE #define CFS_UINT32BEU UINT32BEU #define _CFS_SETUINT16LE(d,v) setuint16le(d,v) #define _CFS_SETUINT32LE(d,v) setuint32le(d,v) #define _CFS_SETUINT32LEU(d,v) setuint32leu(d,v) #define _CFS_SETUINT16BE(d,v) setuint16be(d,v) #define _CFS_SETUINT32BE(d,v) setuint32be(d,v) #define _CFS_SETUINT32BEU(d,v) setuint32beu(d,v) #define _CFS_GETUINT16BE(s) getuint16be(s) #define _CFS_GETUINT32BE(s) getuint32be(s) #define _CFS_GETUINT32BEU(s) getuint32beu(s) #else typedef struct { _CFS_UINT8 b0; _CFS_UINT8 b1; } CfsUint16U; typedef struct { _CFS_UINT8 b0; _CFS_UINT8 b1; _CFS_UINT8 b2; _CFS_UINT8 b3; } CfsUint32U; typedef union { _CFS_UINT16 oe; CfsUint16U u; } CfsUint16Oe; typedef union { _CFS_UINT32 oe; CfsUint32U u; } CfsUint32Oe; typedef struct { CfsUint32U u; } CfsUint32OeU; #if defined(LITTLEENDIAN) && !defined(DEBUG) #define CFS_UINT16LE _CFS_UINT16 #define CFS_UINT32LE _CFS_UINT32 #define CFS_UINT32LEU CfsUint32U #define _CFS_SETUINT16LE(d,v) { *(d) = v; } #define _CFS_SETUINT32LE(d,v) { *(d) = v; } #define _CFS_SETUINT32LEU(d,v) { (d)->b0 = (_CFS_UINT8)(v); (d)->b1 = (_CFS_UINT8)((v)>>8); (d)->b2 = (_CFS_UINT8)((v)>>16); (d)->b3 = (_CFS_UINT8)((v)>>24); } #else #define CFS_UINT16LE CfsUint16Oe #define CFS_UINT32LE CfsUint32Oe #define CFS_UINT32LEU CfsUint32OeU #define _CFS_SETUINT16LE(d,v) { (d)->u.b0 = (_CFS_UINT8)(v); (d)->u.b1 = (_CFS_UINT8)((v)>>8); } #define _CFS_SETUINT32LE(d,v) { (d)->u.b0 = (_CFS_UINT8)(v); (d)->u.b1 = (_CFS_UINT8)((v)>>8); (d)->u.b2 = (_CFS_UINT8)((v)>>16); (d)->u.b3 = (_CFS_UINT8)((v)>>24); } #define _CFS_SETUINT32LEU(d,v) _CFS_SETUINT32LE(d,v) #endif #ifdef BIGENDIAN #define CFS_UINT16BE _CFS_UINT16 #define CFS_UINT32BE _CFS_UINT32 #define CFS_UINT32BEU CfsUint32U #define _CFS_SETUINT16BE(d,v) { *(d) = v; } #define _CFS_SETUINT32BE(d,v) { *(d) = v; } #define _CFS_SETUINT32BEU(d,v) { (d)->b3 = (_CFS_UINT8)(v); (d)->b2 = (_CFS_UINT8)((v)>>8); (d)->b1 = (_CFS_UINT8)((v)>>16); (d)->b0 = (_CFS_UINT8)((v)>>24); } #define _CFS_GETUINT16BE(s) (*(s)) #define _CFS_GETUINT32BE(s) (*(s)) #define _CFS_GETUINT32BEU(s) ((s)->b3|((_CFS_UINT32)((s)->b2)<<8)|((_CFS_UINT32)((s)->b1)<<16)|((_CFS_UINT32)((s)->b0)<<24)) #else #define CFS_UINT16BE CfsUint16Oe #define CFS_UINT32BE CfsUint32Oe #define CFS_UINT32BEU CfsUint32OeU #define _CFS_SETUINT16BE(d,v) { (d)->u.b1 = (_CFS_UINT8)(v); (d)->u.b0 = (_CFS_UINT8)((v)>>8); } #define _CFS_SETUINT32BE(d,v) { (d)->u.b3 = (_CFS_UINT8)(v); (d)->u.b2 = (_CFS_UINT8)((v)>>8); (d)->u.b1 = (_CFS_UINT8)((v)>>16); (d)->u.b0 = (_CFS_UINT8)((v)>>24); } #define _CFS_SETUINT32BEU(d,v) _CFS_SETUINT32BE(d,v) #define _CFS_GETUINT16BE(s) ((s)->u.b1|((_CFS_UINT16)((s)->u.b0)<<8) #define _CFS_GETUINT32BE(s) ((s)->u.b3|((_CFS_UINT32)((s)->u.b2)<<8)|((_CFS_UINT32)((s)->u.b1)<<16)|((_CFS_UINT32)((s)->u.b0)<<24)) #define _CFS_GETUINT32BEU(s) _CFS_GETUINT32BE(s) #endif #endif typedef struct { CFS_UINT16LE le; CFS_UINT16BE be; } CfsBoth16; typedef struct { CFS_UINT32LE le; CFS_UINT32BE be; } CfsBoth32; typedef struct { CFS_UINT32LEU le; CFS_UINT32BEU be; } CfsBoth32Unaligned; _CFS_INLINE void CfsSetUint16Le(CFS_UINT16LE* d,_CFS_UINT16 v) { _CFS_SETUINT16LE(d,v); } _CFS_INLINE void CfsSetUint32Le(CFS_UINT32LE* d,_CFS_UINT32 v) { _CFS_SETUINT32LE(d,v); } _CFS_INLINE void CfsSetUint32LeUnaligned(CFS_UINT32LEU* d,_CFS_UINT32 v) { _CFS_SETUINT32LEU(d,v); } _CFS_INLINE void CfsSetUint16Be(CFS_UINT16BE* d,_CFS_UINT16 v) { _CFS_SETUINT16BE(d,v); } _CFS_INLINE void CfsSetUint32Be(CFS_UINT32BE* d,_CFS_UINT32 v) { _CFS_SETUINT32BE(d,v); } _CFS_INLINE void CfsSetUint32BeUnaligned(CFS_UINT32BEU* d,_CFS_UINT32 v) { _CFS_SETUINT32BEU(d,v); } _CFS_INLINE void CfsSetBoth16(CfsBoth16* d,_CFS_UINT16 v) { _CFS_SETUINT16LE(&(d->le),v); _CFS_SETUINT16BE(&(d->be),v); } _CFS_INLINE void CfsSetBoth32(CfsBoth32* d,_CFS_UINT32 v) { _CFS_SETUINT32LE(&(d->le),v); _CFS_SETUINT32BE(&(d->be),v); } _CFS_INLINE void CfsSetBoth32Unaligned(CfsBoth32Unaligned* d,_CFS_UINT32 v) { _CFS_SETUINT32LEU(&(d->le),v); _CFS_SETUINT32BEU(&(d->be),v); } /* ISO-9660, ISO-9660-1999, and Joliet definitions */ enum { cfsBlockSize = 2048, cfsPrimaryVolumeDescBlock = 16 }; typedef struct { _CFS_UINT8 yearSince1900; _CFS_UINT8 month; _CFS_UINT8 day; _CFS_UINT8 hour; _CFS_UINT8 minute; _CFS_UINT8 second; _CFS_INT8 timeZone15Min; } CfsTimeStamp; _CFS_C_ASSERT(sizeof(CfsTimeStamp) == 7); typedef struct { _CFS_CHAR8 year[4]; _CFS_CHAR8 month[2]; _CFS_CHAR8 day[2]; _CFS_CHAR8 hour[2]; _CFS_CHAR8 minute[2]; _CFS_CHAR8 second[2]; _CFS_CHAR8 centiSec[2]; _CFS_INT8 timeZone15Min; } CfsLongTimeStamp; _CFS_C_ASSERT(sizeof(CfsLongTimeStamp) == 17); typedef struct { _CFS_UINT8 recordSize; _CFS_UINT8 extendedAttributeSize; CfsBoth32Unaligned extentBlockNumber; CfsBoth32Unaligned dataSize; CfsTimeStamp recordTime; _CFS_UINT8 recordFlags; _CFS_UINT8 interleaveUnitSize; _CFS_UINT8 interleaveGapSize; CfsBoth16 volumeSequenceNumber; _CFS_UINT8 fileNameLen; _CFS_CHAR8 fileName[1/*fileNameLen*/]; /* _CFS_UINT8 padding[offsetof(padding)%2]; */ /* _CFS_UINT8 systemUse[recordSize-offsetof(systemUse)]; */ } CfsFileRecord; _CFS_C_ASSERT(offsetof(CfsFileRecord,fileName) == 33); _CFS_C_ASSERT(sizeof(CfsFileRecord) == 34); enum { cfsMaxFileRecordSize = 0xFE, cfsRecordFlagVisible = 0x01, cfsRecordFlagFolder = 0x02, cfsRecordFlagAssociated = 0x04, /* ISO-9660-1999 */ cfsEnhancedRecordFlagMoreExtents = 0x80 }; typedef struct { _CFS_UINT8 fileNameLen; _CFS_UINT8 extendadAttributeSize; CFS_UINT32LEU extentBlockNumber; CFS_UINT16LE parentPathRecordNumber; _CFS_CHAR8 fileName[1/*fileNameLen*/]; /* _CFS_UINT8 padding[offsetof(padding)%2]; */ } CfsPathRecordLe; typedef struct { _CFS_UINT8 fileNameLen; _CFS_UINT8 extendadAttributeSize; CFS_UINT32BEU extentBlockNumber; CFS_UINT16BE parentPathRecordNumber; _CFS_CHAR8 fileName[1/*fileNameLen*/]; /* _CFS_UINT8 padding1[offsetof(padding)%2]; */ } CfsPathRecordBe; typedef struct { CfsBoth16 ownerId; CfsBoth16 groupId; CFS_UINT16BE permissions; CfsLongTimeStamp createTime; CfsLongTimeStamp writeTime; CfsLongTimeStamp expireTime; CfsLongTimeStamp effectiveTime; _CFS_UINT8 recordFormat; _CFS_UINT8 recordAttributes; CfsBoth16 recordSize; _CFS_CHAR8 systemId[32]; _CFS_UINT8 systemUse[64]; _CFS_UINT8 extendedAttributeVersion; _CFS_UINT8 escapeSequenceSize; _CFS_UINT8 reserved1[64]; CfsBoth16 appUseSize; /* _CFS_UINT8 appUse[appUseSize]; */ /* _CFS_UINT8 escapeSequence[escapeSequenceSize]; */ } CfsExtendedAttribute; _CFS_C_ASSERT(offsetof(CfsExtendedAttribute,appUseSize) == 246); enum { cfsExtendedAttributeVersion = 1 }; typedef struct { _CFS_UINT8 descType; _CFS_CHAR8 descId[5]; _CFS_UINT8 descVersion; } CfsDescTag; _CFS_C_ASSERT(sizeof(CfsDescTag) == 7); #define CFS_BOOTDESCTAG { 0x00,{'C','D','0','0','1'},0x01 } #define CFS_PRIMARYVOLUMEDESCTAG { 0x01,{'C','D','0','0','1'},0x01 } #define CFS_SUPPLEMENTARYVOLUMEDESCTAG { 0x02,{'C','D','0','0','1'},0x01 } #define CFS_ENHANCEDVOLUMEDESCTAG { 0x02,{'C','D','0','0','1'},0x02 } #define CFS_PARTITIONDESCTAG { 0x03,{'C','D','0','0','1'},0x01 } #define CFS_TERMINATORDESCTAG { 0xFF,{'C','D','0','0','1'},0x01 } // Extended descriptors present with UDF and ISO-13490 media. #define CFS_BEGINEXTENDEDDESCTAG { 0x00,{'B','E','A','0','1'},0x01 } #define CFS_ENDEXTENDEDDESCTAG { 0x00,{'T','E','A','0','1'},0x01 } #define CFS_UDFMARKER1DESCTAG { 0x00,{'N','S','R','0','2'},0x01 } #define CFS_UDFMARKER2DESCTAG { 0x00,{'N','S','R','0','3'},0x01 } #define CFS_BOOT2DESCTAG { 0x00,{'B','O','O','T','2'},0x01 } #define CFS_CDWDESCTAG { 0x00,{'C','D','W','0','2'},0x02 } #ifdef __cplusplus static const CfsDescTag cfsBootDescTag = CFS_BOOTDESCTAG ; static const CfsDescTag cfsPrimaryVolumeDescTag = CFS_PRIMARYVOLUMEDESCTAG ; static const CfsDescTag cfsSupplementaryVolumeDescTag = CFS_SUPPLEMENTARYVOLUMEDESCTAG; static const CfsDescTag cfsEnhancedVolumeDescTag = CFS_ENHANCEDVOLUMEDESCTAG ; static const CfsDescTag cfsPartitionDescTag = CFS_PARTITIONDESCTAG ; static const CfsDescTag cfsTerminatorDescTag = CFS_TERMINATORDESCTAG ; static const CfsDescTag cfsBeginExtendedDescTag = CFS_BEGINEXTENDEDDESCTAG ; static const CfsDescTag cfsEndExtendedDescTag = CFS_ENDEXTENDEDDESCTAG ; static const CfsDescTag cfsUdfMarker1DescTag = CFS_UDFMARKER1DESCTAG ; static const CfsDescTag cfsUdfMarker2DescTag = CFS_UDFMARKER2DESCTAG ; static const CfsDescTag cfsBoot2DescTag = CFS_BOOT2DESCTAG ; static const CfsDescTag cfsCdwDescTag = CFS_CDWDESCTAG ; #endif /* This structure works for primary, supplementary, and enhanced volume descriptors. The volume flags and escape sequence fields are only valid for supplementary and enhanced descriptors. */ typedef struct { CfsDescTag descTag; _CFS_UINT8 volumeFlags; _CFS_CHAR8 systemId[32]; _CFS_CHAR8 volumeId[32]; _CFS_UINT8 reserved1[8]; CfsBoth32 volumeBlockCount; _CFS_CHAR8 charSetEscapeSequences[32]; CfsBoth16 volumeSetSize; CfsBoth16 volumeSequenceNumber; CfsBoth16 blockSize; CfsBoth32 pathTableSize; CFS_UINT32LE lePathTableBlockNumber; CFS_UINT32LE leOptPathTableBlockNumber; CFS_UINT32BE bePathTableBlockNumber; CFS_UINT32BE beOptPathTableBlockNumber; CfsFileRecord rootRecord; _CFS_CHAR8 volumeSetId[128]; _CFS_CHAR8 publisherId[128]; _CFS_CHAR8 preparerId[128]; _CFS_CHAR8 applicationId[128]; _CFS_CHAR8 copyrightFileName[37]; _CFS_CHAR8 abstractFileName[37]; _CFS_CHAR8 biblioFileName[37]; CfsLongTimeStamp volumeCreateTime; CfsLongTimeStamp volumeModifyTime; CfsLongTimeStamp volumeExpireTime; CfsLongTimeStamp volumeEffectiveTime; _CFS_UINT8 fileStructVersion; _CFS_UINT8 reserved2[1]; _CFS_UINT8 appUse1[512]; _CFS_UINT8 reserved3[653]; } CfsVolumeDesc; _CFS_C_ASSERT(offsetof(CfsVolumeDesc,volumeSetId)-offsetof(CfsVolumeDesc,rootRecord) == 34); _CFS_C_ASSERT(sizeof(CfsVolumeDesc) == cfsBlockSize); enum { cdsVolumeFlagStandardCharSet = 0x01 }; #define CFS_CHARSETESCAPESEQUENCEUCS2_1 "%/@" #define CFS_CHARSETESCAPESEQUENCEUCS2_2 "%/C" #define CFS_CHARSETESCAPESEQUENCEUCS2_3 "%/E" /* The following three escape sequences are registered according to ISO/IEC 2022 and ISO/IEC 2375 to select UTF-8. It is a good idea to handle these sequences in supplementary volume descriptors, but it is not likely many ISO-9660 implementations create them. */ #define CFS_CHARSETESCAPESEQUENCEUTF8_1 "%/G" #define CFS_CHARSETESCAPESEQUENCEUTF8_2 "%/H" #define CFS_CHARSETESCAPESEQUENCEUTF8_3 "%/I" #ifdef __cplusplus static const _CFS_CHAR8 cfsCharSetEscapeSequenceUcs2_1[] = CFS_CHARSETESCAPESEQUENCEUCS2_1; static const _CFS_CHAR8 cfsCharSetEscapeSequenceUcs2_2[] = CFS_CHARSETESCAPESEQUENCEUCS2_2; static const _CFS_CHAR8 cfsCharSetEscapeSequenceUcs2_3[] = CFS_CHARSETESCAPESEQUENCEUCS2_3; static const _CFS_CHAR8 cfsCharSetEscapeSequenceUtf8_1[] = CFS_CHARSETESCAPESEQUENCEUTF8_1; static const _CFS_CHAR8 cfsCharSetEscapeSequenceUtf8_2[] = CFS_CHARSETESCAPESEQUENCEUTF8_2; static const _CFS_CHAR8 cfsCharSetEscapeSequenceUtf8_3[] = CFS_CHARSETESCAPESEQUENCEUTF8_3; #endif /* Compact File Set Specification Definitions and media header construction logic. */ #define CFS_PVDSYSTEMID "CFS" #define CFS_PVDVOLUMEID "CompactFileSet" #define CFS_SVDDEFAULTVOLUMEID L"CompactFileSet" #define CFS_SYSTEMID "CFS:??:??:??" #ifdef __cplusplus static const _CFS_CHAR8 cfsPvdSystemId[] = CFS_PVDSYSTEMID; static const _CFS_CHAR8 cfsPvdVolumeId[] = CFS_PVDVOLUMEID; static const wchar_t cfsSvdDefaultVolumeId[] = CFS_SVDDEFAULTVOLUMEID; static const _CFS_CHAR8 cfsSystemId[] = CFS_SYSTEMID; #endif enum { cfsSvdSystemIdCompareLen = 4, cfsSvdSystemIdVersionTensByteIndex = 9, cfsSvdSystemIdVersionOnesByteIndex = 11, cfsSvdSystemIdMinReaderVersionTensByteIndex = 15, cfsSvdSystemIdMinReaderVersionOnesByteIndex = 17, cfsSvdSystemIdMinWriterVersionTensByteIndex = 21, cfsSvdSystemIdMinWriterVersionOnesByteIndex = 23, cfsMediaHeaderBlockCount = 20, cfsMediaHeaderSize = 20*cfsBlockSize, cfsVersion = 1, cfsMinReadVersion = 1, cfsMinWriteVersion = 1, cfsInitMinReaderVersion = 1, cfsInitMinWriterVersion = 1, /* Patch area goes from start of system id to after record flag field in root record of supplementary volume descriptor. This allows updating the CFS version, volume id, volume block count, and root folder location. */ cfsMediaHeaderPatchAreaStart = 17*cfsBlockSize+8, cfsMediaHeaderPatchAreaSize = 174, cfsMaxFileNameLen = 110, cfsMaxRecordBlockCount = 0x1FFFFF }; _CFS_INLINE void CfsBuildMediaHeader( void* mediaHeader,const wchar_t* volumeId,const CfsTimeStamp* modifyTime, size_t volumeBlockCount,size_t rootFolderBlock,size_t rootFolderSize, size_t lePathTableBlock,size_t bePathTableBlock,size_t pathTableSize) { static const _CFS_UINT32 readmeDataBlock = 12; static const _CFS_UINT32 readmeRootFolderBlock = 13; static const _CFS_UINT32 leReadmePathTableBlock = 14; static const _CFS_UINT32 beReadmePathTableBlock = 15; static const _CFS_CHAR8 readmeFileName[] = "README.TXT;1"; static const _CFS_UINT32 readmeFileNameLen = sizeof(readmeFileName)-1; static const _CFS_CHAR8 readmeData[] = "Compact File Set compatible reader required.\n"; static const unsigned readmeDataSize = sizeof(readmeData)-1; static const _CFS_UINT32 readmePathTableSize = 10; static const CfsDescTag pvdDescTag = CFS_PRIMARYVOLUMEDESCTAG; static const CfsDescTag svdDescTag = CFS_SUPPLEMENTARYVOLUMEDESCTAG; static const CfsDescTag termDescTag = CFS_TERMINATORDESCTAG; static const _CFS_CHAR8 escapeSequenceUcs2[] = CFS_CHARSETESCAPESEQUENCEUCS2_3; static const unsigned escapeSequenceUcs2Size = sizeof(escapeSequenceUcs2)-1; static const _CFS_CHAR8 pvdSystemId[] = CFS_PVDSYSTEMID; static const _CFS_CHAR8 pvdVolumeId[] = CFS_PVDVOLUMEID; static const wchar_t svdDefaultVolumeId[] = CFS_SVDDEFAULTVOLUMEID; static const _CFS_CHAR8 systemId[] = CFS_SYSTEMID; CfsFileRecord* rec; CfsPathRecordLe* lePathRec; CfsPathRecordBe* bePathRec; size_t len; size_t i; int mediaCreateYear; CfsVolumeDesc* vd; memset(mediaHeader,0,cfsMediaHeaderSize); memcpy((_CFS_UINT8*)(mediaHeader)+readmeDataBlock*cfsBlockSize,readmeData,readmeDataSize); lePathRec = (CfsPathRecordLe*)((_CFS_UINT8*)(mediaHeader)+leReadmePathTableBlock*cfsBlockSize); lePathRec->fileNameLen = 1; CfsSetUint32LeUnaligned(&(lePathRec->extentBlockNumber),readmeRootFolderBlock); CfsSetUint16Le(&(lePathRec->parentPathRecordNumber),1); bePathRec = (CfsPathRecordBe*)((_CFS_UINT8*)(mediaHeader)+beReadmePathTableBlock*cfsBlockSize); bePathRec->fileNameLen = 1; CfsSetUint32BeUnaligned(&(bePathRec->extentBlockNumber),readmeRootFolderBlock); CfsSetUint16Be(&(bePathRec->parentPathRecordNumber),1); rec = (CfsFileRecord*)((_CFS_UINT8*)(mediaHeader)+readmeRootFolderBlock*cfsBlockSize+0); rec->recordSize = 34; CfsSetBoth32Unaligned(&(rec->extentBlockNumber),readmeRootFolderBlock); CfsSetBoth32Unaligned(&(rec->dataSize),cfsBlockSize); rec->recordTime = *modifyTime; rec->recordFlags = cfsRecordFlagFolder; CfsSetBoth16(&(rec->volumeSequenceNumber),1); rec->fileNameLen = 1; rec->fileName[0] = 0; rec = (CfsFileRecord*)((_CFS_UINT8*)(mediaHeader)+readmeRootFolderBlock*cfsBlockSize+34); rec->recordSize = 34; CfsSetBoth32Unaligned(&(rec->extentBlockNumber),readmeRootFolderBlock); CfsSetBoth32Unaligned(&(rec->dataSize),cfsBlockSize); rec->recordTime = *modifyTime; rec->recordFlags = cfsRecordFlagFolder; CfsSetBoth16(&(rec->volumeSequenceNumber),1); rec->fileNameLen = 1; rec->fileName[0] = 1; rec = (CfsFileRecord*)((_CFS_UINT8*)(mediaHeader)+readmeRootFolderBlock*cfsBlockSize+68); rec->recordSize = (33+readmeFileNameLen+1)&~1; CfsSetBoth32Unaligned(&(rec->extentBlockNumber),readmeDataBlock); CfsSetBoth32Unaligned(&(rec->dataSize),readmeDataSize); rec->recordTime = *modifyTime; CfsSetBoth16(&(rec->volumeSequenceNumber),1); rec->fileNameLen = readmeFileNameLen; memcpy(rec->fileName,readmeFileName,readmeFileNameLen); _CFS_C_ASSERT(sizeof(*vd) == cfsBlockSize); vd = (CfsVolumeDesc*)(mediaHeader)+16; *(CfsDescTag*)(vd) = pvdDescTag; memset(vd->systemId,' ',sizeof(vd->systemId)); memcpy(vd->systemId,pvdSystemId,_CFS_C_STRLEN(pvdSystemId)); memset(vd->volumeId,' ',sizeof(vd->volumeId)); memcpy(vd->volumeId,pvdVolumeId,_CFS_C_STRLEN(pvdVolumeId)); CfsSetBoth32(&(vd->volumeBlockCount),(_CFS_UINT32)volumeBlockCount); CfsSetBoth16(&(vd->volumeSetSize),1); CfsSetBoth16(&(vd->volumeSequenceNumber),1); CfsSetBoth16(&(vd->blockSize),cfsBlockSize); vd->rootRecord.recordSize = 34; CfsSetBoth32(&(vd->pathTableSize),readmePathTableSize); CfsSetUint32Le(&(vd->lePathTableBlockNumber),leReadmePathTableBlock); CfsSetUint32Be(&(vd->bePathTableBlockNumber),beReadmePathTableBlock); CfsSetBoth32Unaligned(&(vd->rootRecord.extentBlockNumber),readmeRootFolderBlock); CfsSetBoth32Unaligned(&(vd->rootRecord.dataSize),cfsBlockSize); vd->rootRecord.recordTime = *modifyTime; vd->rootRecord.recordFlags = cfsRecordFlagFolder; CfsSetBoth16(&(vd->rootRecord.volumeSequenceNumber),1); vd->rootRecord.fileNameLen = 1; vd->rootRecord.fileName[0] = 0; memset(vd->volumeSetId,' ',sizeof(vd->volumeSetId)); memset(vd->publisherId,' ',sizeof(vd->publisherId)); memset(vd->preparerId,' ',sizeof(vd->preparerId)); memset(vd->applicationId,' ',sizeof(vd->applicationId)); memset(vd->copyrightFileName,' ',sizeof(vd->copyrightFileName)); memset(vd->abstractFileName,' ',sizeof(vd->abstractFileName)); memset(vd->biblioFileName,' ',sizeof(vd->biblioFileName)); mediaCreateYear = 1900+modifyTime->yearSince1900; vd->volumeCreateTime.year[0] = (_CFS_CHAR8)('0'+(mediaCreateYear/1000)%10); vd->volumeCreateTime.year[1] = (_CFS_CHAR8)('0'+(mediaCreateYear/100)%10); vd->volumeCreateTime.year[2] = (_CFS_CHAR8)('0'+(mediaCreateYear/10)%10); vd->volumeCreateTime.year[3] = (_CFS_CHAR8)('0'+ mediaCreateYear%10); vd->volumeCreateTime.month[0] = (_CFS_CHAR8)('0'+(modifyTime->month/10)%10); vd->volumeCreateTime.month[1] = (_CFS_CHAR8)('0'+ modifyTime->month%10); vd->volumeCreateTime.day[0] = (_CFS_CHAR8)('0'+(modifyTime->day/10)%10); vd->volumeCreateTime.day[1] = (_CFS_CHAR8)('0'+ modifyTime->day%10); vd->volumeCreateTime.hour[0] = (_CFS_CHAR8)('0'+(modifyTime->hour/10)%10); vd->volumeCreateTime.hour[1] = (_CFS_CHAR8)('0'+ modifyTime->hour%10); vd->volumeCreateTime.minute[0] = (_CFS_CHAR8)('0'+(modifyTime->minute/10)%10); vd->volumeCreateTime.minute[1] = (_CFS_CHAR8)('0'+ modifyTime->minute%10); vd->volumeCreateTime.second[0] = (_CFS_CHAR8)('0'+(modifyTime->second/10)%10); vd->volumeCreateTime.second[1] = (_CFS_CHAR8)('0'+ modifyTime->second%10); vd->volumeCreateTime.centiSec[0] = '0'; vd->volumeCreateTime.centiSec[1] = '0'; vd->volumeCreateTime.timeZone15Min = modifyTime->timeZone15Min; vd->volumeModifyTime = vd->volumeCreateTime; memset(&(vd->volumeExpireTime),'0',16); vd->volumeEffectiveTime = vd->volumeCreateTime; vd->fileStructVersion = 1; *(vd+1) = *vd; vd ++; *(CfsDescTag*)(vd) = svdDescTag; memset(vd->systemId,0,_CFS_C_ARRAYLEN(vd->systemId)); for(i = 0; i < _CFS_C_STRLEN(systemId); i ++) { vd->systemId[i*2+0] = (_CFS_CHAR8)(systemId[i]>>8); vd->systemId[i*2+1] = (_CFS_CHAR8)(systemId[i]); } vd->systemId[cfsSvdSystemIdVersionTensByteIndex] = '0'+cfsVersion/10; vd->systemId[cfsSvdSystemIdVersionOnesByteIndex] = '0'+cfsVersion%10; vd->systemId[cfsSvdSystemIdMinReaderVersionTensByteIndex] = '0'+cfsInitMinReaderVersion/10; vd->systemId[cfsSvdSystemIdMinReaderVersionOnesByteIndex] = '0'+cfsInitMinReaderVersion%10; vd->systemId[cfsSvdSystemIdMinWriterVersionTensByteIndex] = '0'+cfsInitMinWriterVersion/10; vd->systemId[cfsSvdSystemIdMinWriterVersionOnesByteIndex] = '0'+cfsInitMinWriterVersion%10; memset(vd->volumeId,0,sizeof(vd->volumeId)); if(!volumeId) { volumeId = svdDefaultVolumeId; } len = wcslen(volumeId); for(i = 0; i < len && i < sizeof(vd->volumeId)/2; i ++) { vd->volumeId[i*2+0] = (_CFS_CHAR8)(volumeId[i]>>8); vd->volumeId[i*2+1] = (_CFS_CHAR8)(volumeId[i]); } memcpy(vd->charSetEscapeSequences,escapeSequenceUcs2,escapeSequenceUcs2Size); CfsSetBoth32(&(vd->pathTableSize),(_CFS_UINT32)pathTableSize); CfsSetUint32Le(&(vd->lePathTableBlockNumber),(_CFS_UINT32)lePathTableBlock); CfsSetUint32Be(&(vd->bePathTableBlockNumber),(_CFS_UINT32)bePathTableBlock); CfsSetBoth32Unaligned(&(vd->rootRecord.extentBlockNumber),(_CFS_UINT32)rootFolderBlock); CfsSetBoth32Unaligned(&(vd->rootRecord.dataSize),(_CFS_UINT32)rootFolderSize); *(CfsDescTag*)((_CFS_UINT8*)(mediaHeader)+18*cfsBlockSize) = termDescTag; }; #undef _CFS_CHAR8 #undef _CFS_INT8 #undef _CFS_UINT8 #undef _CFS_UINT16 #undef _CFS_UINT32 #undef _CFS_C_ARRAYLEN #undef _CFS_C_STRLEN #undef _CFS_C_ASSERT #undef _CFS_INLINE #undef _CFS_SETUINT16LE #undef _CFS_SETUINT32LE #undef _CFS_SETUINT32LEU #undef _CFS_SETUINT16BE #undef _CFS_SETUINT32BE #undef _CFS_SETUINT32BEU #undef _CFS_GETUINT16BE #undef _CFS_GETUINT32BE #undef _CFS_GETUINT32BEU #if 0 // // Compact File Set Specification // Version 1 // 2008.04.06 // // Overview. // // CFS is based on ISO-9660 with specific features and // restrictions. It is intended to be similar enough to // ISO-9660 that many systems and applications will be able // to read CFS, and other applications will require only // minor modifications. CFS may be useful when written directly // to CD/DVD media, but the primary application is expected to // be container files for various archiving and distribution // applications. // // Goals: // - Simplify use with data compression and with non seeking // storage (pipes, sockets, tape). // - Simplify implementation of read and write applications // compared to traditional ISO-9660/UDF based images. // - Improved consistency and interchange of data between // different applications. // - Simplify implementation of applications that modify // images. // - Increase storage efficiency by using less image space // for media structures and duplicated directory data. // - Eliminate the folder count limitation imposed in ISO-9660 // by the path table. // - Eliminate the file size limitations imposed by various // compatibility restrictions with use of ISO-9660 and UDF. // // Main differences of CFS from ISO-9660. // - The layout and contents of the media header (first 40k) // is fixed, always containing the same sequence of volume // structures and data. // - All file names and text fields are stored as big-endian // UCS-2, as specified in the Joliet extensions. // - Arbitrary file name and directory depth limitations are // removed, up to the limitations of the ISO-9660 // file record structure, 110 16 bit characters. // - All directory data is written after the last block of // file data. // - Readers are expected to handle files over 4GB in size. // - Path tables are optionally generated but are not used. // // Media header. // // The first 20 blocks (40K) of the logical image is the media // header. The layout of the media header is compatible with the // various descriptor and directory structures for ISO-9660. The // first block of file data is stored in block 20, immediately // following the media header. // // The media header has the following layout. // block 0-11 // all zero // block 12 // compatibility readme file text // block 13 // compatibility root folder // block 14 // compatibility little-endian path table // block 15 // compatibility big-endian path table // block 16 // ISO-9660 compatibility primary volume descriptor // block 17 // ISO-9660 supplementary volume descriptor // block 18 // ISO-9660 terminating descriptor // block 19 // all zero // // The primary volume descriptor in the media header references // the fixed compatibility root folder and readme, to help users // identify applications and systems that do not use the // supplementary volume descriptor. // // The supplementary volume descriptor indicates the UCS-2 // character set and references the real directory structure. // // The media header should be initialized exactly as is done // in the logic in this header file. No additional application // data, system data, comments, dates, text, etc., should be // added to the media header. // // Unicode file names. // // All file names and the system ID and volume ID fields of the // supplementary volume descriptor are encoded as UCS-2, // big-endian. // // File name lengths are limited by the 8 bit file record size // to 110 16 bit characters. // // No arbitrary limits are imposed on directory hierarchy depth // or combined length of a file name and included folder name // components. Readers will need to choose an appropriate limit // for their environment and perform checks as necessary. // // As in ISO-9660-1999, version numbers are not added to file // names. // // As in ISO-9660-1999, special meaning of the the '.' and ';' // characters during file name sorting is eliminated. // // Optional path tables. // // Path tables consume media space with redundant information, // and restrict media to a maximum of 64k folders. Readers // should not reference path tables. // // Writers may choose to generate path tables to increase // compatibility with ISO-9660 readers. Path tables must be // written with the directory data (folder extents), beyond // the last block of file data. Note that correct path tables // cannot be generated for media containing more than 64K // folders. // // Writers that are modifying an existing media may choose to // remove existing path tables. // // If path tables are not present then the three related volume // descriptor fields in the supplementary volume descriptor // must be set to zero. // // Extended attributes. // // Extended attributes are reserved for future extensions to // CFS. Writers must not create extended attributes. Readers // must gracefully handle extended attributes if they exist. // // File data must be contiguos, and restricted use of duplicate // file records for multi-extent files. // // All data for each file must exist in one contiguos extent. // This is true even when the files are represented using // multiple file records. // // Interleaved files must not be created. Associated files // must not be created. // // Duplicate file records are to be used only to allow // representing files with data extents that are larger // than 4GiB-2048. Duplicate file records are not to be used // to represent files with fragmented data. When duplicate // file records are used, the multi-entent flag must also // be used as indicated in ISO-9660-1999 specification. // // Duplicate file records should not be created unless the // total data size of the file is greater than 4Gib-2048. // // When duplicate file records exist for a file, all but // the last file record must have a data extent that is // exactly 4Gib-2048 bytes in size. // // Location of directory data on media. // // All file data must precede all folder extents and path tables // on media. The intent is that an image modifying application // can read the entire directory into memory, add new file data // to the image, and rewrite an updated directory after the new // file data. // // Writers will need to determine the last block of file data // after reading the entire directory. // // Media header patch area. // // When the media header is modified, either at the end of image // creation or as part of later modifications to an existing // image, only some specific fields are to be updated. These // fields exist entirely within the media header patch area. // // Only the media header patch area should be re-written. This // allows more options when dealing with image container file // formats or transports with limited seeking or overwrite // capability (compressed formats, pipes, sockets). // // Format extensions and compound file systems. // // All files and folders written in the image must be accessible // through the single directory structure referenced from the // supplementary volume descriptor. // // Compound file systems, such as including UDF or HFS structures, // are not allowed. // // Rockridge and other ISO-9660 extensions are not allowed. // // Extensions for archiving system specific attributes. // // Future versions of CFS may include extensions to allow storing // system specific attributes such as time fields,security // descriptors, access control lists, resource forks, symbolic // links etc.. // // Developers with a need for these extensions should contact // Pismo Technic with requirements and/or suggestions. // // Media formats. // // CFS images are either written to CD/DVD media, or are stored // in a media container file. The media container file can be // a raw dump of the CFS image, referred to here as DD, but // more commonly known as ISO files. Also, the media container // file can be a more structured container format that provides // additional features such as compression and spanning. // // CFS images are only compliant with this specification when // they are stored in DD or CISO (Compact ISO) format media // files. When burned to CD/DVD media or when stored in other // media container file formats such as NRG or DAA, the // combination is not CFS compliant and should not be referred // to as a CFS file. // // Note: Compact ISO is not the same format as the compressed // ISO format common in Playstation Portable homebrew development. // The PSP compressied ISO format is also referred to as CISO, but // the file extension is CSO. // // CFS writing applications should default to writing DD format // media container files unless the user has specified container // file options that require CISO (spanning, compression, ...). This // provides more intuitive interchange with systems and applications // that support DD CD/DVD images but do not support CFS. // #endif #endif