From ab38aa8ed434dc7d813564493b9c4e0ab9fe9b71 Mon Sep 17 00:00:00 2001
From: Li
Date: Tue, 18 Apr 2023 00:28:19 +1200
Subject: [PATCH] add stuff
---
.../PublishProfiles/FolderProfile.pubxml.user | 2 +-
.../{Core => }/ApplePartitionMap/BlockZero.cs | 0
.../ApplePartitionMap/PartitionMap.cs | 0
.../ApplePartitionMap/PartitionMapEntry.cs | 0
.../ApplePartitionMap/PartitionMapFactory.cs | 0
DiscUtils/{Core => }/Archives/FileRecord.cs | 0
DiscUtils/{Core => }/Archives/TarFile.cs | 0
.../{Core => }/Archives/TarFileBuilder.cs | 0
DiscUtils/{Core => }/Archives/TarHeader.cs | 0
.../{Core => }/Archives/TarHeaderExtent.cs | 0
.../Archives/UnixBuildFileRecord.cs | 0
DiscUtils/{Core => }/ChsAddress.cs | 0
DiscUtils/{Core => }/ClusterMap.cs | 0
DiscUtils/{Core => }/ClusterRoles.cs | 0
DiscUtils/{Core => }/Compression/Adler32.cs | 0
.../Compression/BZip2BlockDecoder.cs | 0
.../Compression/BZip2CombinedHuffmanTrees.cs | 0
.../Compression/BZip2DecoderStream.cs | 0
.../{Core => }/Compression/BZip2Randomizer.cs | 0
.../{Core => }/Compression/BZip2RleStream.cs | 0
.../Compression/BigEndianBitStream.cs | 0
DiscUtils/{Core => }/Compression/BitStream.cs | 0
.../{Core => }/Compression/BlockCompressor.cs | 0
.../Compression/CompressionResult.cs | 0
.../Compression/DataBlockTransform.cs | 0
.../{Core => }/Compression/HuffmanTree.cs | 0
.../Compression/InverseBurrowsWheeler.cs | 0
.../{Core => }/Compression/MoveToFront.cs | 0
.../Compression/SizedDeflateStream.cs | 0
.../{Core => }/Compression/ZlibBuffer.cs | 0
.../{Core => }/Compression/ZlibStream.cs | 0
DiscUtils/Core/DiscUtils.Core.csproj | 15 -
.../{Core => }/CoreCompat/EncodingHelper.cs | 0
.../{Core => }/CoreCompat/ReflectionHelper.cs | 0
.../{Core => }/CoreCompat/StringExtensions.cs | 0
DiscUtils/{Core => }/DiscDirectoryInfo.cs | 0
DiscUtils/{Core => }/DiscFileInfo.cs | 0
DiscUtils/{Core => }/DiscFileLocator.cs | 0
DiscUtils/{Core => }/DiscFileSystem.cs | 0
DiscUtils/{Core => }/DiscFileSystemChecker.cs | 0
DiscUtils/{Core => }/DiscFileSystemInfo.cs | 0
DiscUtils/{Core => }/DiscFileSystemOptions.cs | 0
DiscUtils/{Core => }/DiskImageBuilder.cs | 0
.../{Core => }/DiskImageFileSpecification.cs | 0
DiscUtils/{Core => }/FileLocator.cs | 0
DiscUtils/{Core => }/FileSystemInfo.cs | 0
DiscUtils/{Core => }/FileSystemManager.cs | 0
DiscUtils/{Core => }/FileSystemParameters.cs | 0
DiscUtils/{Core => }/FileTransport.cs | 0
DiscUtils/{Core => }/FloppyDiskType.cs | 0
.../{Core => }/GenericDiskAdapterType.cs | 0
DiscUtils/{Core => }/Geometry.cs | 0
DiscUtils/{Core => }/GeometryCalculation.cs | 0
DiscUtils/{Core => }/GeometryTranslation.cs | 0
.../{Core => }/IClusterBasedFileSystem.cs | 0
DiscUtils/{Core => }/IDiagnosticTraceable.cs | 0
DiscUtils/{Core => }/IFileSystem.cs | 0
DiscUtils/{Core => }/IUnixFileSystem.cs | 0
DiscUtils/{Core => }/IWindowsFileSystem.cs | 0
DiscUtils/{Core => }/Internal/Crc32.cs | 0
.../{Core => }/Internal/Crc32Algorithm.cs | 0
.../{Core => }/Internal/Crc32BigEndian.cs | 0
.../{Core => }/Internal/Crc32LittleEndian.cs | 0
.../{Core => }/Internal/LocalFileLocator.cs | 0
.../Internal/LogicalVolumeFactory.cs | 0
.../Internal/LogicalVolumeFactoryAttribute.cs | 0
DiscUtils/{Core => }/Internal/ObjectCache.cs | 0
DiscUtils/{Core => }/Internal/Utilities.cs | 0
.../{Core => }/Internal/VirtualDiskFactory.cs | 0
.../Internal/VirtualDiskFactoryAttribute.cs | 0
.../Internal/VirtualDiskTransport.cs | 0
.../Internal/VirtualDiskTransportAttribute.cs | 0
.../{Core => }/InvalidFileSystemException.cs | 0
DiscUtils/Iso9660/BaseVolumeDescriptor.cs | 6 +-
DiscUtils/Iso9660/BootVolumeDescriptor.cs | 4 +-
.../Iso9660/BootVolumeDescriptorRegion.cs | 6 +-
DiscUtils/Iso9660/BuildDirectoryInfo.cs | 24 +-
DiscUtils/Iso9660/BuildParameters.cs | 3 -
DiscUtils/Iso9660/CDBuilder.cs | 100 ++--
DiscUtils/Iso9660/CDReader.cs | 36 +-
DiscUtils/Iso9660/CommonVolumeDescriptor.cs | 7 +-
DiscUtils/Iso9660/DiscUtils.Iso9660.csproj | 14 -
DiscUtils/Iso9660/ExtentStream.cs | 6 +-
DiscUtils/Iso9660/File.cs | 2 +-
DiscUtils/Iso9660/IsoContext.cs | 7 -
DiscUtils/Iso9660/IsoUtilities.cs | 2 +-
DiscUtils/Iso9660/PrimaryVolumeDescriptor.cs | 5 +-
.../Iso9660/PrimaryVolumeDescriptorRegion.cs | 6 +-
DiscUtils/Iso9660/ReaderDirectory.cs | 6 +-
.../Iso9660/SupplementaryVolumeDescriptor.cs | 5 +-
.../SupplementaryVolumeDescriptorRegion.cs | 6 +-
DiscUtils/Iso9660/VfsCDReader.cs | 55 +-
.../Iso9660/VolumeDescriptorDiskRegion.cs | 4 +-
.../Iso9660/VolumeDescriptorSetTerminator.cs | 4 +-
.../VolumeDescriptorSetTerminatorRegion.cs | 6 +-
DiscUtils/Iso9660Ps1/BaseVolumeDescriptor.cs | 60 ++
DiscUtils/Iso9660Ps1/BootDeviceEmulation.cs | 55 ++
DiscUtils/Iso9660Ps1/BootInitialEntry.cs | 60 ++
DiscUtils/Iso9660Ps1/BootValidationEntry.cs | 88 +++
DiscUtils/Iso9660Ps1/BootVolumeDescriptor.cs | 56 ++
.../Iso9660Ps1/BootVolumeDescriptorRegion.cs | 42 ++
DiscUtils/Iso9660Ps1/BuildDirectoryInfo.cs | 219 ++++++++
DiscUtils/Iso9660Ps1/BuildDirectoryMember.cs | 155 +++++
DiscUtils/Iso9660Ps1/BuildFileInfo.cs | 136 +++++
DiscUtils/Iso9660Ps1/BuildParameters.cs | 40 ++
DiscUtils/Iso9660Ps1/CDBuilder.cs | 518 +++++++++++++++++
DiscUtils/Iso9660Ps1/CDReader.cs | 229 ++++++++
.../Iso9660Ps1/CommonVolumeDescriptor.cs | 141 +++++
DiscUtils/Iso9660Ps1/DirectoryExtent.cs | 71 +++
DiscUtils/Iso9660Ps1/DirectoryRecord.cs | 114 ++++
DiscUtils/Iso9660Ps1/ExtentStream.cs | 125 +++++
DiscUtils/Iso9660Ps1/File.cs | 119 ++++
DiscUtils/Iso9660Ps1/FileExtent.cs | 85 +++
DiscUtils/Iso9660Ps1/FileFlags.cs | 16 +
DiscUtils/Iso9660Ps1/Iso9660Variant.cs | 60 ++
DiscUtils/Iso9660Ps1/IsoContext.cs | 49 ++
DiscUtils/Iso9660Ps1/IsoUtilities.cs | 467 +++++++++++++++
DiscUtils/Iso9660Ps1/PathTable.cs | 100 ++++
DiscUtils/Iso9660Ps1/PathTableRecord.cs | 71 +++
.../Iso9660Ps1/PrimaryVolumeDescriptor.cs | 76 +++
.../PrimaryVolumeDescriptorRegion.cs | 42 ++
DiscUtils/Iso9660Ps1/ReaderDirEntry.cs | 195 +++++++
DiscUtils/Iso9660Ps1/ReaderDirectory.cs | 130 +++++
.../RockRidge/ChildLinkSystemUseEntry.cs | 36 ++
.../RockRidge/FileTimeSystemUseEntry.cs | 94 ++++
.../RockRidge/PosixFileInfoSystemUseEntry.cs | 48 ++
.../RockRidge/PosixNameSystemUseEntry.cs | 40 ++
.../RockRidge/RockRidgeExtension.cs | 57 ++
.../SupplementaryVolumeDescriptor.cs | 80 +++
.../SupplementaryVolumeDescriptorRegion.cs | 42 ++
.../Susp/ContinuationSystemUseEntry.cs | 40 ++
.../Susp/ExtensionSelectSystemUseEntry.cs | 36 ++
.../Susp/ExtensionSystemUseEntry.cs | 56 ++
.../Iso9660Ps1/Susp/GenericSuspExtension.cs | 41 ++
.../Iso9660Ps1/Susp/GenericSystemUseEntry.cs | 39 ++
.../Iso9660Ps1/Susp/PaddingSystemUseEntry.cs | 32 ++
.../Susp/SharingProtocolSystemUseEntry.cs | 43 ++
DiscUtils/Iso9660Ps1/Susp/SuspExtension.cs | 33 ++
DiscUtils/Iso9660Ps1/Susp/SuspRecords.cs | 182 ++++++
DiscUtils/Iso9660Ps1/Susp/SystemUseEntry.cs | 105 ++++
DiscUtils/Iso9660Ps1/VfsCDReader.cs | 530 ++++++++++++++++++
.../Iso9660Ps1/VolumeDescriptorDiskRegion.cs | 60 ++
.../VolumeDescriptorSetTerminator.cs | 30 +
.../VolumeDescriptorSetTerminatorRegion.cs | 42 ++
DiscUtils/Iso9660Ps1/VolumeDescriptorType.cs | 11 +
.../LogicalDiskManager/ComponentRecord.cs | 0
.../{Core => }/LogicalDiskManager/Database.cs | 0
.../LogicalDiskManager/DatabaseHeader.cs | 0
.../LogicalDiskManager/DatabaseRecord.cs | 0
.../LogicalDiskManager/DiskGroupRecord.cs | 0
.../LogicalDiskManager/DiskRecord.cs | 0
.../LogicalDiskManager/DynamicDisk.cs | 0
.../LogicalDiskManager/DynamicDiskGroup.cs | 0
.../LogicalDiskManager/DynamicDiskManager.cs | 0
.../DynamicDiskManagerFactory.cs | 0
.../LogicalDiskManager/DynamicVolume.cs | 0
.../LogicalDiskManager/ExtentMergeType.cs | 0
.../LogicalDiskManager/ExtentRecord.cs | 0
.../LogicalDiskManager/PrivateHeader.cs | 0
.../LogicalDiskManager/RecordType.cs | 0
.../{Core => }/LogicalDiskManager/TocBlock.cs | 0
.../LogicalDiskManager/VolumeRecord.cs | 0
DiscUtils/{Core => }/LogicalVolumeInfo.cs | 0
DiscUtils/{Core => }/LogicalVolumeStatus.cs | 0
DiscUtils/{Core => }/NativeFileSystem.cs | 0
.../Partitions/BiosExtendedPartitionTable.cs | 0
.../Partitions/BiosPartitionInfo.cs | 0
.../Partitions/BiosPartitionRecord.cs | 0
.../Partitions/BiosPartitionTable.cs | 0
.../Partitions/BiosPartitionTypes.cs | 0
.../Partitions/BiosPartitionedDiskBuilder.cs | 0
.../DefaultPartitionTableFactory.cs | 0
DiscUtils/{Core => }/Partitions/GptEntry.cs | 0
DiscUtils/{Core => }/Partitions/GptHeader.cs | 0
.../Partitions/GuidPartitionInfo.cs | 0
.../Partitions/GuidPartitionTable.cs | 0
.../Partitions/GuidPartitionTypes.cs | 0
.../{Core => }/Partitions/PartitionInfo.cs | 0
.../{Core => }/Partitions/PartitionTable.cs | 0
.../Partitions/PartitionTableFactory.cs | 0
.../PartitionTableFactoryAttribute.cs | 0
.../Partitions/WellKnownPartitionType.cs | 0
DiscUtils/{Core => }/PhysicalVolumeInfo.cs | 0
DiscUtils/{Core => }/PhysicalVolumeType.cs | 0
DiscUtils/{Core => }/Plist.cs | 0
DiscUtils/{Core => }/Raw/Disk.cs | 0
DiscUtils/{Core => }/Raw/DiskFactory.cs | 0
DiscUtils/{Core => }/Raw/DiskImageFile.cs | 0
.../{Core => }/ReadOnlyDiscFileSystem.cs | 0
DiscUtils/{Core => }/ReparsePoint.cs | 0
DiscUtils/{Core => }/ReportLevels.cs | 0
.../{Core => }/Setup/FileOpenEventArgs.cs | 0
DiscUtils/{Core => }/Setup/SetupHelper.cs | 0
DiscUtils/Streams/DiscUtils.Streams.csproj | 10 -
.../System/DateTimeOffsetExtensions.cs | 0
.../{Core => }/System/ExtensionAttribute.cs | 0
DiscUtils/{Core => }/System/HashSet.cs | 0
DiscUtils/{Core => }/System/Tuple.cs | 0
DiscUtils/{Core => }/TimeConverter.cs | 0
DiscUtils/{Core => }/UnixFilePermissions.cs | 0
DiscUtils/{Core => }/UnixFileSystemInfo.cs | 0
DiscUtils/{Core => }/UnixFileType.cs | 0
DiscUtils/{Core => }/Vfs/IVfsDirectory.cs | 0
DiscUtils/{Core => }/Vfs/IVfsFile.cs | 0
.../{Core => }/Vfs/IVfsFileWithStreams.cs | 0
DiscUtils/{Core => }/Vfs/IVfsSymlink.cs | 0
DiscUtils/{Core => }/Vfs/VfsContext.cs | 0
DiscUtils/{Core => }/Vfs/VfsDirEntry.cs | 0
DiscUtils/{Core => }/Vfs/VfsFileSystem.cs | 0
.../{Core => }/Vfs/VfsFileSystemFacade.cs | 0
.../{Core => }/Vfs/VfsFileSystemFactory.cs | 0
.../Vfs/VfsFileSystemFactoryAttribute.cs | 0
DiscUtils/{Core => }/Vfs/VfsFileSystemInfo.cs | 0
.../{Core => }/Vfs/VfsFileSystemOpener.cs | 0
.../{Core => }/Vfs/VfsReadOnlyFileSystem.cs | 0
DiscUtils/{Core => }/VirtualDisk.cs | 0
DiscUtils/{Core => }/VirtualDiskClass.cs | 0
DiscUtils/{Core => }/VirtualDiskExtent.cs | 0
DiscUtils/{Core => }/VirtualDiskLayer.cs | 0
DiscUtils/{Core => }/VirtualDiskManager.cs | 0
DiscUtils/{Core => }/VirtualDiskParameters.cs | 0
DiscUtils/{Core => }/VirtualDiskTypeInfo.cs | 0
DiscUtils/{Core => }/VolumeInfo.cs | 0
DiscUtils/{Core => }/VolumeManager.cs | 0
.../{Core => }/WindowsFileInformation.cs | 0
PopsBuilder/Pops/DiscInfo.cs | 2 +-
PopsBuilder/Pops/PsIsoImg.cs | 5 +-
PopsBuilder/Psp/UmdInfo.cs | 2 +-
228 files changed, 5315 insertions(+), 231 deletions(-)
rename DiscUtils/{Core => }/ApplePartitionMap/BlockZero.cs (100%)
rename DiscUtils/{Core => }/ApplePartitionMap/PartitionMap.cs (100%)
rename DiscUtils/{Core => }/ApplePartitionMap/PartitionMapEntry.cs (100%)
rename DiscUtils/{Core => }/ApplePartitionMap/PartitionMapFactory.cs (100%)
rename DiscUtils/{Core => }/Archives/FileRecord.cs (100%)
rename DiscUtils/{Core => }/Archives/TarFile.cs (100%)
rename DiscUtils/{Core => }/Archives/TarFileBuilder.cs (100%)
rename DiscUtils/{Core => }/Archives/TarHeader.cs (100%)
rename DiscUtils/{Core => }/Archives/TarHeaderExtent.cs (100%)
rename DiscUtils/{Core => }/Archives/UnixBuildFileRecord.cs (100%)
rename DiscUtils/{Core => }/ChsAddress.cs (100%)
rename DiscUtils/{Core => }/ClusterMap.cs (100%)
rename DiscUtils/{Core => }/ClusterRoles.cs (100%)
rename DiscUtils/{Core => }/Compression/Adler32.cs (100%)
rename DiscUtils/{Core => }/Compression/BZip2BlockDecoder.cs (100%)
rename DiscUtils/{Core => }/Compression/BZip2CombinedHuffmanTrees.cs (100%)
rename DiscUtils/{Core => }/Compression/BZip2DecoderStream.cs (100%)
rename DiscUtils/{Core => }/Compression/BZip2Randomizer.cs (100%)
rename DiscUtils/{Core => }/Compression/BZip2RleStream.cs (100%)
rename DiscUtils/{Core => }/Compression/BigEndianBitStream.cs (100%)
rename DiscUtils/{Core => }/Compression/BitStream.cs (100%)
rename DiscUtils/{Core => }/Compression/BlockCompressor.cs (100%)
rename DiscUtils/{Core => }/Compression/CompressionResult.cs (100%)
rename DiscUtils/{Core => }/Compression/DataBlockTransform.cs (100%)
rename DiscUtils/{Core => }/Compression/HuffmanTree.cs (100%)
rename DiscUtils/{Core => }/Compression/InverseBurrowsWheeler.cs (100%)
rename DiscUtils/{Core => }/Compression/MoveToFront.cs (100%)
rename DiscUtils/{Core => }/Compression/SizedDeflateStream.cs (100%)
rename DiscUtils/{Core => }/Compression/ZlibBuffer.cs (100%)
rename DiscUtils/{Core => }/Compression/ZlibStream.cs (100%)
delete mode 100644 DiscUtils/Core/DiscUtils.Core.csproj
rename DiscUtils/{Core => }/CoreCompat/EncodingHelper.cs (100%)
rename DiscUtils/{Core => }/CoreCompat/ReflectionHelper.cs (100%)
rename DiscUtils/{Core => }/CoreCompat/StringExtensions.cs (100%)
rename DiscUtils/{Core => }/DiscDirectoryInfo.cs (100%)
rename DiscUtils/{Core => }/DiscFileInfo.cs (100%)
rename DiscUtils/{Core => }/DiscFileLocator.cs (100%)
rename DiscUtils/{Core => }/DiscFileSystem.cs (100%)
rename DiscUtils/{Core => }/DiscFileSystemChecker.cs (100%)
rename DiscUtils/{Core => }/DiscFileSystemInfo.cs (100%)
rename DiscUtils/{Core => }/DiscFileSystemOptions.cs (100%)
rename DiscUtils/{Core => }/DiskImageBuilder.cs (100%)
rename DiscUtils/{Core => }/DiskImageFileSpecification.cs (100%)
rename DiscUtils/{Core => }/FileLocator.cs (100%)
rename DiscUtils/{Core => }/FileSystemInfo.cs (100%)
rename DiscUtils/{Core => }/FileSystemManager.cs (100%)
rename DiscUtils/{Core => }/FileSystemParameters.cs (100%)
rename DiscUtils/{Core => }/FileTransport.cs (100%)
rename DiscUtils/{Core => }/FloppyDiskType.cs (100%)
rename DiscUtils/{Core => }/GenericDiskAdapterType.cs (100%)
rename DiscUtils/{Core => }/Geometry.cs (100%)
rename DiscUtils/{Core => }/GeometryCalculation.cs (100%)
rename DiscUtils/{Core => }/GeometryTranslation.cs (100%)
rename DiscUtils/{Core => }/IClusterBasedFileSystem.cs (100%)
rename DiscUtils/{Core => }/IDiagnosticTraceable.cs (100%)
rename DiscUtils/{Core => }/IFileSystem.cs (100%)
rename DiscUtils/{Core => }/IUnixFileSystem.cs (100%)
rename DiscUtils/{Core => }/IWindowsFileSystem.cs (100%)
rename DiscUtils/{Core => }/Internal/Crc32.cs (100%)
rename DiscUtils/{Core => }/Internal/Crc32Algorithm.cs (100%)
rename DiscUtils/{Core => }/Internal/Crc32BigEndian.cs (100%)
rename DiscUtils/{Core => }/Internal/Crc32LittleEndian.cs (100%)
rename DiscUtils/{Core => }/Internal/LocalFileLocator.cs (100%)
rename DiscUtils/{Core => }/Internal/LogicalVolumeFactory.cs (100%)
rename DiscUtils/{Core => }/Internal/LogicalVolumeFactoryAttribute.cs (100%)
rename DiscUtils/{Core => }/Internal/ObjectCache.cs (100%)
rename DiscUtils/{Core => }/Internal/Utilities.cs (100%)
rename DiscUtils/{Core => }/Internal/VirtualDiskFactory.cs (100%)
rename DiscUtils/{Core => }/Internal/VirtualDiskFactoryAttribute.cs (100%)
rename DiscUtils/{Core => }/Internal/VirtualDiskTransport.cs (100%)
rename DiscUtils/{Core => }/Internal/VirtualDiskTransportAttribute.cs (100%)
rename DiscUtils/{Core => }/InvalidFileSystemException.cs (100%)
delete mode 100644 DiscUtils/Iso9660/DiscUtils.Iso9660.csproj
create mode 100644 DiscUtils/Iso9660Ps1/BaseVolumeDescriptor.cs
create mode 100644 DiscUtils/Iso9660Ps1/BootDeviceEmulation.cs
create mode 100644 DiscUtils/Iso9660Ps1/BootInitialEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/BootValidationEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/BootVolumeDescriptor.cs
create mode 100644 DiscUtils/Iso9660Ps1/BootVolumeDescriptorRegion.cs
create mode 100644 DiscUtils/Iso9660Ps1/BuildDirectoryInfo.cs
create mode 100644 DiscUtils/Iso9660Ps1/BuildDirectoryMember.cs
create mode 100644 DiscUtils/Iso9660Ps1/BuildFileInfo.cs
create mode 100644 DiscUtils/Iso9660Ps1/BuildParameters.cs
create mode 100644 DiscUtils/Iso9660Ps1/CDBuilder.cs
create mode 100644 DiscUtils/Iso9660Ps1/CDReader.cs
create mode 100644 DiscUtils/Iso9660Ps1/CommonVolumeDescriptor.cs
create mode 100644 DiscUtils/Iso9660Ps1/DirectoryExtent.cs
create mode 100644 DiscUtils/Iso9660Ps1/DirectoryRecord.cs
create mode 100644 DiscUtils/Iso9660Ps1/ExtentStream.cs
create mode 100644 DiscUtils/Iso9660Ps1/File.cs
create mode 100644 DiscUtils/Iso9660Ps1/FileExtent.cs
create mode 100644 DiscUtils/Iso9660Ps1/FileFlags.cs
create mode 100644 DiscUtils/Iso9660Ps1/Iso9660Variant.cs
create mode 100644 DiscUtils/Iso9660Ps1/IsoContext.cs
create mode 100644 DiscUtils/Iso9660Ps1/IsoUtilities.cs
create mode 100644 DiscUtils/Iso9660Ps1/PathTable.cs
create mode 100644 DiscUtils/Iso9660Ps1/PathTableRecord.cs
create mode 100644 DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptor.cs
create mode 100644 DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptorRegion.cs
create mode 100644 DiscUtils/Iso9660Ps1/ReaderDirEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/ReaderDirectory.cs
create mode 100644 DiscUtils/Iso9660Ps1/RockRidge/ChildLinkSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/RockRidge/FileTimeSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/RockRidge/PosixFileInfoSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/RockRidge/PosixNameSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/RockRidge/RockRidgeExtension.cs
create mode 100644 DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptor.cs
create mode 100644 DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptorRegion.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/ContinuationSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/ExtensionSelectSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/ExtensionSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/GenericSuspExtension.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/GenericSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/PaddingSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/SharingProtocolSystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/SuspExtension.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/SuspRecords.cs
create mode 100644 DiscUtils/Iso9660Ps1/Susp/SystemUseEntry.cs
create mode 100644 DiscUtils/Iso9660Ps1/VfsCDReader.cs
create mode 100644 DiscUtils/Iso9660Ps1/VolumeDescriptorDiskRegion.cs
create mode 100644 DiscUtils/Iso9660Ps1/VolumeDescriptorSetTerminator.cs
create mode 100644 DiscUtils/Iso9660Ps1/VolumeDescriptorSetTerminatorRegion.cs
create mode 100644 DiscUtils/Iso9660Ps1/VolumeDescriptorType.cs
rename DiscUtils/{Core => }/LogicalDiskManager/ComponentRecord.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/Database.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DatabaseHeader.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DatabaseRecord.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DiskGroupRecord.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DiskRecord.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DynamicDisk.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DynamicDiskGroup.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DynamicDiskManager.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DynamicDiskManagerFactory.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/DynamicVolume.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/ExtentMergeType.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/ExtentRecord.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/PrivateHeader.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/RecordType.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/TocBlock.cs (100%)
rename DiscUtils/{Core => }/LogicalDiskManager/VolumeRecord.cs (100%)
rename DiscUtils/{Core => }/LogicalVolumeInfo.cs (100%)
rename DiscUtils/{Core => }/LogicalVolumeStatus.cs (100%)
rename DiscUtils/{Core => }/NativeFileSystem.cs (100%)
rename DiscUtils/{Core => }/Partitions/BiosExtendedPartitionTable.cs (100%)
rename DiscUtils/{Core => }/Partitions/BiosPartitionInfo.cs (100%)
rename DiscUtils/{Core => }/Partitions/BiosPartitionRecord.cs (100%)
rename DiscUtils/{Core => }/Partitions/BiosPartitionTable.cs (100%)
rename DiscUtils/{Core => }/Partitions/BiosPartitionTypes.cs (100%)
rename DiscUtils/{Core => }/Partitions/BiosPartitionedDiskBuilder.cs (100%)
rename DiscUtils/{Core => }/Partitions/DefaultPartitionTableFactory.cs (100%)
rename DiscUtils/{Core => }/Partitions/GptEntry.cs (100%)
rename DiscUtils/{Core => }/Partitions/GptHeader.cs (100%)
rename DiscUtils/{Core => }/Partitions/GuidPartitionInfo.cs (100%)
rename DiscUtils/{Core => }/Partitions/GuidPartitionTable.cs (100%)
rename DiscUtils/{Core => }/Partitions/GuidPartitionTypes.cs (100%)
rename DiscUtils/{Core => }/Partitions/PartitionInfo.cs (100%)
rename DiscUtils/{Core => }/Partitions/PartitionTable.cs (100%)
rename DiscUtils/{Core => }/Partitions/PartitionTableFactory.cs (100%)
rename DiscUtils/{Core => }/Partitions/PartitionTableFactoryAttribute.cs (100%)
rename DiscUtils/{Core => }/Partitions/WellKnownPartitionType.cs (100%)
rename DiscUtils/{Core => }/PhysicalVolumeInfo.cs (100%)
rename DiscUtils/{Core => }/PhysicalVolumeType.cs (100%)
rename DiscUtils/{Core => }/Plist.cs (100%)
rename DiscUtils/{Core => }/Raw/Disk.cs (100%)
rename DiscUtils/{Core => }/Raw/DiskFactory.cs (100%)
rename DiscUtils/{Core => }/Raw/DiskImageFile.cs (100%)
rename DiscUtils/{Core => }/ReadOnlyDiscFileSystem.cs (100%)
rename DiscUtils/{Core => }/ReparsePoint.cs (100%)
rename DiscUtils/{Core => }/ReportLevels.cs (100%)
rename DiscUtils/{Core => }/Setup/FileOpenEventArgs.cs (100%)
rename DiscUtils/{Core => }/Setup/SetupHelper.cs (100%)
delete mode 100644 DiscUtils/Streams/DiscUtils.Streams.csproj
rename DiscUtils/{Core => }/System/DateTimeOffsetExtensions.cs (100%)
rename DiscUtils/{Core => }/System/ExtensionAttribute.cs (100%)
rename DiscUtils/{Core => }/System/HashSet.cs (100%)
rename DiscUtils/{Core => }/System/Tuple.cs (100%)
rename DiscUtils/{Core => }/TimeConverter.cs (100%)
rename DiscUtils/{Core => }/UnixFilePermissions.cs (100%)
rename DiscUtils/{Core => }/UnixFileSystemInfo.cs (100%)
rename DiscUtils/{Core => }/UnixFileType.cs (100%)
rename DiscUtils/{Core => }/Vfs/IVfsDirectory.cs (100%)
rename DiscUtils/{Core => }/Vfs/IVfsFile.cs (100%)
rename DiscUtils/{Core => }/Vfs/IVfsFileWithStreams.cs (100%)
rename DiscUtils/{Core => }/Vfs/IVfsSymlink.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsContext.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsDirEntry.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsFileSystem.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsFileSystemFacade.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsFileSystemFactory.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsFileSystemFactoryAttribute.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsFileSystemInfo.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsFileSystemOpener.cs (100%)
rename DiscUtils/{Core => }/Vfs/VfsReadOnlyFileSystem.cs (100%)
rename DiscUtils/{Core => }/VirtualDisk.cs (100%)
rename DiscUtils/{Core => }/VirtualDiskClass.cs (100%)
rename DiscUtils/{Core => }/VirtualDiskExtent.cs (100%)
rename DiscUtils/{Core => }/VirtualDiskLayer.cs (100%)
rename DiscUtils/{Core => }/VirtualDiskManager.cs (100%)
rename DiscUtils/{Core => }/VirtualDiskParameters.cs (100%)
rename DiscUtils/{Core => }/VirtualDiskTypeInfo.cs (100%)
rename DiscUtils/{Core => }/VolumeInfo.cs (100%)
rename DiscUtils/{Core => }/VolumeManager.cs (100%)
rename DiscUtils/{Core => }/WindowsFileInformation.cs (100%)
diff --git a/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user b/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user
index 0d6a3e7..1fb038a 100644
--- a/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user
+++ b/ChovySign-CLI/Properties/PublishProfiles/FolderProfile.pubxml.user
@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
-->
- True|2023-04-16T21:56:35.5065135Z;True|2023-04-17T09:22:54.8607008+12:00;True|2023-04-17T08:27:16.5281469+12:00;True|2023-04-17T08:22:02.0531219+12:00;
+ True|2023-04-17T12:00:51.4131559Z;True|2023-04-17T09:56:35.5065135+12:00;True|2023-04-17T09:22:54.8607008+12:00;True|2023-04-17T08:27:16.5281469+12:00;True|2023-04-17T08:22:02.0531219+12:00;
\ No newline at end of file
diff --git a/DiscUtils/Core/ApplePartitionMap/BlockZero.cs b/DiscUtils/ApplePartitionMap/BlockZero.cs
similarity index 100%
rename from DiscUtils/Core/ApplePartitionMap/BlockZero.cs
rename to DiscUtils/ApplePartitionMap/BlockZero.cs
diff --git a/DiscUtils/Core/ApplePartitionMap/PartitionMap.cs b/DiscUtils/ApplePartitionMap/PartitionMap.cs
similarity index 100%
rename from DiscUtils/Core/ApplePartitionMap/PartitionMap.cs
rename to DiscUtils/ApplePartitionMap/PartitionMap.cs
diff --git a/DiscUtils/Core/ApplePartitionMap/PartitionMapEntry.cs b/DiscUtils/ApplePartitionMap/PartitionMapEntry.cs
similarity index 100%
rename from DiscUtils/Core/ApplePartitionMap/PartitionMapEntry.cs
rename to DiscUtils/ApplePartitionMap/PartitionMapEntry.cs
diff --git a/DiscUtils/Core/ApplePartitionMap/PartitionMapFactory.cs b/DiscUtils/ApplePartitionMap/PartitionMapFactory.cs
similarity index 100%
rename from DiscUtils/Core/ApplePartitionMap/PartitionMapFactory.cs
rename to DiscUtils/ApplePartitionMap/PartitionMapFactory.cs
diff --git a/DiscUtils/Core/Archives/FileRecord.cs b/DiscUtils/Archives/FileRecord.cs
similarity index 100%
rename from DiscUtils/Core/Archives/FileRecord.cs
rename to DiscUtils/Archives/FileRecord.cs
diff --git a/DiscUtils/Core/Archives/TarFile.cs b/DiscUtils/Archives/TarFile.cs
similarity index 100%
rename from DiscUtils/Core/Archives/TarFile.cs
rename to DiscUtils/Archives/TarFile.cs
diff --git a/DiscUtils/Core/Archives/TarFileBuilder.cs b/DiscUtils/Archives/TarFileBuilder.cs
similarity index 100%
rename from DiscUtils/Core/Archives/TarFileBuilder.cs
rename to DiscUtils/Archives/TarFileBuilder.cs
diff --git a/DiscUtils/Core/Archives/TarHeader.cs b/DiscUtils/Archives/TarHeader.cs
similarity index 100%
rename from DiscUtils/Core/Archives/TarHeader.cs
rename to DiscUtils/Archives/TarHeader.cs
diff --git a/DiscUtils/Core/Archives/TarHeaderExtent.cs b/DiscUtils/Archives/TarHeaderExtent.cs
similarity index 100%
rename from DiscUtils/Core/Archives/TarHeaderExtent.cs
rename to DiscUtils/Archives/TarHeaderExtent.cs
diff --git a/DiscUtils/Core/Archives/UnixBuildFileRecord.cs b/DiscUtils/Archives/UnixBuildFileRecord.cs
similarity index 100%
rename from DiscUtils/Core/Archives/UnixBuildFileRecord.cs
rename to DiscUtils/Archives/UnixBuildFileRecord.cs
diff --git a/DiscUtils/Core/ChsAddress.cs b/DiscUtils/ChsAddress.cs
similarity index 100%
rename from DiscUtils/Core/ChsAddress.cs
rename to DiscUtils/ChsAddress.cs
diff --git a/DiscUtils/Core/ClusterMap.cs b/DiscUtils/ClusterMap.cs
similarity index 100%
rename from DiscUtils/Core/ClusterMap.cs
rename to DiscUtils/ClusterMap.cs
diff --git a/DiscUtils/Core/ClusterRoles.cs b/DiscUtils/ClusterRoles.cs
similarity index 100%
rename from DiscUtils/Core/ClusterRoles.cs
rename to DiscUtils/ClusterRoles.cs
diff --git a/DiscUtils/Core/Compression/Adler32.cs b/DiscUtils/Compression/Adler32.cs
similarity index 100%
rename from DiscUtils/Core/Compression/Adler32.cs
rename to DiscUtils/Compression/Adler32.cs
diff --git a/DiscUtils/Core/Compression/BZip2BlockDecoder.cs b/DiscUtils/Compression/BZip2BlockDecoder.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BZip2BlockDecoder.cs
rename to DiscUtils/Compression/BZip2BlockDecoder.cs
diff --git a/DiscUtils/Core/Compression/BZip2CombinedHuffmanTrees.cs b/DiscUtils/Compression/BZip2CombinedHuffmanTrees.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BZip2CombinedHuffmanTrees.cs
rename to DiscUtils/Compression/BZip2CombinedHuffmanTrees.cs
diff --git a/DiscUtils/Core/Compression/BZip2DecoderStream.cs b/DiscUtils/Compression/BZip2DecoderStream.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BZip2DecoderStream.cs
rename to DiscUtils/Compression/BZip2DecoderStream.cs
diff --git a/DiscUtils/Core/Compression/BZip2Randomizer.cs b/DiscUtils/Compression/BZip2Randomizer.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BZip2Randomizer.cs
rename to DiscUtils/Compression/BZip2Randomizer.cs
diff --git a/DiscUtils/Core/Compression/BZip2RleStream.cs b/DiscUtils/Compression/BZip2RleStream.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BZip2RleStream.cs
rename to DiscUtils/Compression/BZip2RleStream.cs
diff --git a/DiscUtils/Core/Compression/BigEndianBitStream.cs b/DiscUtils/Compression/BigEndianBitStream.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BigEndianBitStream.cs
rename to DiscUtils/Compression/BigEndianBitStream.cs
diff --git a/DiscUtils/Core/Compression/BitStream.cs b/DiscUtils/Compression/BitStream.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BitStream.cs
rename to DiscUtils/Compression/BitStream.cs
diff --git a/DiscUtils/Core/Compression/BlockCompressor.cs b/DiscUtils/Compression/BlockCompressor.cs
similarity index 100%
rename from DiscUtils/Core/Compression/BlockCompressor.cs
rename to DiscUtils/Compression/BlockCompressor.cs
diff --git a/DiscUtils/Core/Compression/CompressionResult.cs b/DiscUtils/Compression/CompressionResult.cs
similarity index 100%
rename from DiscUtils/Core/Compression/CompressionResult.cs
rename to DiscUtils/Compression/CompressionResult.cs
diff --git a/DiscUtils/Core/Compression/DataBlockTransform.cs b/DiscUtils/Compression/DataBlockTransform.cs
similarity index 100%
rename from DiscUtils/Core/Compression/DataBlockTransform.cs
rename to DiscUtils/Compression/DataBlockTransform.cs
diff --git a/DiscUtils/Core/Compression/HuffmanTree.cs b/DiscUtils/Compression/HuffmanTree.cs
similarity index 100%
rename from DiscUtils/Core/Compression/HuffmanTree.cs
rename to DiscUtils/Compression/HuffmanTree.cs
diff --git a/DiscUtils/Core/Compression/InverseBurrowsWheeler.cs b/DiscUtils/Compression/InverseBurrowsWheeler.cs
similarity index 100%
rename from DiscUtils/Core/Compression/InverseBurrowsWheeler.cs
rename to DiscUtils/Compression/InverseBurrowsWheeler.cs
diff --git a/DiscUtils/Core/Compression/MoveToFront.cs b/DiscUtils/Compression/MoveToFront.cs
similarity index 100%
rename from DiscUtils/Core/Compression/MoveToFront.cs
rename to DiscUtils/Compression/MoveToFront.cs
diff --git a/DiscUtils/Core/Compression/SizedDeflateStream.cs b/DiscUtils/Compression/SizedDeflateStream.cs
similarity index 100%
rename from DiscUtils/Core/Compression/SizedDeflateStream.cs
rename to DiscUtils/Compression/SizedDeflateStream.cs
diff --git a/DiscUtils/Core/Compression/ZlibBuffer.cs b/DiscUtils/Compression/ZlibBuffer.cs
similarity index 100%
rename from DiscUtils/Core/Compression/ZlibBuffer.cs
rename to DiscUtils/Compression/ZlibBuffer.cs
diff --git a/DiscUtils/Core/Compression/ZlibStream.cs b/DiscUtils/Compression/ZlibStream.cs
similarity index 100%
rename from DiscUtils/Core/Compression/ZlibStream.cs
rename to DiscUtils/Compression/ZlibStream.cs
diff --git a/DiscUtils/Core/DiscUtils.Core.csproj b/DiscUtils/Core/DiscUtils.Core.csproj
deleted file mode 100644
index 8abd0ad..0000000
--- a/DiscUtils/Core/DiscUtils.Core.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- Implementation of the ISO, UDF, FAT and NTFS file systems is now fairly stable. VHD, XVA, VMDK and VDI disk formats are implemented, as well as read/write Registry support. The library also includes a simple iSCSI initiator, for accessing disks via iSCSI and an NFS client implementation.
- DiscUtils (for .NET and .NET Core), core library that supports parts of DiscUtils
- Kenneth Bell;Quamotion;LordMike
- DiscUtils;VHD;VDI;XVA;VMDK;ISO;NTFS;EXT2FS
-
-
-
-
-
-
-
diff --git a/DiscUtils/Core/CoreCompat/EncodingHelper.cs b/DiscUtils/CoreCompat/EncodingHelper.cs
similarity index 100%
rename from DiscUtils/Core/CoreCompat/EncodingHelper.cs
rename to DiscUtils/CoreCompat/EncodingHelper.cs
diff --git a/DiscUtils/Core/CoreCompat/ReflectionHelper.cs b/DiscUtils/CoreCompat/ReflectionHelper.cs
similarity index 100%
rename from DiscUtils/Core/CoreCompat/ReflectionHelper.cs
rename to DiscUtils/CoreCompat/ReflectionHelper.cs
diff --git a/DiscUtils/Core/CoreCompat/StringExtensions.cs b/DiscUtils/CoreCompat/StringExtensions.cs
similarity index 100%
rename from DiscUtils/Core/CoreCompat/StringExtensions.cs
rename to DiscUtils/CoreCompat/StringExtensions.cs
diff --git a/DiscUtils/Core/DiscDirectoryInfo.cs b/DiscUtils/DiscDirectoryInfo.cs
similarity index 100%
rename from DiscUtils/Core/DiscDirectoryInfo.cs
rename to DiscUtils/DiscDirectoryInfo.cs
diff --git a/DiscUtils/Core/DiscFileInfo.cs b/DiscUtils/DiscFileInfo.cs
similarity index 100%
rename from DiscUtils/Core/DiscFileInfo.cs
rename to DiscUtils/DiscFileInfo.cs
diff --git a/DiscUtils/Core/DiscFileLocator.cs b/DiscUtils/DiscFileLocator.cs
similarity index 100%
rename from DiscUtils/Core/DiscFileLocator.cs
rename to DiscUtils/DiscFileLocator.cs
diff --git a/DiscUtils/Core/DiscFileSystem.cs b/DiscUtils/DiscFileSystem.cs
similarity index 100%
rename from DiscUtils/Core/DiscFileSystem.cs
rename to DiscUtils/DiscFileSystem.cs
diff --git a/DiscUtils/Core/DiscFileSystemChecker.cs b/DiscUtils/DiscFileSystemChecker.cs
similarity index 100%
rename from DiscUtils/Core/DiscFileSystemChecker.cs
rename to DiscUtils/DiscFileSystemChecker.cs
diff --git a/DiscUtils/Core/DiscFileSystemInfo.cs b/DiscUtils/DiscFileSystemInfo.cs
similarity index 100%
rename from DiscUtils/Core/DiscFileSystemInfo.cs
rename to DiscUtils/DiscFileSystemInfo.cs
diff --git a/DiscUtils/Core/DiscFileSystemOptions.cs b/DiscUtils/DiscFileSystemOptions.cs
similarity index 100%
rename from DiscUtils/Core/DiscFileSystemOptions.cs
rename to DiscUtils/DiscFileSystemOptions.cs
diff --git a/DiscUtils/Core/DiskImageBuilder.cs b/DiscUtils/DiskImageBuilder.cs
similarity index 100%
rename from DiscUtils/Core/DiskImageBuilder.cs
rename to DiscUtils/DiskImageBuilder.cs
diff --git a/DiscUtils/Core/DiskImageFileSpecification.cs b/DiscUtils/DiskImageFileSpecification.cs
similarity index 100%
rename from DiscUtils/Core/DiskImageFileSpecification.cs
rename to DiscUtils/DiskImageFileSpecification.cs
diff --git a/DiscUtils/Core/FileLocator.cs b/DiscUtils/FileLocator.cs
similarity index 100%
rename from DiscUtils/Core/FileLocator.cs
rename to DiscUtils/FileLocator.cs
diff --git a/DiscUtils/Core/FileSystemInfo.cs b/DiscUtils/FileSystemInfo.cs
similarity index 100%
rename from DiscUtils/Core/FileSystemInfo.cs
rename to DiscUtils/FileSystemInfo.cs
diff --git a/DiscUtils/Core/FileSystemManager.cs b/DiscUtils/FileSystemManager.cs
similarity index 100%
rename from DiscUtils/Core/FileSystemManager.cs
rename to DiscUtils/FileSystemManager.cs
diff --git a/DiscUtils/Core/FileSystemParameters.cs b/DiscUtils/FileSystemParameters.cs
similarity index 100%
rename from DiscUtils/Core/FileSystemParameters.cs
rename to DiscUtils/FileSystemParameters.cs
diff --git a/DiscUtils/Core/FileTransport.cs b/DiscUtils/FileTransport.cs
similarity index 100%
rename from DiscUtils/Core/FileTransport.cs
rename to DiscUtils/FileTransport.cs
diff --git a/DiscUtils/Core/FloppyDiskType.cs b/DiscUtils/FloppyDiskType.cs
similarity index 100%
rename from DiscUtils/Core/FloppyDiskType.cs
rename to DiscUtils/FloppyDiskType.cs
diff --git a/DiscUtils/Core/GenericDiskAdapterType.cs b/DiscUtils/GenericDiskAdapterType.cs
similarity index 100%
rename from DiscUtils/Core/GenericDiskAdapterType.cs
rename to DiscUtils/GenericDiskAdapterType.cs
diff --git a/DiscUtils/Core/Geometry.cs b/DiscUtils/Geometry.cs
similarity index 100%
rename from DiscUtils/Core/Geometry.cs
rename to DiscUtils/Geometry.cs
diff --git a/DiscUtils/Core/GeometryCalculation.cs b/DiscUtils/GeometryCalculation.cs
similarity index 100%
rename from DiscUtils/Core/GeometryCalculation.cs
rename to DiscUtils/GeometryCalculation.cs
diff --git a/DiscUtils/Core/GeometryTranslation.cs b/DiscUtils/GeometryTranslation.cs
similarity index 100%
rename from DiscUtils/Core/GeometryTranslation.cs
rename to DiscUtils/GeometryTranslation.cs
diff --git a/DiscUtils/Core/IClusterBasedFileSystem.cs b/DiscUtils/IClusterBasedFileSystem.cs
similarity index 100%
rename from DiscUtils/Core/IClusterBasedFileSystem.cs
rename to DiscUtils/IClusterBasedFileSystem.cs
diff --git a/DiscUtils/Core/IDiagnosticTraceable.cs b/DiscUtils/IDiagnosticTraceable.cs
similarity index 100%
rename from DiscUtils/Core/IDiagnosticTraceable.cs
rename to DiscUtils/IDiagnosticTraceable.cs
diff --git a/DiscUtils/Core/IFileSystem.cs b/DiscUtils/IFileSystem.cs
similarity index 100%
rename from DiscUtils/Core/IFileSystem.cs
rename to DiscUtils/IFileSystem.cs
diff --git a/DiscUtils/Core/IUnixFileSystem.cs b/DiscUtils/IUnixFileSystem.cs
similarity index 100%
rename from DiscUtils/Core/IUnixFileSystem.cs
rename to DiscUtils/IUnixFileSystem.cs
diff --git a/DiscUtils/Core/IWindowsFileSystem.cs b/DiscUtils/IWindowsFileSystem.cs
similarity index 100%
rename from DiscUtils/Core/IWindowsFileSystem.cs
rename to DiscUtils/IWindowsFileSystem.cs
diff --git a/DiscUtils/Core/Internal/Crc32.cs b/DiscUtils/Internal/Crc32.cs
similarity index 100%
rename from DiscUtils/Core/Internal/Crc32.cs
rename to DiscUtils/Internal/Crc32.cs
diff --git a/DiscUtils/Core/Internal/Crc32Algorithm.cs b/DiscUtils/Internal/Crc32Algorithm.cs
similarity index 100%
rename from DiscUtils/Core/Internal/Crc32Algorithm.cs
rename to DiscUtils/Internal/Crc32Algorithm.cs
diff --git a/DiscUtils/Core/Internal/Crc32BigEndian.cs b/DiscUtils/Internal/Crc32BigEndian.cs
similarity index 100%
rename from DiscUtils/Core/Internal/Crc32BigEndian.cs
rename to DiscUtils/Internal/Crc32BigEndian.cs
diff --git a/DiscUtils/Core/Internal/Crc32LittleEndian.cs b/DiscUtils/Internal/Crc32LittleEndian.cs
similarity index 100%
rename from DiscUtils/Core/Internal/Crc32LittleEndian.cs
rename to DiscUtils/Internal/Crc32LittleEndian.cs
diff --git a/DiscUtils/Core/Internal/LocalFileLocator.cs b/DiscUtils/Internal/LocalFileLocator.cs
similarity index 100%
rename from DiscUtils/Core/Internal/LocalFileLocator.cs
rename to DiscUtils/Internal/LocalFileLocator.cs
diff --git a/DiscUtils/Core/Internal/LogicalVolumeFactory.cs b/DiscUtils/Internal/LogicalVolumeFactory.cs
similarity index 100%
rename from DiscUtils/Core/Internal/LogicalVolumeFactory.cs
rename to DiscUtils/Internal/LogicalVolumeFactory.cs
diff --git a/DiscUtils/Core/Internal/LogicalVolumeFactoryAttribute.cs b/DiscUtils/Internal/LogicalVolumeFactoryAttribute.cs
similarity index 100%
rename from DiscUtils/Core/Internal/LogicalVolumeFactoryAttribute.cs
rename to DiscUtils/Internal/LogicalVolumeFactoryAttribute.cs
diff --git a/DiscUtils/Core/Internal/ObjectCache.cs b/DiscUtils/Internal/ObjectCache.cs
similarity index 100%
rename from DiscUtils/Core/Internal/ObjectCache.cs
rename to DiscUtils/Internal/ObjectCache.cs
diff --git a/DiscUtils/Core/Internal/Utilities.cs b/DiscUtils/Internal/Utilities.cs
similarity index 100%
rename from DiscUtils/Core/Internal/Utilities.cs
rename to DiscUtils/Internal/Utilities.cs
diff --git a/DiscUtils/Core/Internal/VirtualDiskFactory.cs b/DiscUtils/Internal/VirtualDiskFactory.cs
similarity index 100%
rename from DiscUtils/Core/Internal/VirtualDiskFactory.cs
rename to DiscUtils/Internal/VirtualDiskFactory.cs
diff --git a/DiscUtils/Core/Internal/VirtualDiskFactoryAttribute.cs b/DiscUtils/Internal/VirtualDiskFactoryAttribute.cs
similarity index 100%
rename from DiscUtils/Core/Internal/VirtualDiskFactoryAttribute.cs
rename to DiscUtils/Internal/VirtualDiskFactoryAttribute.cs
diff --git a/DiscUtils/Core/Internal/VirtualDiskTransport.cs b/DiscUtils/Internal/VirtualDiskTransport.cs
similarity index 100%
rename from DiscUtils/Core/Internal/VirtualDiskTransport.cs
rename to DiscUtils/Internal/VirtualDiskTransport.cs
diff --git a/DiscUtils/Core/Internal/VirtualDiskTransportAttribute.cs b/DiscUtils/Internal/VirtualDiskTransportAttribute.cs
similarity index 100%
rename from DiscUtils/Core/Internal/VirtualDiskTransportAttribute.cs
rename to DiscUtils/Internal/VirtualDiskTransportAttribute.cs
diff --git a/DiscUtils/Core/InvalidFileSystemException.cs b/DiscUtils/InvalidFileSystemException.cs
similarity index 100%
rename from DiscUtils/Core/InvalidFileSystemException.cs
rename to DiscUtils/InvalidFileSystemException.cs
diff --git a/DiscUtils/Iso9660/BaseVolumeDescriptor.cs b/DiscUtils/Iso9660/BaseVolumeDescriptor.cs
index 3aeb519..bab65d6 100644
--- a/DiscUtils/Iso9660/BaseVolumeDescriptor.cs
+++ b/DiscUtils/Iso9660/BaseVolumeDescriptor.cs
@@ -32,14 +32,12 @@ namespace DiscUtils.Iso9660
public readonly string StandardIdentifier;
public readonly VolumeDescriptorType VolumeDescriptorType;
public readonly byte VolumeDescriptorVersion;
- private int SectorSize;
- public BaseVolumeDescriptor(VolumeDescriptorType type, byte version, int sectorSize)
+ public BaseVolumeDescriptor(VolumeDescriptorType type, byte version)
{
VolumeDescriptorType = type;
StandardIdentifier = "CD001";
VolumeDescriptorVersion = version;
- SectorSize = sectorSize;
}
public BaseVolumeDescriptor(byte[] src, int offset)
@@ -51,7 +49,7 @@ namespace DiscUtils.Iso9660
internal virtual void WriteTo(byte[] buffer, int offset)
{
- Array.Clear(buffer, offset, SectorSize);
+ Array.Clear(buffer, offset, IsoUtilities.SectorSize);
buffer[offset] = (byte)VolumeDescriptorType;
IsoUtilities.WriteAChars(buffer, offset + 1, 5, StandardIdentifier);
buffer[offset + 6] = VolumeDescriptorVersion;
diff --git a/DiscUtils/Iso9660/BootVolumeDescriptor.cs b/DiscUtils/Iso9660/BootVolumeDescriptor.cs
index d32908a..335711b 100644
--- a/DiscUtils/Iso9660/BootVolumeDescriptor.cs
+++ b/DiscUtils/Iso9660/BootVolumeDescriptor.cs
@@ -28,8 +28,8 @@ namespace DiscUtils.Iso9660
{
public const string ElToritoSystemIdentifier = "EL TORITO SPECIFICATION";
- public BootVolumeDescriptor(uint catalogSector, int sectorSize)
- : base(VolumeDescriptorType.Boot, 1, sectorSize)
+ public BootVolumeDescriptor(uint catalogSector)
+ : base(VolumeDescriptorType.Boot, 1)
{
CatalogSector = catalogSector;
}
diff --git a/DiscUtils/Iso9660/BootVolumeDescriptorRegion.cs b/DiscUtils/Iso9660/BootVolumeDescriptorRegion.cs
index 8e73eb0..f98d1b7 100644
--- a/DiscUtils/Iso9660/BootVolumeDescriptorRegion.cs
+++ b/DiscUtils/Iso9660/BootVolumeDescriptorRegion.cs
@@ -26,15 +26,15 @@ namespace DiscUtils.Iso9660
{
private readonly BootVolumeDescriptor _descriptor;
- public BootVolumeDescriptorRegion(BootVolumeDescriptor descriptor, long start, int sectorSize)
- : base(start, sectorSize)
+ public BootVolumeDescriptorRegion(BootVolumeDescriptor descriptor, long start)
+ : base(start)
{
_descriptor = descriptor;
}
protected override byte[] GetBlockData()
{
- byte[] buffer = new byte[Length];
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
_descriptor.WriteTo(buffer, 0);
return buffer;
}
diff --git a/DiscUtils/Iso9660/BuildDirectoryInfo.cs b/DiscUtils/Iso9660/BuildDirectoryInfo.cs
index 3212654..2fdc382 100644
--- a/DiscUtils/Iso9660/BuildDirectoryInfo.cs
+++ b/DiscUtils/Iso9660/BuildDirectoryInfo.cs
@@ -39,15 +39,13 @@ namespace DiscUtils.Iso9660
private readonly BuildDirectoryInfo _parent;
private List _sortedMembers;
- private int _sectorSize;
- internal BuildDirectoryInfo(string name, BuildDirectoryInfo parent, int sectorSize)
+ internal BuildDirectoryInfo(string name, BuildDirectoryInfo parent)
: base(name, MakeShortDirName(name, parent))
{
_parent = parent == null ? this : parent;
HierarchyDepth = parent == null ? 0 : parent.HierarchyDepth + 1;
_members = new Dictionary();
- _sectorSize = sectorSize;
}
internal int HierarchyDepth { get; }
@@ -89,16 +87,16 @@ namespace DiscUtils.Iso9660
// If this record would span a sector boundary, then the current sector is
// zero-padded, and the record goes at the start of the next sector.
- if (total % _sectorSize + recordSize > _sectorSize)
+ if (total % IsoUtilities.SectorSize + recordSize > IsoUtilities.SectorSize)
{
- long padLength = _sectorSize - total % _sectorSize;
+ long padLength = IsoUtilities.SectorSize - total % IsoUtilities.SectorSize;
total += padLength;
}
total += recordSize;
}
- return MathUtilities.RoundUp(total, _sectorSize);
+ return MathUtilities.RoundUp(total, IsoUtilities.SectorSize);
}
internal uint GetPathTableEntrySize(Encoding enc)
@@ -115,31 +113,31 @@ namespace DiscUtils.Iso9660
List sorted = GetSortedMembers();
// Two pseudo entries, effectively '.' and '..'
- pos += WriteMember(this, "\0", Encoding.ASCII, buffer, offset + pos, locationTable, enc, _sectorSize);
- pos += WriteMember(_parent, "\x01", Encoding.ASCII, buffer, offset + pos, locationTable, enc, _sectorSize);
+ pos += WriteMember(this, "\0", Encoding.ASCII, buffer, offset + pos, locationTable, enc);
+ pos += WriteMember(_parent, "\x01", Encoding.ASCII, buffer, offset + pos, locationTable, enc);
foreach (BuildDirectoryMember m in sorted)
{
uint recordSize = m.GetDirectoryRecordSize(enc);
- if (pos % _sectorSize + recordSize > _sectorSize)
+ if (pos % IsoUtilities.SectorSize + recordSize > IsoUtilities.SectorSize)
{
- int padLength = _sectorSize - pos % _sectorSize;
+ int padLength = IsoUtilities.SectorSize - pos % IsoUtilities.SectorSize;
Array.Clear(buffer, offset + pos, padLength);
pos += padLength;
}
- pos += WriteMember(m, null, enc, buffer, offset + pos, locationTable, enc, _sectorSize);
+ pos += WriteMember(m, null, enc, buffer, offset + pos, locationTable, enc);
}
// Ensure final padding data is zero'd
- int finalPadLength = MathUtilities.RoundUp(pos, _sectorSize) - pos;
+ int finalPadLength = MathUtilities.RoundUp(pos, IsoUtilities.SectorSize) - pos;
Array.Clear(buffer, offset + pos, finalPadLength);
return pos + finalPadLength;
}
- private static int WriteMember(BuildDirectoryMember m, string nameOverride, Encoding nameEnc, byte[] buffer, int offset, Dictionary locationTable, Encoding dataEnc, int sectorSize)
+ private static int WriteMember(BuildDirectoryMember m, string nameOverride, Encoding nameEnc, byte[] buffer, int offset, Dictionary locationTable, Encoding dataEnc)
{
DirectoryRecord dr = new DirectoryRecord();
dr.FileIdentifier = m.PickName(nameOverride, nameEnc);
diff --git a/DiscUtils/Iso9660/BuildParameters.cs b/DiscUtils/Iso9660/BuildParameters.cs
index 63f7658..1ac3892 100644
--- a/DiscUtils/Iso9660/BuildParameters.cs
+++ b/DiscUtils/Iso9660/BuildParameters.cs
@@ -28,11 +28,8 @@ namespace DiscUtils.Iso9660
{
VolumeIdentifier = string.Empty;
UseJoliet = true;
- SectorSize = 2048;
}
- public int SectorSize { get; set; }
-
public bool UseJoliet { get; set; }
public string VolumeIdentifier { get; set; }
diff --git a/DiscUtils/Iso9660/CDBuilder.cs b/DiscUtils/Iso9660/CDBuilder.cs
index 0d7a275..7042d1e 100644
--- a/DiscUtils/Iso9660/CDBuilder.cs
+++ b/DiscUtils/Iso9660/CDBuilder.cs
@@ -51,7 +51,6 @@ namespace DiscUtils.Iso9660
private readonly List _files;
private readonly BuildDirectoryInfo _rootDirectory;
- private readonly int _sectorSize;
///
/// Initializes a new instance of the CDBuilder class.
@@ -60,24 +59,7 @@ namespace DiscUtils.Iso9660
{
_files = new List();
_dirs = new List();
- _sectorSize = 2048;
- _rootDirectory = new BuildDirectoryInfo("\0", null, _sectorSize);
- _dirs.Add(_rootDirectory);
-
- _buildParams = new BuildParameters();
- _buildParams.UseJoliet = true;
- }
-
-
- ///
- /// Initializes a new instance of the CDBuilder class.
- ///
- public CDBuilder(int sectorSize)
- {
- _files = new List();
- _dirs = new List();
- _sectorSize = sectorSize;
- _rootDirectory = new BuildDirectoryInfo("\0", null, _sectorSize);
+ _rootDirectory = new BuildDirectoryInfo("\0", null);
_dirs.Add(_rootDirectory);
_buildParams = new BuildParameters();
@@ -270,10 +252,10 @@ namespace DiscUtils.Iso9660
Dictionary supplementaryLocationTable =
new Dictionary();
- long focus = DiskStart + 3 * _buildParams.SectorSize; // Primary, Supplementary, End (fixed at end...)
+ long focus = DiskStart + 3 * IsoUtilities.SectorSize; // Primary, Supplementary, End (fixed at end...)
if (_bootEntry != null)
{
- focus += _buildParams.SectorSize;
+ focus += IsoUtilities.SectorSize;
}
// ####################################################################
@@ -283,21 +265,21 @@ namespace DiscUtils.Iso9660
if (_bootEntry != null)
{
long bootImagePos = focus;
- Stream realBootImage = PatchBootImage(_bootImage, (uint)(DiskStart / _buildParams.SectorSize),
- (uint)(bootImagePos / _buildParams.SectorSize));
+ Stream realBootImage = PatchBootImage(_bootImage, (uint)(DiskStart / IsoUtilities.SectorSize),
+ (uint)(bootImagePos / IsoUtilities.SectorSize));
BuilderStreamExtent bootImageExtent = new BuilderStreamExtent(focus, realBootImage);
fixedRegions.Add(bootImageExtent);
- focus += MathUtilities.RoundUp(bootImageExtent.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(bootImageExtent.Length, IsoUtilities.SectorSize);
bootCatalogPos = focus;
- byte[] bootCatalog = new byte[_buildParams.SectorSize];
+ byte[] bootCatalog = new byte[IsoUtilities.SectorSize];
BootValidationEntry bve = new BootValidationEntry();
bve.WriteTo(bootCatalog, 0x00);
- _bootEntry.ImageStart = (uint)MathUtilities.Ceil(bootImagePos, _buildParams.SectorSize);
+ _bootEntry.ImageStart = (uint)MathUtilities.Ceil(bootImagePos, IsoUtilities.SectorSize);
_bootEntry.SectorCount = (ushort)MathUtilities.Ceil(_bootImage.Length, Sizes.Sector);
_bootEntry.WriteTo(bootCatalog, 0x20);
fixedRegions.Add(new BuilderBufferExtent(bootCatalogPos, bootCatalog));
- focus += _buildParams.SectorSize;
+ focus += IsoUtilities.SectorSize;
}
// ####################################################################
@@ -307,8 +289,8 @@ namespace DiscUtils.Iso9660
// Find end of the file data, fixing the files in place as we go
foreach (BuildFileInfo fi in _files)
{
- primaryLocationTable.Add(fi, (uint)(focus / _buildParams.SectorSize));
- supplementaryLocationTable.Add(fi, (uint)(focus / _buildParams.SectorSize));
+ primaryLocationTable.Add(fi, (uint)(focus / IsoUtilities.SectorSize));
+ supplementaryLocationTable.Add(fi, (uint)(focus / IsoUtilities.SectorSize));
FileExtent extent = new FileExtent(fi, focus);
// Only remember files of non-zero length (otherwise we'll stomp on a valid file)
@@ -317,7 +299,7 @@ namespace DiscUtils.Iso9660
fixedRegions.Add(extent);
}
- focus += MathUtilities.RoundUp(extent.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(extent.Length, IsoUtilities.SectorSize);
}
// ####################################################################
@@ -332,20 +314,20 @@ namespace DiscUtils.Iso9660
long startOfFirstDirData = focus;
foreach (BuildDirectoryInfo di in _dirs)
{
- primaryLocationTable.Add(di, (uint)(focus / _buildParams.SectorSize));
+ primaryLocationTable.Add(di, (uint)(focus / IsoUtilities.SectorSize));
DirectoryExtent extent = new DirectoryExtent(di, primaryLocationTable, Encoding.ASCII, focus);
fixedRegions.Add(extent);
- focus += MathUtilities.RoundUp(extent.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(extent.Length, IsoUtilities.SectorSize);
}
// Find end of the second directory table, fixing supplementary directories in place.
long startOfSecondDirData = focus;
foreach (BuildDirectoryInfo di in _dirs)
{
- supplementaryLocationTable.Add(di, (uint)(focus / _buildParams.SectorSize));
+ supplementaryLocationTable.Add(di, (uint)(focus / IsoUtilities.SectorSize));
DirectoryExtent extent = new DirectoryExtent(di, supplementaryLocationTable, suppEncoding, focus);
fixedRegions.Add(extent);
- focus += MathUtilities.RoundUp(extent.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(extent.Length, IsoUtilities.SectorSize);
}
// ####################################################################
@@ -362,24 +344,24 @@ namespace DiscUtils.Iso9660
long startOfFirstPathTable = focus;
PathTable pathTable = new PathTable(false, Encoding.ASCII, _dirs, primaryLocationTable, focus);
fixedRegions.Add(pathTable);
- focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(pathTable.Length, IsoUtilities.SectorSize);
long primaryPathTableLength = pathTable.Length;
long startOfSecondPathTable = focus;
pathTable = new PathTable(true, Encoding.ASCII, _dirs, primaryLocationTable, focus);
fixedRegions.Add(pathTable);
- focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(pathTable.Length, IsoUtilities.SectorSize);
long startOfThirdPathTable = focus;
pathTable = new PathTable(false, suppEncoding, _dirs, supplementaryLocationTable, focus);
fixedRegions.Add(pathTable);
- focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(pathTable.Length, IsoUtilities.SectorSize);
long supplementaryPathTableLength = pathTable.Length;
long startOfFourthPathTable = focus;
pathTable = new PathTable(true, suppEncoding, _dirs, supplementaryLocationTable, focus);
fixedRegions.Add(pathTable);
- focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+ focus += MathUtilities.RoundUp(pathTable.Length, IsoUtilities.SectorSize);
// Find the end of the disk
totalLength = focus;
@@ -390,45 +372,43 @@ namespace DiscUtils.Iso9660
int regionIdx = 0;
focus = DiskStart;
PrimaryVolumeDescriptor pvDesc = new PrimaryVolumeDescriptor(
- (uint)(totalLength / _buildParams.SectorSize), // VolumeSpaceSize
+ (uint)(totalLength / IsoUtilities.SectorSize), // VolumeSpaceSize
(uint)primaryPathTableLength, // PathTableSize
- (uint)(startOfFirstPathTable / _buildParams.SectorSize), // TypeLPathTableLocation
- (uint)(startOfSecondPathTable / _buildParams.SectorSize), // TypeMPathTableLocation
- (uint)(startOfFirstDirData / _buildParams.SectorSize), // RootDirectory.LocationOfExtent
+ (uint)(startOfFirstPathTable / IsoUtilities.SectorSize), // TypeLPathTableLocation
+ (uint)(startOfSecondPathTable / IsoUtilities.SectorSize), // TypeMPathTableLocation
+ (uint)(startOfFirstDirData / IsoUtilities.SectorSize), // RootDirectory.LocationOfExtent
(uint)_rootDirectory.GetDataSize(Encoding.ASCII), // RootDirectory.DataLength
- buildTime,
- _sectorSize);
+ buildTime);
pvDesc.VolumeIdentifier = _buildParams.VolumeIdentifier;
- PrimaryVolumeDescriptorRegion pvdr = new PrimaryVolumeDescriptorRegion(pvDesc, focus, _sectorSize);
+ PrimaryVolumeDescriptorRegion pvdr = new PrimaryVolumeDescriptorRegion(pvDesc, focus);
fixedRegions.Insert(regionIdx++, pvdr);
- focus += _buildParams.SectorSize;
+ focus += IsoUtilities.SectorSize;
if (_bootEntry != null)
{
BootVolumeDescriptor bvDesc = new BootVolumeDescriptor(
- (uint)(bootCatalogPos / _buildParams.SectorSize), _buildParams.SectorSize);
- BootVolumeDescriptorRegion bvdr = new BootVolumeDescriptorRegion(bvDesc, focus, _buildParams.SectorSize);
+ (uint)(bootCatalogPos / IsoUtilities.SectorSize));
+ BootVolumeDescriptorRegion bvdr = new BootVolumeDescriptorRegion(bvDesc, focus);
fixedRegions.Insert(regionIdx++, bvdr);
- focus += _buildParams.SectorSize;
+ focus += IsoUtilities.SectorSize;
}
SupplementaryVolumeDescriptor svDesc = new SupplementaryVolumeDescriptor(
- (uint)(totalLength / _buildParams.SectorSize), // VolumeSpaceSize
+ (uint)(totalLength / IsoUtilities.SectorSize), // VolumeSpaceSize
(uint)supplementaryPathTableLength, // PathTableSize
- (uint)(startOfThirdPathTable / _buildParams.SectorSize), // TypeLPathTableLocation
- (uint)(startOfFourthPathTable / _buildParams.SectorSize), // TypeMPathTableLocation
- (uint)(startOfSecondDirData / _buildParams.SectorSize), // RootDirectory.LocationOfExtent
+ (uint)(startOfThirdPathTable / IsoUtilities.SectorSize), // TypeLPathTableLocation
+ (uint)(startOfFourthPathTable / IsoUtilities.SectorSize), // TypeMPathTableLocation
+ (uint)(startOfSecondDirData / IsoUtilities.SectorSize), // RootDirectory.LocationOfExtent
(uint)_rootDirectory.GetDataSize(suppEncoding), // RootDirectory.DataLength
buildTime,
- suppEncoding,
- _sectorSize);
+ suppEncoding);
svDesc.VolumeIdentifier = _buildParams.VolumeIdentifier;
- SupplementaryVolumeDescriptorRegion svdr = new SupplementaryVolumeDescriptorRegion(svDesc, focus, _sectorSize);
+ SupplementaryVolumeDescriptorRegion svdr = new SupplementaryVolumeDescriptorRegion(svDesc, focus);
fixedRegions.Insert(regionIdx++, svdr);
- focus += _buildParams.SectorSize;
+ focus += IsoUtilities.SectorSize;
- VolumeDescriptorSetTerminator evDesc = new VolumeDescriptorSetTerminator(_sectorSize);
- VolumeDescriptorSetTerminatorRegion evdr = new VolumeDescriptorSetTerminatorRegion(evDesc, focus, _sectorSize);
+ VolumeDescriptorSetTerminator evDesc = new VolumeDescriptorSetTerminator();
+ VolumeDescriptorSetTerminatorRegion evdr = new VolumeDescriptorSetTerminatorRegion(evDesc, focus);
fixedRegions.Insert(regionIdx++, evdr);
return fixedRegions;
@@ -491,7 +471,7 @@ namespace DiscUtils.Iso9660
if (createMissing)
{
// This directory doesn't exist, create it...
- BuildDirectoryInfo di = new BuildDirectoryInfo(path[i], focus, _sectorSize);
+ BuildDirectoryInfo di = new BuildDirectoryInfo(path[i], focus);
focus.Add(di);
_dirs.Add(di);
focus = di;
diff --git a/DiscUtils/Iso9660/CDReader.cs b/DiscUtils/Iso9660/CDReader.cs
index 82bfe41..8a544ca 100644
--- a/DiscUtils/Iso9660/CDReader.cs
+++ b/DiscUtils/Iso9660/CDReader.cs
@@ -37,9 +37,7 @@ namespace DiscUtils.Iso9660
/// The stream to read the ISO image from.
/// Whether to read Joliet extensions.
public CDReader(Stream data, bool joliet)
- : base(new VfsCDReader(data, joliet, false, 2048))
- {
- }
+ : base(new VfsCDReader(data, joliet, false)) {}
///
/// Initializes a new instance of the CDReader class.
@@ -48,27 +46,7 @@ namespace DiscUtils.Iso9660
/// Whether to read Joliet extensions.
/// Hides version numbers (e.g. ";1") from the end of files.
public CDReader(Stream data, bool joliet, bool hideVersions)
- : base(new VfsCDReader(data, joliet, hideVersions, 2048)) { }
-
-
- ///
- /// Initializes a new instance of the CDReader class.
- ///
- /// The stream to read the ISO image from.
- /// Whether to read Joliet extensions.
- /// The size of a sector
- public CDReader(Stream data, bool joliet, int sectorSize)
- : base(new VfsCDReader(data, joliet, false, sectorSize)) {
- }
-
- ///
- /// Initializes a new instance of the CDReader class.
- ///
- /// The stream to read the ISO image from.
- /// Whether to read Joliet extensions.
- /// Hides version numbers (e.g. ";1") from the end of files.
- public CDReader(Stream data, bool joliet, bool hideVersions, int sectorSize)
- : base(new VfsCDReader(data, joliet, hideVersions, sectorSize)) {}
+ : base(new VfsCDReader(data, joliet, hideVersions)) {}
///
/// Gets which of the Iso9660 variants is being used.
@@ -196,18 +174,18 @@ namespace DiscUtils.Iso9660
///
/// The stream to inspect.
/// true if the stream contains an ISO file system, else false.
- public static bool Detect(Stream data, int sectorSize)
+ public static bool Detect(Stream data)
{
- byte[] buffer = new byte[sectorSize];
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
- if (data.Length < 0x8000 + sectorSize)
+ if (data.Length < 0x8000 + IsoUtilities.SectorSize)
{
return false;
}
data.Position = 0x8000;
- int numRead = StreamUtilities.ReadMaximum(data, buffer, 0, sectorSize);
- if (numRead != sectorSize)
+ int numRead = StreamUtilities.ReadMaximum(data, buffer, 0, IsoUtilities.SectorSize);
+ if (numRead != IsoUtilities.SectorSize)
{
return false;
}
diff --git a/DiscUtils/Iso9660/CommonVolumeDescriptor.cs b/DiscUtils/Iso9660/CommonVolumeDescriptor.cs
index f4a4e0a..7ef3bf6 100644
--- a/DiscUtils/Iso9660/CommonVolumeDescriptor.cs
+++ b/DiscUtils/Iso9660/CommonVolumeDescriptor.cs
@@ -97,9 +97,8 @@ namespace DiscUtils.Iso9660
uint rootDirExtentLocation,
uint rootDirDataLength,
DateTime buildTime,
- Encoding enc,
- int sectorSize)
- : base(type, version, sectorSize)
+ Encoding enc)
+ : base(type, version)
{
CharacterEncoding = enc;
@@ -108,7 +107,7 @@ namespace DiscUtils.Iso9660
VolumeSpaceSize = volumeSpaceSize;
VolumeSetSize = 1;
VolumeSequenceNumber = 1;
- LogicalBlockSize = (ushort)sectorSize;
+ LogicalBlockSize = IsoUtilities.SectorSize;
PathTableSize = pathTableSize;
TypeLPathTableLocation = typeLPathTableLocation;
////OptionalTypeLPathTableLocation = 0;
diff --git a/DiscUtils/Iso9660/DiscUtils.Iso9660.csproj b/DiscUtils/Iso9660/DiscUtils.Iso9660.csproj
deleted file mode 100644
index e9968cf..0000000
--- a/DiscUtils/Iso9660/DiscUtils.Iso9660.csproj
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- DiscUtils Iso9660
- Kenneth Bell;LordMike
- DiscUtils;Optical;Iso9660
-
-
-
-
-
-
-
diff --git a/DiscUtils/Iso9660/ExtentStream.cs b/DiscUtils/Iso9660/ExtentStream.cs
index 13ec3c2..e7d5aa4 100644
--- a/DiscUtils/Iso9660/ExtentStream.cs
+++ b/DiscUtils/Iso9660/ExtentStream.cs
@@ -35,17 +35,15 @@ namespace DiscUtils.Iso9660
private long _position;
private readonly uint _startBlock;
- private readonly int _sectorSize;
public ExtentStream(Stream isoStream, uint startBlock, uint dataLength, byte fileUnitSize,
- byte interleaveGapSize, int sectorSize)
+ byte interleaveGapSize)
{
_isoStream = isoStream;
_startBlock = startBlock;
_dataLength = dataLength;
_fileUnitSize = fileUnitSize;
_interleaveGapSize = interleaveGapSize;
- _sectorSize = sectorSize;
if (_fileUnitSize != 0 || _interleaveGapSize != 0)
{
@@ -90,7 +88,7 @@ namespace DiscUtils.Iso9660
int toRead = (int)Math.Min((uint)count, _dataLength - _position);
- _isoStream.Position = _position + _startBlock * (long)_sectorSize;
+ _isoStream.Position = _position + _startBlock * (long)IsoUtilities.SectorSize;
int numRead = _isoStream.Read(buffer, offset, toRead);
_position += numRead;
return numRead;
diff --git a/DiscUtils/Iso9660/File.cs b/DiscUtils/Iso9660/File.cs
index 81bbad4..0ca134a 100644
--- a/DiscUtils/Iso9660/File.cs
+++ b/DiscUtils/Iso9660/File.cs
@@ -111,7 +111,7 @@ namespace DiscUtils.Iso9660
get
{
ExtentStream es = new ExtentStream(_context.DataStream, _dirEntry.Record.LocationOfExtent,
- _dirEntry.Record.DataLength, _dirEntry.Record.FileUnitSize, _dirEntry.Record.InterleaveGapSize, _context.SectorSize);
+ _dirEntry.Record.DataLength, _dirEntry.Record.FileUnitSize, _dirEntry.Record.InterleaveGapSize);
return new StreamBuffer(es, Ownership.Dispose);
}
}
diff --git a/DiscUtils/Iso9660/IsoContext.cs b/DiscUtils/Iso9660/IsoContext.cs
index 5232f62..5ff6396 100644
--- a/DiscUtils/Iso9660/IsoContext.cs
+++ b/DiscUtils/Iso9660/IsoContext.cs
@@ -28,19 +28,12 @@ namespace DiscUtils.Iso9660
{
internal class IsoContext : VfsContext
{
- public IsoContext(int sectorSize)
- {
- SectorSize = sectorSize;
- }
-
public Stream DataStream { get; set; }
public string RockRidgeIdentifier { get; set; }
public bool SuspDetected { get; set; }
- public int SectorSize { get; set; }
-
public List SuspExtensions { get; set; }
public int SuspSkipBytes { get; set; }
diff --git a/DiscUtils/Iso9660/IsoUtilities.cs b/DiscUtils/Iso9660/IsoUtilities.cs
index 4327450..ac6e552 100644
--- a/DiscUtils/Iso9660/IsoUtilities.cs
+++ b/DiscUtils/Iso9660/IsoUtilities.cs
@@ -30,7 +30,7 @@ namespace DiscUtils.Iso9660
{
internal static class IsoUtilities
{
- //public const int SectorSize = 2048;
+ public const int SectorSize = 2048;
public static uint ToUInt32FromBoth(byte[] data, int offset)
{
diff --git a/DiscUtils/Iso9660/PrimaryVolumeDescriptor.cs b/DiscUtils/Iso9660/PrimaryVolumeDescriptor.cs
index 565c2ea..1d3199d 100644
--- a/DiscUtils/Iso9660/PrimaryVolumeDescriptor.cs
+++ b/DiscUtils/Iso9660/PrimaryVolumeDescriptor.cs
@@ -38,11 +38,10 @@ namespace DiscUtils.Iso9660
uint typeMPathTableLocation,
uint rootDirExtentLocation,
uint rootDirDataLength,
- DateTime buildTime,
- int sectorSize)
+ DateTime buildTime)
: base(
VolumeDescriptorType.Primary, 1, volumeSpaceSize, pathTableSize, typeLPathTableLocation,
- typeMPathTableLocation, rootDirExtentLocation, rootDirDataLength, buildTime, Encoding.ASCII, sectorSize) {}
+ typeMPathTableLocation, rootDirExtentLocation, rootDirDataLength, buildTime, Encoding.ASCII) {}
internal override void WriteTo(byte[] buffer, int offset)
{
diff --git a/DiscUtils/Iso9660/PrimaryVolumeDescriptorRegion.cs b/DiscUtils/Iso9660/PrimaryVolumeDescriptorRegion.cs
index dcc2125..0f0ae5d 100644
--- a/DiscUtils/Iso9660/PrimaryVolumeDescriptorRegion.cs
+++ b/DiscUtils/Iso9660/PrimaryVolumeDescriptorRegion.cs
@@ -26,15 +26,15 @@ namespace DiscUtils.Iso9660
{
private readonly PrimaryVolumeDescriptor _descriptor;
- public PrimaryVolumeDescriptorRegion(PrimaryVolumeDescriptor descriptor, long start, int sectorSize)
- : base(start, sectorSize)
+ public PrimaryVolumeDescriptorRegion(PrimaryVolumeDescriptor descriptor, long start)
+ : base(start)
{
_descriptor = descriptor;
}
protected override byte[] GetBlockData()
{
- byte[] buffer = new byte[Length];
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
_descriptor.WriteTo(buffer, 0);
return buffer;
}
diff --git a/DiscUtils/Iso9660/ReaderDirectory.cs b/DiscUtils/Iso9660/ReaderDirectory.cs
index 003436b..d88d312 100644
--- a/DiscUtils/Iso9660/ReaderDirectory.cs
+++ b/DiscUtils/Iso9660/ReaderDirectory.cs
@@ -37,8 +37,8 @@ namespace DiscUtils.Iso9660
public ReaderDirectory(IsoContext context, ReaderDirEntry dirEntry)
: base(context, dirEntry)
{
- byte[] buffer = new byte[context.SectorSize];
- Stream extent = new ExtentStream(_context.DataStream, dirEntry.Record.LocationOfExtent, uint.MaxValue, 0, 0, context.SectorSize);
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
+ Stream extent = new ExtentStream(_context.DataStream, dirEntry.Record.LocationOfExtent, uint.MaxValue, 0, 0);
_records = new List();
@@ -48,8 +48,6 @@ namespace DiscUtils.Iso9660
{
int bytesRead = (int)Math.Min(buffer.Length, totalLength - totalRead);
- extent.Seek(24, SeekOrigin.Current);
-
StreamUtilities.ReadExact(extent, buffer, 0, bytesRead);
totalRead += (uint)bytesRead;
diff --git a/DiscUtils/Iso9660/SupplementaryVolumeDescriptor.cs b/DiscUtils/Iso9660/SupplementaryVolumeDescriptor.cs
index bb7c6ba..dfe5ebb 100644
--- a/DiscUtils/Iso9660/SupplementaryVolumeDescriptor.cs
+++ b/DiscUtils/Iso9660/SupplementaryVolumeDescriptor.cs
@@ -39,11 +39,10 @@ namespace DiscUtils.Iso9660
uint rootDirExtentLocation,
uint rootDirDataLength,
DateTime buildTime,
- Encoding enc,
- int sectorSize)
+ Encoding enc)
: base(
VolumeDescriptorType.Supplementary, 1, volumeSpaceSize, pathTableSize, typeLPathTableLocation,
- typeMPathTableLocation, rootDirExtentLocation, rootDirDataLength, buildTime, enc, sectorSize) {}
+ typeMPathTableLocation, rootDirExtentLocation, rootDirDataLength, buildTime, enc) {}
internal override void WriteTo(byte[] buffer, int offset)
{
diff --git a/DiscUtils/Iso9660/SupplementaryVolumeDescriptorRegion.cs b/DiscUtils/Iso9660/SupplementaryVolumeDescriptorRegion.cs
index 07e756a..317ea7f 100644
--- a/DiscUtils/Iso9660/SupplementaryVolumeDescriptorRegion.cs
+++ b/DiscUtils/Iso9660/SupplementaryVolumeDescriptorRegion.cs
@@ -26,15 +26,15 @@ namespace DiscUtils.Iso9660
{
private readonly SupplementaryVolumeDescriptor _descriptor;
- public SupplementaryVolumeDescriptorRegion(SupplementaryVolumeDescriptor descriptor, long start, int sectorSize)
- : base(start, sectorSize)
+ public SupplementaryVolumeDescriptorRegion(SupplementaryVolumeDescriptor descriptor, long start)
+ : base(start)
{
_descriptor = descriptor;
}
protected override byte[] GetBlockData()
{
- byte[] buffer = new byte[Length];
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
_descriptor.WriteTo(buffer, 0);
return buffer;
}
diff --git a/DiscUtils/Iso9660/VfsCDReader.cs b/DiscUtils/Iso9660/VfsCDReader.cs
index f9207ed..9c628f2 100644
--- a/DiscUtils/Iso9660/VfsCDReader.cs
+++ b/DiscUtils/Iso9660/VfsCDReader.cs
@@ -40,7 +40,6 @@ namespace DiscUtils.Iso9660
private readonly Stream _data;
private readonly bool _hideVersions;
- protected readonly int _sectorSize;
///
/// Initializes a new instance of the VfsCDReader class.
@@ -48,9 +47,8 @@ namespace DiscUtils.Iso9660
/// The stream to read the ISO image from.
/// Whether to read Joliet extensions.
/// Hides version numbers (e.g. ";1") from the end of files.
- public VfsCDReader(Stream data, bool joliet, bool hideVersions, int sectorSize)
- : this(data, joliet ? DefaultVariantsWithJoliet : DefaultVariantsNoJoliet, hideVersions, sectorSize) {
- }
+ public VfsCDReader(Stream data, bool joliet, bool hideVersions)
+ : this(data, joliet ? DefaultVariantsWithJoliet : DefaultVariantsNoJoliet, hideVersions) {}
///
/// Initializes a new instance of the VfsCDReader class.
@@ -70,16 +68,15 @@ namespace DiscUtils.Iso9660
/// The Iso9660 variant should normally be specified as the final entry in the list. Placing it earlier
/// in the list will effectively mask later items and not including it may prevent some ISOs from being read.
///
- public VfsCDReader(Stream data, Iso9660Variant[] variantPriorities, bool hideVersions, int sectorSize)
+ public VfsCDReader(Stream data, Iso9660Variant[] variantPriorities, bool hideVersions)
: base(new DiscFileSystemOptions())
{
_data = data;
- _sectorSize = sectorSize;
_hideVersions = hideVersions;
- long vdpos = _sectorSize * 16; // Skip lead-in
+ long vdpos = 0x8000; // Skip lead-in
- byte[] buffer = new byte[_sectorSize];
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
long pvdPos = 0;
long svdPos = 0;
@@ -88,15 +85,13 @@ namespace DiscUtils.Iso9660
do
{
data.Position = vdpos;
- int numRead = data.Read(buffer, 0, _sectorSize);
- if (numRead != _sectorSize)
+ int numRead = data.Read(buffer, 0, IsoUtilities.SectorSize);
+ if (numRead != IsoUtilities.SectorSize)
{
break;
}
- var offset = 24;
-
- bvd = new BaseVolumeDescriptor(buffer, offset);
+ bvd = new BaseVolumeDescriptor(buffer, 0);
if (bvd.StandardIdentifier != BaseVolumeDescriptor.Iso9660StandardIdentifier)
{
@@ -106,7 +101,7 @@ namespace DiscUtils.Iso9660
switch (bvd.VolumeDescriptorType)
{
case VolumeDescriptorType.Boot:
- _bootVolDesc = new BootVolumeDescriptor(buffer, offset);
+ _bootVolDesc = new BootVolumeDescriptor(buffer, 0);
if (_bootVolDesc.SystemId != BootVolumeDescriptor.ElToritoSystemIdentifier)
{
_bootVolDesc = null;
@@ -128,7 +123,7 @@ namespace DiscUtils.Iso9660
break;
}
- vdpos += _sectorSize;
+ vdpos += IsoUtilities.SectorSize;
} while (bvd.VolumeDescriptorType != VolumeDescriptorType.SetTerminator);
ActiveVariant = Iso9660Variant.None;
@@ -140,10 +135,10 @@ namespace DiscUtils.Iso9660
if (svdPos != 0)
{
data.Position = svdPos;
- data.Read(buffer, 0, _sectorSize);
+ data.Read(buffer, 0, IsoUtilities.SectorSize);
SupplementaryVolumeDescriptor volDesc = new SupplementaryVolumeDescriptor(buffer, 0);
- Context = new IsoContext(_sectorSize) { VolumeDescriptor = volDesc, DataStream = _data };
+ Context = new IsoContext { VolumeDescriptor = volDesc, DataStream = _data };
RootDirectory = new ReaderDirectory(Context,
new ReaderDirEntry(Context, volDesc.RootDirectory));
ActiveVariant = Iso9660Variant.Iso9660;
@@ -155,13 +150,11 @@ namespace DiscUtils.Iso9660
case Iso9660Variant.Iso9660:
if (pvdPos != 0)
{
- data.Position = pvdPos + 24;
- data.Read(buffer, 0, _sectorSize);
+ data.Position = pvdPos;
+ data.Read(buffer, 0, IsoUtilities.SectorSize);
PrimaryVolumeDescriptor volDesc = new PrimaryVolumeDescriptor(buffer, 0);
- volDesc.LogicalBlockSize = 2352;
-
- IsoContext context = new IsoContext(_sectorSize) { VolumeDescriptor = volDesc, DataStream = _data };
+ IsoContext context = new IsoContext { VolumeDescriptor = volDesc, DataStream = _data };
DirectoryRecord rootSelfRecord = ReadRootSelfRecord(context);
InitializeSusp(context, rootSelfRecord);
@@ -215,7 +208,7 @@ namespace DiscUtils.Iso9660
BootInitialEntry initialEntry = GetBootInitialEntry();
if (initialEntry != null)
{
- return initialEntry.ImageStart * _sectorSize;
+ return initialEntry.ImageStart * IsoUtilities.SectorSize;
}
return 0;
}
@@ -273,7 +266,7 @@ namespace DiscUtils.Iso9660
public long ClusterSize
{
- get { return _sectorSize; }
+ get { return IsoUtilities.SectorSize; }
}
public long TotalClusters
@@ -331,7 +324,7 @@ namespace DiscUtils.Iso9660
return new[]
{
new Range(entry.Record.LocationOfExtent,
- MathUtilities.Ceil(entry.Record.DataLength, _sectorSize))
+ MathUtilities.Ceil(entry.Record.DataLength, IsoUtilities.SectorSize))
};
}
@@ -349,7 +342,7 @@ namespace DiscUtils.Iso9660
}
return new[]
- { new StreamExtent(entry.Record.LocationOfExtent * _sectorSize, entry.Record.DataLength) };
+ { new StreamExtent(entry.Record.LocationOfExtent * IsoUtilities.SectorSize, entry.Record.DataLength) };
}
public ClusterMap BuildClusterMap()
@@ -386,7 +379,7 @@ namespace DiscUtils.Iso9660
throw new NotSupportedException("Non-contiguous extents not supported");
}
- long clusters = MathUtilities.Ceil(entry.Record.DataLength, _sectorSize);
+ long clusters = MathUtilities.Ceil(entry.Record.DataLength, IsoUtilities.SectorSize);
for (long i = 0; i < clusters; ++i)
{
clusterToRole[i + entry.Record.LocationOfExtent] = ClusterRoles.DataFile;
@@ -408,7 +401,7 @@ namespace DiscUtils.Iso9660
BootInitialEntry initialEntry = GetBootInitialEntry();
if (initialEntry != null)
{
- return new SubStream(_data, initialEntry.ImageStart * _sectorSize,
+ return new SubStream(_data, initialEntry.ImageStart * IsoUtilities.SectorSize,
initialEntry.SectorCount * Sizes.Sector);
}
throw new InvalidOperationException("No valid boot image");
@@ -491,7 +484,7 @@ namespace DiscUtils.Iso9660
private static DirectoryRecord ReadRootSelfRecord(IsoContext context)
{
context.DataStream.Position = context.VolumeDescriptor.RootDirectory.LocationOfExtent *
- context.VolumeDescriptor.LogicalBlockSize + 24;
+ context.VolumeDescriptor.LogicalBlockSize;
byte[] firstSector = StreamUtilities.ReadExact(context.DataStream, context.VolumeDescriptor.LogicalBlockSize);
DirectoryRecord rootSelfRecord;
@@ -520,8 +513,8 @@ namespace DiscUtils.Iso9660
{
if (_bootCatalog == null && _bootVolDesc != null)
{
- _data.Position = _bootVolDesc.CatalogSector * _sectorSize;
- _bootCatalog = StreamUtilities.ReadExact(_data, _sectorSize);
+ _data.Position = _bootVolDesc.CatalogSector * IsoUtilities.SectorSize;
+ _bootCatalog = StreamUtilities.ReadExact(_data, IsoUtilities.SectorSize);
}
return _bootCatalog;
diff --git a/DiscUtils/Iso9660/VolumeDescriptorDiskRegion.cs b/DiscUtils/Iso9660/VolumeDescriptorDiskRegion.cs
index ad89652..11546f6 100644
--- a/DiscUtils/Iso9660/VolumeDescriptorDiskRegion.cs
+++ b/DiscUtils/Iso9660/VolumeDescriptorDiskRegion.cs
@@ -29,8 +29,8 @@ namespace DiscUtils.Iso9660
{
private byte[] _readCache;
- public VolumeDescriptorDiskRegion(long start, int sectorSize)
- : base(start, sectorSize) {}
+ public VolumeDescriptorDiskRegion(long start)
+ : base(start, IsoUtilities.SectorSize) {}
public override void Dispose() {}
diff --git a/DiscUtils/Iso9660/VolumeDescriptorSetTerminator.cs b/DiscUtils/Iso9660/VolumeDescriptorSetTerminator.cs
index fb247d2..f7035ff 100644
--- a/DiscUtils/Iso9660/VolumeDescriptorSetTerminator.cs
+++ b/DiscUtils/Iso9660/VolumeDescriptorSetTerminator.cs
@@ -24,7 +24,7 @@ namespace DiscUtils.Iso9660
{
internal class VolumeDescriptorSetTerminator : BaseVolumeDescriptor
{
- public VolumeDescriptorSetTerminator(int sectorSize)
- : base(VolumeDescriptorType.SetTerminator, 1, sectorSize) {}
+ public VolumeDescriptorSetTerminator()
+ : base(VolumeDescriptorType.SetTerminator, 1) {}
}
}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660/VolumeDescriptorSetTerminatorRegion.cs b/DiscUtils/Iso9660/VolumeDescriptorSetTerminatorRegion.cs
index 743bfc4..f1e98d6 100644
--- a/DiscUtils/Iso9660/VolumeDescriptorSetTerminatorRegion.cs
+++ b/DiscUtils/Iso9660/VolumeDescriptorSetTerminatorRegion.cs
@@ -26,15 +26,15 @@ namespace DiscUtils.Iso9660
{
private readonly VolumeDescriptorSetTerminator _descriptor;
- public VolumeDescriptorSetTerminatorRegion(VolumeDescriptorSetTerminator descriptor, long start, int sectorSize)
- : base(start, sectorSize)
+ public VolumeDescriptorSetTerminatorRegion(VolumeDescriptorSetTerminator descriptor, long start)
+ : base(start)
{
_descriptor = descriptor;
}
protected override byte[] GetBlockData()
{
- byte[] buffer = new byte[Length];
+ byte[] buffer = new byte[IsoUtilities.SectorSize];
_descriptor.WriteTo(buffer, 0);
return buffer;
}
diff --git a/DiscUtils/Iso9660Ps1/BaseVolumeDescriptor.cs b/DiscUtils/Iso9660Ps1/BaseVolumeDescriptor.cs
new file mode 100644
index 0000000..f1f4feb
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BaseVolumeDescriptor.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class BaseVolumeDescriptor
+ {
+ public const string Iso9660StandardIdentifier = "CD001";
+
+ public readonly string StandardIdentifier;
+ public readonly VolumeDescriptorType VolumeDescriptorType;
+ public readonly byte VolumeDescriptorVersion;
+ private int SectorSize;
+
+ public BaseVolumeDescriptor(VolumeDescriptorType type, byte version, int sectorSize)
+ {
+ VolumeDescriptorType = type;
+ StandardIdentifier = "CD001";
+ VolumeDescriptorVersion = version;
+ SectorSize = sectorSize;
+ }
+
+ public BaseVolumeDescriptor(byte[] src, int offset)
+ {
+ VolumeDescriptorType = (VolumeDescriptorType)src[offset + 0];
+ StandardIdentifier = Encoding.ASCII.GetString(src, offset + 1, 5);
+ VolumeDescriptorVersion = src[offset + 6];
+ }
+
+ internal virtual void WriteTo(byte[] buffer, int offset)
+ {
+ Array.Clear(buffer, offset, SectorSize);
+ buffer[offset] = (byte)VolumeDescriptorType;
+ IsoUtilities.WriteAChars(buffer, offset + 1, 5, StandardIdentifier);
+ buffer[offset + 6] = VolumeDescriptorVersion;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BootDeviceEmulation.cs b/DiscUtils/Iso9660Ps1/BootDeviceEmulation.cs
new file mode 100644
index 0000000..553e468
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BootDeviceEmulation.cs
@@ -0,0 +1,55 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Enumeration of boot device emulation modes.
+ ///
+ public enum BootDeviceEmulation : byte
+ {
+ ///
+ /// No emulation, the boot image is just loaded and executed.
+ ///
+ NoEmulation = 0x0,
+
+ ///
+ /// Emulates 1.2MB diskette image as drive A.
+ ///
+ Diskette1200KiB = 0x1,
+
+ ///
+ /// Emulates 1.44MB diskette image as drive A.
+ ///
+ Diskette1440KiB = 0x2,
+
+ ///
+ /// Emulates 2.88MB diskette image as drive A.
+ ///
+ Diskette2880KiB = 0x3,
+
+ ///
+ /// Emulates hard disk image as drive C.
+ ///
+ HardDisk = 0x4
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BootInitialEntry.cs b/DiscUtils/Iso9660Ps1/BootInitialEntry.cs
new file mode 100644
index 0000000..0d09fba
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BootInitialEntry.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class BootInitialEntry
+ {
+ public byte BootIndicator;
+ public BootDeviceEmulation BootMediaType;
+ public uint ImageStart;
+ public ushort LoadSegment;
+ public ushort SectorCount;
+ public byte SystemType;
+
+ public BootInitialEntry() {}
+
+ public BootInitialEntry(byte[] buffer, int offset)
+ {
+ BootIndicator = buffer[offset + 0x00];
+ BootMediaType = (BootDeviceEmulation)buffer[offset + 0x01];
+ LoadSegment = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x02);
+ SystemType = buffer[offset + 0x04];
+ SectorCount = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 0x06);
+ ImageStart = EndianUtilities.ToUInt32LittleEndian(buffer, offset + 0x08);
+ }
+
+ internal void WriteTo(byte[] buffer, int offset)
+ {
+ Array.Clear(buffer, offset, 0x20);
+ buffer[offset + 0x00] = BootIndicator;
+ buffer[offset + 0x01] = (byte)BootMediaType;
+ EndianUtilities.WriteBytesLittleEndian(LoadSegment, buffer, offset + 0x02);
+ buffer[offset + 0x04] = SystemType;
+ EndianUtilities.WriteBytesLittleEndian(SectorCount, buffer, offset + 0x06);
+ EndianUtilities.WriteBytesLittleEndian(ImageStart, buffer, offset + 0x08);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BootValidationEntry.cs b/DiscUtils/Iso9660Ps1/BootValidationEntry.cs
new file mode 100644
index 0000000..505c6b4
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BootValidationEntry.cs
@@ -0,0 +1,88 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class BootValidationEntry
+ {
+ private readonly byte[] _data;
+ public byte HeaderId;
+ public string ManfId;
+ public byte PlatformId;
+
+ public BootValidationEntry()
+ {
+ HeaderId = 1;
+ PlatformId = 0;
+ ManfId = ".Net DiscUtils";
+ }
+
+ public BootValidationEntry(byte[] src, int offset)
+ {
+ _data = new byte[32];
+ Array.Copy(src, offset, _data, 0, 32);
+
+ HeaderId = _data[0];
+ PlatformId = _data[1];
+ ManfId = EndianUtilities.BytesToString(_data, 4, 24).TrimEnd('\0').TrimEnd(' ');
+ }
+
+ public bool ChecksumValid
+ {
+ get
+ {
+ ushort total = 0;
+ for (int i = 0; i < 16; ++i)
+ {
+ total += EndianUtilities.ToUInt16LittleEndian(_data, i * 2);
+ }
+
+ return total == 0;
+ }
+ }
+
+ internal void WriteTo(byte[] buffer, int offset)
+ {
+ Array.Clear(buffer, offset, 0x20);
+ buffer[offset + 0x00] = HeaderId;
+ buffer[offset + 0x01] = PlatformId;
+ EndianUtilities.StringToBytes(ManfId, buffer, offset + 0x04, 24);
+ buffer[offset + 0x1E] = 0x55;
+ buffer[offset + 0x1F] = 0xAA;
+ EndianUtilities.WriteBytesLittleEndian(CalcChecksum(buffer, offset), buffer, offset + 0x1C);
+ }
+
+ private static ushort CalcChecksum(byte[] buffer, int offset)
+ {
+ ushort total = 0;
+ for (int i = 0; i < 16; ++i)
+ {
+ total += EndianUtilities.ToUInt16LittleEndian(buffer, offset + i * 2);
+ }
+
+ return (ushort)(0 - total);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BootVolumeDescriptor.cs b/DiscUtils/Iso9660Ps1/BootVolumeDescriptor.cs
new file mode 100644
index 0000000..87f786a
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BootVolumeDescriptor.cs
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class BootVolumeDescriptor : BaseVolumeDescriptor
+ {
+ public const string ElToritoSystemIdentifier = "EL TORITO SPECIFICATION";
+
+ public BootVolumeDescriptor(uint catalogSector, int sectorSize)
+ : base(VolumeDescriptorType.Boot, 1, sectorSize)
+ {
+ CatalogSector = catalogSector;
+ }
+
+ public BootVolumeDescriptor(byte[] src, int offset)
+ : base(src, offset)
+ {
+ SystemId = EndianUtilities.BytesToString(src, offset + 0x7, 0x20).TrimEnd('\0');
+ CatalogSector = EndianUtilities.ToUInt32LittleEndian(src, offset + 0x47);
+ }
+
+ public uint CatalogSector { get; }
+
+ public string SystemId { get; }
+
+ internal override void WriteTo(byte[] buffer, int offset)
+ {
+ base.WriteTo(buffer, offset);
+
+ EndianUtilities.StringToBytes(ElToritoSystemIdentifier, buffer, offset + 7, 0x20);
+ EndianUtilities.WriteBytesLittleEndian(CatalogSector, buffer, offset + 0x47);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BootVolumeDescriptorRegion.cs b/DiscUtils/Iso9660Ps1/BootVolumeDescriptorRegion.cs
new file mode 100644
index 0000000..61e1670
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BootVolumeDescriptorRegion.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class BootVolumeDescriptorRegion : VolumeDescriptorDiskRegion
+ {
+ private readonly BootVolumeDescriptor _descriptor;
+
+ public BootVolumeDescriptorRegion(BootVolumeDescriptor descriptor, long start, int sectorSize)
+ : base(start, sectorSize)
+ {
+ _descriptor = descriptor;
+ }
+
+ protected override byte[] GetBlockData()
+ {
+ byte[] buffer = new byte[Length];
+ _descriptor.WriteTo(buffer, 0);
+ return buffer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BuildDirectoryInfo.cs b/DiscUtils/Iso9660Ps1/BuildDirectoryInfo.cs
new file mode 100644
index 0000000..f021e83
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BuildDirectoryInfo.cs
@@ -0,0 +1,219 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using DiscUtils.CoreCompat;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Represents a directory that will be built into the ISO image.
+ ///
+ public sealed class BuildDirectoryInfo : BuildDirectoryMember
+ {
+ internal static readonly Comparer PathTableSortComparison = new PathTableComparison();
+ private readonly Dictionary _members;
+
+ private readonly BuildDirectoryInfo _parent;
+ private List _sortedMembers;
+ private int _sectorSize;
+
+ internal BuildDirectoryInfo(string name, BuildDirectoryInfo parent, int sectorSize)
+ : base(name, MakeShortDirName(name, parent))
+ {
+ _parent = parent == null ? this : parent;
+ HierarchyDepth = parent == null ? 0 : parent.HierarchyDepth + 1;
+ _members = new Dictionary();
+ _sectorSize = sectorSize;
+ }
+
+ internal int HierarchyDepth { get; }
+
+ ///
+ /// The parent directory, or null if none.
+ ///
+ public override BuildDirectoryInfo Parent
+ {
+ get { return _parent; }
+ }
+
+ ///
+ /// Gets the specified child directory or file.
+ ///
+ /// The name of the file or directory to get.
+ /// The member found (or null).
+ /// true if the specified member was found.
+ internal bool TryGetMember(string name, out BuildDirectoryMember member)
+ {
+ return _members.TryGetValue(name, out member);
+ }
+
+ internal void Add(BuildDirectoryMember member)
+ {
+ _members.Add(member.Name, member);
+ _sortedMembers = null;
+ }
+
+ internal override long GetDataSize(Encoding enc)
+ {
+ List sorted = GetSortedMembers();
+
+ long total = 34 * 2; // Two pseudo entries (self & parent)
+
+ foreach (BuildDirectoryMember m in sorted)
+ {
+ uint recordSize = m.GetDirectoryRecordSize(enc);
+
+ // If this record would span a sector boundary, then the current sector is
+ // zero-padded, and the record goes at the start of the next sector.
+ if (total % _sectorSize + recordSize > _sectorSize)
+ {
+ long padLength = _sectorSize - total % _sectorSize;
+ total += padLength;
+ }
+
+ total += recordSize;
+ }
+
+ return MathUtilities.RoundUp(total, _sectorSize);
+ }
+
+ internal uint GetPathTableEntrySize(Encoding enc)
+ {
+ int nameBytes = enc.GetByteCount(PickName(null, enc));
+
+ return (uint)(8 + nameBytes + ((nameBytes & 0x1) == 1 ? 1 : 0));
+ }
+
+ internal int Write(byte[] buffer, int offset, Dictionary locationTable, Encoding enc)
+ {
+ int pos = 0;
+
+ List sorted = GetSortedMembers();
+
+ // Two pseudo entries, effectively '.' and '..'
+ pos += WriteMember(this, "\0", Encoding.ASCII, buffer, offset + pos, locationTable, enc, _sectorSize);
+ pos += WriteMember(_parent, "\x01", Encoding.ASCII, buffer, offset + pos, locationTable, enc, _sectorSize);
+
+ foreach (BuildDirectoryMember m in sorted)
+ {
+ uint recordSize = m.GetDirectoryRecordSize(enc);
+
+ if (pos % _sectorSize + recordSize > _sectorSize)
+ {
+ int padLength = _sectorSize - pos % _sectorSize;
+ Array.Clear(buffer, offset + pos, padLength);
+ pos += padLength;
+ }
+
+ pos += WriteMember(m, null, enc, buffer, offset + pos, locationTable, enc, _sectorSize);
+ }
+
+ // Ensure final padding data is zero'd
+ int finalPadLength = MathUtilities.RoundUp(pos, _sectorSize) - pos;
+ Array.Clear(buffer, offset + pos, finalPadLength);
+
+ return pos + finalPadLength;
+ }
+
+ private static int WriteMember(BuildDirectoryMember m, string nameOverride, Encoding nameEnc, byte[] buffer, int offset, Dictionary locationTable, Encoding dataEnc, int sectorSize)
+ {
+ DirectoryRecord dr = new DirectoryRecord();
+ dr.FileIdentifier = m.PickName(nameOverride, nameEnc);
+ dr.LocationOfExtent = locationTable[m];
+ dr.DataLength = (uint)m.GetDataSize(dataEnc);
+ dr.RecordingDateAndTime = m.CreationTime;
+ dr.Flags = m is BuildDirectoryInfo ? FileFlags.Directory : FileFlags.None;
+ return dr.WriteTo(buffer, offset, nameEnc);
+ }
+
+ private static string MakeShortDirName(string longName, BuildDirectoryInfo dir)
+ {
+ if (IsoUtilities.IsValidDirectoryName(longName))
+ {
+ return longName;
+ }
+
+ char[] shortNameChars = longName.ToUpper(CultureInfo.InvariantCulture).ToCharArray();
+ for (int i = 0; i < shortNameChars.Length; ++i)
+ {
+ if (!IsoUtilities.IsValidDChar(shortNameChars[i]) && shortNameChars[i] != '.' && shortNameChars[i] != ';')
+ {
+ shortNameChars[i] = '_';
+ }
+ }
+
+ return new string(shortNameChars);
+ }
+
+ private List GetSortedMembers()
+ {
+ if (_sortedMembers == null)
+ {
+ List sorted = new List(_members.Values);
+ sorted.Sort(SortedComparison);
+ _sortedMembers = sorted;
+ }
+
+ return _sortedMembers;
+ }
+
+ private class PathTableComparison : Comparer
+ {
+ public override int Compare(BuildDirectoryInfo x, BuildDirectoryInfo y)
+ {
+ if (x.HierarchyDepth != y.HierarchyDepth)
+ {
+ return x.HierarchyDepth - y.HierarchyDepth;
+ }
+
+ if (x.Parent != y.Parent)
+ {
+ return Compare(x.Parent, y.Parent);
+ }
+
+ return CompareNames(x.Name, y.Name, ' ');
+ }
+
+ private static int CompareNames(string x, string y, char padChar)
+ {
+ int max = Math.Max(x.Length, y.Length);
+ for (int i = 0; i < max; ++i)
+ {
+ char xChar = i < x.Length ? x[i] : padChar;
+ char yChar = i < y.Length ? y[i] : padChar;
+
+ if (xChar != yChar)
+ {
+ return xChar - yChar;
+ }
+ }
+
+ return 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BuildDirectoryMember.cs b/DiscUtils/Iso9660Ps1/BuildDirectoryMember.cs
new file mode 100644
index 0000000..fdf135b
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BuildDirectoryMember.cs
@@ -0,0 +1,155 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Provides the base class for and
+ /// objects that will be built into an
+ /// ISO image.
+ ///
+ /// Instances of this class have two names, a ,
+ /// which is the full-length Joliet name and a ,
+ /// which is the strictly compliant ISO 9660 name.
+ public abstract class BuildDirectoryMember
+ {
+ internal static readonly Comparer SortedComparison = new DirectorySortedComparison();
+
+ ///
+ /// Initializes a new instance of the BuildDirectoryMember class.
+ ///
+ /// The Joliet compliant name of the file or directory.
+ /// The ISO 9660 compliant name of the file or directory.
+ protected BuildDirectoryMember(string name, string shortName)
+ {
+ Name = name;
+ ShortName = shortName;
+ CreationTime = DateTime.UtcNow;
+ }
+
+ ///
+ /// Gets or sets the creation date for the file or directory, in UTC.
+ ///
+ public DateTime CreationTime { get; set; }
+
+ ///
+ /// Gets the Joliet compliant name of the file or directory.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Gets the parent directory, or null if this is the root directory.
+ ///
+ public abstract BuildDirectoryInfo Parent { get; }
+
+ ///
+ /// Gets the ISO 9660 compliant name of the file or directory.
+ ///
+ public string ShortName { get; }
+
+ internal string PickName(string nameOverride, Encoding enc)
+ {
+ if (nameOverride != null)
+ {
+ return nameOverride;
+ }
+ return enc == Encoding.ASCII ? ShortName : Name;
+ }
+
+ internal abstract long GetDataSize(Encoding enc);
+
+ internal uint GetDirectoryRecordSize(Encoding enc)
+ {
+ return DirectoryRecord.CalcLength(PickName(null, enc), enc);
+ }
+
+ private class DirectorySortedComparison : Comparer
+ {
+ public override int Compare(BuildDirectoryMember x, BuildDirectoryMember y)
+ {
+ string[] xParts = x.Name.Split('.', ';');
+ string[] yParts = y.Name.Split('.', ';');
+
+ string xPart;
+ string yPart;
+
+ for (int i = 0; i < 2; ++i)
+ {
+ xPart = xParts.Length > i ? xParts[i] : string.Empty;
+ yPart = yParts.Length > i ? yParts[i] : string.Empty;
+ int val = ComparePart(xPart, yPart, ' ');
+ if (val != 0)
+ {
+ return val;
+ }
+ }
+
+ xPart = xParts.Length > 2 ? xParts[2] : string.Empty;
+ yPart = yParts.Length > 2 ? yParts[2] : string.Empty;
+ return ComparePartBackwards(xPart, yPart, '0');
+ }
+
+ private static int ComparePart(string x, string y, char padChar)
+ {
+ int max = Math.Max(x.Length, y.Length);
+ for (int i = 0; i < max; ++i)
+ {
+ char xChar = i < x.Length ? x[i] : padChar;
+ char yChar = i < y.Length ? y[i] : padChar;
+
+ if (xChar != yChar)
+ {
+ return xChar - yChar;
+ }
+ }
+
+ return 0;
+ }
+
+ private static int ComparePartBackwards(string x, string y, char padChar)
+ {
+ int max = Math.Max(x.Length, y.Length);
+
+ int xPad = max - x.Length;
+ int yPad = max - y.Length;
+
+ for (int i = 0; i < max; ++i)
+ {
+ char xChar = i >= xPad ? x[i - xPad] : padChar;
+ char yChar = i >= yPad ? y[i - yPad] : padChar;
+
+ if (xChar != yChar)
+ {
+ // Note: Version numbers are in DESCENDING order!
+ return yChar - xChar;
+ }
+ }
+
+ return 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BuildFileInfo.cs b/DiscUtils/Iso9660Ps1/BuildFileInfo.cs
new file mode 100644
index 0000000..a826c2a
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BuildFileInfo.cs
@@ -0,0 +1,136 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using DiscUtils.CoreCompat;
+using DiscUtils.Internal;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Represents a file that will be built into the ISO image.
+ ///
+ public sealed class BuildFileInfo : BuildDirectoryMember
+ {
+ private readonly byte[] _contentData;
+ private readonly string _contentPath;
+ private readonly long _contentSize;
+ private readonly Stream _contentStream;
+
+ internal BuildFileInfo(string name, BuildDirectoryInfo parent, byte[] content)
+ : base(IsoUtilities.NormalizeFileName(name), MakeShortFileName(name, parent))
+ {
+ Parent = parent;
+ _contentData = content;
+ _contentSize = content.Length;
+ }
+
+ internal BuildFileInfo(string name, BuildDirectoryInfo parent, string content)
+ : base(IsoUtilities.NormalizeFileName(name), MakeShortFileName(name, parent))
+ {
+ Parent = parent;
+ _contentPath = content;
+ _contentSize = new FileInfo(_contentPath).Length;
+
+ CreationTime = new FileInfo(_contentPath).LastWriteTimeUtc;
+ }
+
+ internal BuildFileInfo(string name, BuildDirectoryInfo parent, Stream source)
+ : base(IsoUtilities.NormalizeFileName(name), MakeShortFileName(name, parent))
+ {
+ Parent = parent;
+ _contentStream = source;
+ _contentSize = _contentStream.Length;
+ }
+
+ ///
+ /// The parent directory, or null if none.
+ ///
+ public override BuildDirectoryInfo Parent { get; }
+
+ internal override long GetDataSize(Encoding enc)
+ {
+ return _contentSize;
+ }
+
+ internal Stream OpenStream()
+ {
+ if (_contentData != null)
+ {
+ return new MemoryStream(_contentData, false);
+ }
+ if (_contentPath != null)
+ {
+ var locator = new LocalFileLocator(string.Empty);
+ return locator.Open(_contentPath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ }
+ return _contentStream;
+ }
+
+ internal void CloseStream(Stream s)
+ {
+ // Close and dispose the stream, unless it's one we were given to stream in
+ // from (we might need it again).
+ if (_contentStream != s)
+ {
+ s.Dispose();
+ }
+ }
+
+ private static string MakeShortFileName(string longName, BuildDirectoryInfo dir)
+ {
+ if (IsoUtilities.IsValidFileName(longName))
+ {
+ return longName;
+ }
+
+ char[] shortNameChars = longName.ToUpper(CultureInfo.InvariantCulture).ToCharArray();
+ for (int i = 0; i < shortNameChars.Length; ++i)
+ {
+ if (!IsoUtilities.IsValidDChar(shortNameChars[i]) && shortNameChars[i] != '.' && shortNameChars[i] != ';')
+ {
+ shortNameChars[i] = '_';
+ }
+ }
+
+ string[] parts = IsoUtilities.SplitFileName(new string(shortNameChars));
+
+ if (parts[0].Length + parts[1].Length > 30)
+ {
+ parts[1] = parts[1].Substring(0, Math.Min(parts[1].Length, 3));
+ }
+
+ if (parts[0].Length + parts[1].Length > 30)
+ {
+ parts[0] = parts[0].Substring(0, 30 - parts[1].Length);
+ }
+
+ string candidate = parts[0] + '.' + parts[1] + ';' + parts[2];
+
+ // TODO: Make unique
+ return candidate;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/BuildParameters.cs b/DiscUtils/Iso9660Ps1/BuildParameters.cs
new file mode 100644
index 0000000..7f44cb7
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/BuildParameters.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class BuildParameters
+ {
+ public BuildParameters()
+ {
+ VolumeIdentifier = string.Empty;
+ UseJoliet = true;
+ SectorSize = 2048;
+ }
+
+ public int SectorSize { get; set; }
+
+ public bool UseJoliet { get; set; }
+
+ public string VolumeIdentifier { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/CDBuilder.cs b/DiscUtils/Iso9660Ps1/CDBuilder.cs
new file mode 100644
index 0000000..b363661
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/CDBuilder.cs
@@ -0,0 +1,518 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Class that creates ISO images.
+ ///
+ ///
+ ///
+ /// CDBuilder builder = new CDBuilder();
+ /// builder.VolumeIdentifier = "MYISO";
+ /// builder.UseJoliet = true;
+ /// builder.AddFile("Hello.txt", Encoding.ASCII.GetBytes("hello world!"));
+ /// builder.Build(@"C:\TEMP\myiso.iso");
+ ///
+ ///
+ public sealed class CDBuilder : StreamBuilder
+ {
+ private const long DiskStart = 0x8000;
+ private BootInitialEntry _bootEntry;
+ private Stream _bootImage;
+
+ private readonly BuildParameters _buildParams;
+ private readonly List _dirs;
+
+ private readonly List _files;
+ private readonly BuildDirectoryInfo _rootDirectory;
+ private readonly int _sectorSize;
+
+ ///
+ /// Initializes a new instance of the CDBuilder class.
+ ///
+ public CDBuilder()
+ {
+ _files = new List();
+ _dirs = new List();
+ _sectorSize = 2048;
+ _rootDirectory = new BuildDirectoryInfo("\0", null, _sectorSize);
+ _dirs.Add(_rootDirectory);
+
+ _buildParams = new BuildParameters();
+ _buildParams.UseJoliet = true;
+ }
+
+
+ ///
+ /// Initializes a new instance of the CDBuilder class.
+ ///
+ public CDBuilder(int sectorSize)
+ {
+ _files = new List();
+ _dirs = new List();
+ _sectorSize = sectorSize;
+ _rootDirectory = new BuildDirectoryInfo("\0", null, _sectorSize);
+ _dirs.Add(_rootDirectory);
+
+ _buildParams = new BuildParameters();
+ _buildParams.UseJoliet = true;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to update the ISOLINUX info table at the
+ /// start of the boot image. Use with ISOLINUX only.
+ ///
+ ///
+ /// ISOLINUX has an 'information table' at the start of the boot loader that verifies
+ /// the CD has been loaded correctly by the BIOS. This table needs to be updated
+ /// to match the actual ISO.
+ ///
+ public bool UpdateIsolinuxBootTable { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether Joliet file-system extensions should be used.
+ ///
+ public bool UseJoliet
+ {
+ get { return _buildParams.UseJoliet; }
+ set { _buildParams.UseJoliet = value; }
+ }
+
+ ///
+ /// Gets or sets the Volume Identifier for the ISO file.
+ ///
+ ///
+ /// Must be a valid identifier, i.e. max 32 characters in the range A-Z, 0-9 or _.
+ /// Lower-case characters are not permitted.
+ ///
+ public string VolumeIdentifier
+ {
+ get { return _buildParams.VolumeIdentifier; }
+
+ set
+ {
+ if (value.Length > 32)
+ {
+ throw new ArgumentException("Not a valid volume identifier");
+ }
+ _buildParams.VolumeIdentifier = value;
+ }
+ }
+
+ ///
+ /// Sets the boot image for the ISO image.
+ ///
+ /// Stream containing the boot image.
+ /// The type of emulation requested of the BIOS.
+ /// The memory segment to load the image to (0 for default).
+ public void SetBootImage(Stream image, BootDeviceEmulation emulation, int loadSegment)
+ {
+ if (_bootEntry != null)
+ {
+ throw new InvalidOperationException("Boot image already set");
+ }
+
+ _bootEntry = new BootInitialEntry();
+ _bootEntry.BootIndicator = 0x88;
+ _bootEntry.BootMediaType = emulation;
+ _bootEntry.LoadSegment = (ushort)loadSegment;
+ _bootEntry.SystemType = 0;
+ _bootImage = image;
+ }
+
+ ///
+ /// Adds a directory to the ISO image.
+ ///
+ /// The name of the directory on the ISO image.
+ /// The object representing this directory.
+ ///
+ /// The name is the full path to the directory, for example:
+ ///
+ /// builder.AddDirectory(@"DIRA\DIRB\DIRC");
+ ///
+ ///
+ public BuildDirectoryInfo AddDirectory(string name)
+ {
+ string[] nameElements = name.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
+ return GetDirectory(nameElements, nameElements.Length, true);
+ }
+
+ ///
+ /// Adds a byte array to the ISO image as a file.
+ ///
+ /// The name of the file on the ISO image.
+ /// The contents of the file.
+ /// The object representing this file.
+ ///
+ /// The name is the full path to the file, for example:
+ ///
+ /// builder.AddFile(@"DIRA\DIRB\FILE.TXT;1", new byte[]{0,1,2});
+ ///
+ /// Note the version number at the end of the file name is optional, if not
+ /// specified the default of 1 will be used.
+ ///
+ public BuildFileInfo AddFile(string name, byte[] content)
+ {
+ string[] nameElements = name.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
+ BuildDirectoryInfo dir = GetDirectory(nameElements, nameElements.Length - 1, true);
+
+ BuildDirectoryMember existing;
+ if (dir.TryGetMember(nameElements[nameElements.Length - 1], out existing))
+ {
+ throw new IOException("File already exists");
+ }
+ BuildFileInfo fi = new BuildFileInfo(nameElements[nameElements.Length - 1], dir, content);
+ _files.Add(fi);
+ dir.Add(fi);
+ return fi;
+ }
+
+ ///
+ /// Adds a disk file to the ISO image as a file.
+ ///
+ /// The name of the file on the ISO image.
+ /// The name of the file on disk.
+ /// The object representing this file.
+ ///
+ /// The name is the full path to the file, for example:
+ ///
+ /// builder.AddFile(@"DIRA\DIRB\FILE.TXT;1", @"C:\temp\tempfile.bin");
+ ///
+ /// Note the version number at the end of the file name is optional, if not
+ /// specified the default of 1 will be used.
+ ///
+ public BuildFileInfo AddFile(string name, string sourcePath)
+ {
+ string[] nameElements = name.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
+ BuildDirectoryInfo dir = GetDirectory(nameElements, nameElements.Length - 1, true);
+
+ BuildDirectoryMember existing;
+ if (dir.TryGetMember(nameElements[nameElements.Length - 1], out existing))
+ {
+ throw new IOException("File already exists");
+ }
+ BuildFileInfo fi = new BuildFileInfo(nameElements[nameElements.Length - 1], dir, sourcePath);
+ _files.Add(fi);
+ dir.Add(fi);
+ return fi;
+ }
+
+ ///
+ /// Adds a stream to the ISO image as a file.
+ ///
+ /// The name of the file on the ISO image.
+ /// The contents of the file.
+ /// The object representing this file.
+ ///
+ /// The name is the full path to the file, for example:
+ ///
+ /// builder.AddFile(@"DIRA\DIRB\FILE.TXT;1", stream);
+ ///
+ /// Note the version number at the end of the file name is optional, if not
+ /// specified the default of 1 will be used.
+ ///
+ public BuildFileInfo AddFile(string name, Stream source)
+ {
+ if (!source.CanSeek)
+ {
+ throw new ArgumentException("source doesn't support seeking", nameof(source));
+ }
+
+ string[] nameElements = name.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
+ BuildDirectoryInfo dir = GetDirectory(nameElements, nameElements.Length - 1, true);
+
+ BuildDirectoryMember existing;
+ if (dir.TryGetMember(nameElements[nameElements.Length - 1], out existing))
+ {
+ throw new IOException("File already exists");
+ }
+ BuildFileInfo fi = new BuildFileInfo(nameElements[nameElements.Length - 1], dir, source);
+ _files.Add(fi);
+ dir.Add(fi);
+ return fi;
+ }
+
+ protected override List FixExtents(out long totalLength)
+ {
+ List fixedRegions = new List();
+
+ DateTime buildTime = DateTime.UtcNow;
+
+ Encoding suppEncoding = _buildParams.UseJoliet ? Encoding.BigEndianUnicode : Encoding.ASCII;
+
+ Dictionary primaryLocationTable = new Dictionary();
+ Dictionary supplementaryLocationTable =
+ new Dictionary();
+
+ long focus = DiskStart + 3 * _buildParams.SectorSize; // Primary, Supplementary, End (fixed at end...)
+ if (_bootEntry != null)
+ {
+ focus += _buildParams.SectorSize;
+ }
+
+ // ####################################################################
+ // # 0. Fix boot image location
+ // ####################################################################
+ long bootCatalogPos = 0;
+ if (_bootEntry != null)
+ {
+ long bootImagePos = focus;
+ Stream realBootImage = PatchBootImage(_bootImage, (uint)(DiskStart / _buildParams.SectorSize),
+ (uint)(bootImagePos / _buildParams.SectorSize));
+ BuilderStreamExtent bootImageExtent = new BuilderStreamExtent(focus, realBootImage);
+ fixedRegions.Add(bootImageExtent);
+ focus += MathUtilities.RoundUp(bootImageExtent.Length, _buildParams.SectorSize);
+
+ bootCatalogPos = focus;
+ byte[] bootCatalog = new byte[_buildParams.SectorSize];
+ BootValidationEntry bve = new BootValidationEntry();
+ bve.WriteTo(bootCatalog, 0x00);
+ _bootEntry.ImageStart = (uint)MathUtilities.Ceil(bootImagePos, _buildParams.SectorSize);
+ _bootEntry.SectorCount = (ushort)MathUtilities.Ceil(_bootImage.Length, Sizes.Sector);
+ _bootEntry.WriteTo(bootCatalog, 0x20);
+ fixedRegions.Add(new BuilderBufferExtent(bootCatalogPos, bootCatalog));
+ focus += _buildParams.SectorSize;
+ }
+
+ // ####################################################################
+ // # 1. Fix file locations
+ // ####################################################################
+
+ // Find end of the file data, fixing the files in place as we go
+ foreach (BuildFileInfo fi in _files)
+ {
+ primaryLocationTable.Add(fi, (uint)(focus / _buildParams.SectorSize));
+ supplementaryLocationTable.Add(fi, (uint)(focus / _buildParams.SectorSize));
+ FileExtent extent = new FileExtent(fi, focus);
+
+ // Only remember files of non-zero length (otherwise we'll stomp on a valid file)
+ if (extent.Length != 0)
+ {
+ fixedRegions.Add(extent);
+ }
+
+ focus += MathUtilities.RoundUp(extent.Length, _buildParams.SectorSize);
+ }
+
+ // ####################################################################
+ // # 2. Fix directory locations
+ // ####################################################################
+
+ // There are two directory tables
+ // 1. Primary (std ISO9660)
+ // 2. Supplementary (Joliet)
+
+ // Find start of the second set of directory data, fixing ASCII directories in place.
+ long startOfFirstDirData = focus;
+ foreach (BuildDirectoryInfo di in _dirs)
+ {
+ primaryLocationTable.Add(di, (uint)(focus / _buildParams.SectorSize));
+ DirectoryExtent extent = new DirectoryExtent(di, primaryLocationTable, Encoding.ASCII, focus);
+ fixedRegions.Add(extent);
+ focus += MathUtilities.RoundUp(extent.Length, _buildParams.SectorSize);
+ }
+
+ // Find end of the second directory table, fixing supplementary directories in place.
+ long startOfSecondDirData = focus;
+ foreach (BuildDirectoryInfo di in _dirs)
+ {
+ supplementaryLocationTable.Add(di, (uint)(focus / _buildParams.SectorSize));
+ DirectoryExtent extent = new DirectoryExtent(di, supplementaryLocationTable, suppEncoding, focus);
+ fixedRegions.Add(extent);
+ focus += MathUtilities.RoundUp(extent.Length, _buildParams.SectorSize);
+ }
+
+ // ####################################################################
+ // # 3. Fix path tables
+ // ####################################################################
+
+ // There are four path tables:
+ // 1. LE, ASCII
+ // 2. BE, ASCII
+ // 3. LE, Supp Encoding (Joliet)
+ // 4. BE, Supp Encoding (Joliet)
+
+ // Find end of the path table
+ long startOfFirstPathTable = focus;
+ PathTable pathTable = new PathTable(false, Encoding.ASCII, _dirs, primaryLocationTable, focus);
+ fixedRegions.Add(pathTable);
+ focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+ long primaryPathTableLength = pathTable.Length;
+
+ long startOfSecondPathTable = focus;
+ pathTable = new PathTable(true, Encoding.ASCII, _dirs, primaryLocationTable, focus);
+ fixedRegions.Add(pathTable);
+ focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+
+ long startOfThirdPathTable = focus;
+ pathTable = new PathTable(false, suppEncoding, _dirs, supplementaryLocationTable, focus);
+ fixedRegions.Add(pathTable);
+ focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+ long supplementaryPathTableLength = pathTable.Length;
+
+ long startOfFourthPathTable = focus;
+ pathTable = new PathTable(true, suppEncoding, _dirs, supplementaryLocationTable, focus);
+ fixedRegions.Add(pathTable);
+ focus += MathUtilities.RoundUp(pathTable.Length, _buildParams.SectorSize);
+
+ // Find the end of the disk
+ totalLength = focus;
+
+ // ####################################################################
+ // # 4. Prepare volume descriptors now other structures are fixed
+ // ####################################################################
+ int regionIdx = 0;
+ focus = DiskStart;
+ PrimaryVolumeDescriptor pvDesc = new PrimaryVolumeDescriptor(
+ (uint)(totalLength / _buildParams.SectorSize), // VolumeSpaceSize
+ (uint)primaryPathTableLength, // PathTableSize
+ (uint)(startOfFirstPathTable / _buildParams.SectorSize), // TypeLPathTableLocation
+ (uint)(startOfSecondPathTable / _buildParams.SectorSize), // TypeMPathTableLocation
+ (uint)(startOfFirstDirData / _buildParams.SectorSize), // RootDirectory.LocationOfExtent
+ (uint)_rootDirectory.GetDataSize(Encoding.ASCII), // RootDirectory.DataLength
+ buildTime,
+ _sectorSize);
+ pvDesc.VolumeIdentifier = _buildParams.VolumeIdentifier;
+ PrimaryVolumeDescriptorRegion pvdr = new PrimaryVolumeDescriptorRegion(pvDesc, focus, _sectorSize);
+ fixedRegions.Insert(regionIdx++, pvdr);
+ focus += _buildParams.SectorSize;
+
+ if (_bootEntry != null)
+ {
+ BootVolumeDescriptor bvDesc = new BootVolumeDescriptor(
+ (uint)(bootCatalogPos / _buildParams.SectorSize), _buildParams.SectorSize);
+ BootVolumeDescriptorRegion bvdr = new BootVolumeDescriptorRegion(bvDesc, focus, _buildParams.SectorSize);
+ fixedRegions.Insert(regionIdx++, bvdr);
+ focus += _buildParams.SectorSize;
+ }
+
+ SupplementaryVolumeDescriptor svDesc = new SupplementaryVolumeDescriptor(
+ (uint)(totalLength / _buildParams.SectorSize), // VolumeSpaceSize
+ (uint)supplementaryPathTableLength, // PathTableSize
+ (uint)(startOfThirdPathTable / _buildParams.SectorSize), // TypeLPathTableLocation
+ (uint)(startOfFourthPathTable / _buildParams.SectorSize), // TypeMPathTableLocation
+ (uint)(startOfSecondDirData / _buildParams.SectorSize), // RootDirectory.LocationOfExtent
+ (uint)_rootDirectory.GetDataSize(suppEncoding), // RootDirectory.DataLength
+ buildTime,
+ suppEncoding,
+ _sectorSize);
+ svDesc.VolumeIdentifier = _buildParams.VolumeIdentifier;
+ SupplementaryVolumeDescriptorRegion svdr = new SupplementaryVolumeDescriptorRegion(svDesc, focus, _sectorSize);
+ fixedRegions.Insert(regionIdx++, svdr);
+ focus += _buildParams.SectorSize;
+
+ VolumeDescriptorSetTerminator evDesc = new VolumeDescriptorSetTerminator(_sectorSize);
+ VolumeDescriptorSetTerminatorRegion evdr = new VolumeDescriptorSetTerminatorRegion(evDesc, focus, _sectorSize);
+ fixedRegions.Insert(regionIdx++, evdr);
+
+ return fixedRegions;
+ }
+
+ ///
+ /// Patches a boot image (esp. for ISOLINUX) before it is written to the disk.
+ ///
+ /// The original (master) boot image.
+ /// The logical block address of the primary volume descriptor.
+ /// The logical block address of the boot image itself.
+ /// A stream containing the patched boot image - does not need to be disposed.
+ private Stream PatchBootImage(Stream bootImage, uint pvdLba, uint bootImageLba)
+ {
+ // Early-exit if no patching to do...
+ if (!UpdateIsolinuxBootTable)
+ {
+ return bootImage;
+ }
+
+ byte[] bootData = StreamUtilities.ReadExact(bootImage, (int)bootImage.Length);
+
+ Array.Clear(bootData, 8, 56);
+
+ uint checkSum = 0;
+ for (int i = 64; i < bootData.Length; i += 4)
+ {
+ checkSum += EndianUtilities.ToUInt32LittleEndian(bootData, i);
+ }
+
+ EndianUtilities.WriteBytesLittleEndian(pvdLba, bootData, 8);
+ EndianUtilities.WriteBytesLittleEndian(bootImageLba, bootData, 12);
+ EndianUtilities.WriteBytesLittleEndian(bootData.Length, bootData, 16);
+ EndianUtilities.WriteBytesLittleEndian(checkSum, bootData, 20);
+
+ return new MemoryStream(bootData, false);
+ }
+
+ private BuildDirectoryInfo GetDirectory(string[] path, int pathLength, bool createMissing)
+ {
+ BuildDirectoryInfo di = TryGetDirectory(path, pathLength, createMissing);
+
+ if (di == null)
+ {
+ throw new DirectoryNotFoundException("Directory not found");
+ }
+
+ return di;
+ }
+
+ private BuildDirectoryInfo TryGetDirectory(string[] path, int pathLength, bool createMissing)
+ {
+ BuildDirectoryInfo focus = _rootDirectory;
+
+ for (int i = 0; i < pathLength; ++i)
+ {
+ BuildDirectoryMember next;
+ if (!focus.TryGetMember(path[i], out next))
+ {
+ if (createMissing)
+ {
+ // This directory doesn't exist, create it...
+ BuildDirectoryInfo di = new BuildDirectoryInfo(path[i], focus, _sectorSize);
+ focus.Add(di);
+ _dirs.Add(di);
+ focus = di;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ BuildDirectoryInfo nextAsBuildDirectoryInfo = next as BuildDirectoryInfo;
+ if (nextAsBuildDirectoryInfo == null)
+ {
+ throw new IOException("File with conflicting name exists");
+ }
+ focus = nextAsBuildDirectoryInfo;
+ }
+ }
+
+ return focus;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/CDReader.cs b/DiscUtils/Iso9660Ps1/CDReader.cs
new file mode 100644
index 0000000..033b3b6
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/CDReader.cs
@@ -0,0 +1,229 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.IO;
+using DiscUtils.Streams;
+using DiscUtils.Vfs;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Class for reading existing ISO images.
+ ///
+ public class CDReader : VfsFileSystemFacade, IClusterBasedFileSystem, IUnixFileSystem
+ {
+ ///
+ /// Initializes a new instance of the CDReader class.
+ ///
+ /// The stream to read the ISO image from.
+ /// Whether to read Joliet extensions.
+ public CDReader(Stream data, bool joliet)
+ : base(new VfsCDReader(data, joliet, false, 2048))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the CDReader class.
+ ///
+ /// The stream to read the ISO image from.
+ /// Whether to read Joliet extensions.
+ /// Hides version numbers (e.g. ";1") from the end of files.
+ public CDReader(Stream data, bool joliet, bool hideVersions)
+ : base(new VfsCDReader(data, joliet, hideVersions, 2048)) { }
+
+
+
+ ///
+ /// Initializes a new instance of the CDReader class.
+ ///
+ /// The stream to read the ISO image from.
+ /// Whether to read Joliet extensions.
+ public CDReader(Stream data, bool joliet, int sectorSize)
+ : base(new VfsCDReader(data, joliet, false, sectorSize)) {
+ }
+
+ ///
+ /// Initializes a new instance of the CDReader class.
+ ///
+ /// The stream to read the ISO image from.
+ /// Whether to read Joliet extensions.
+ /// Hides version numbers (e.g. ";1") from the end of files.
+ public CDReader(Stream data, bool joliet, bool hideVersions, int sectorSize)
+ : base(new VfsCDReader(data, joliet, hideVersions, sectorSize)) {}
+
+ ///
+ /// Gets which of the Iso9660 variants is being used.
+ ///
+ public Iso9660Variant ActiveVariant
+ {
+ get { return GetRealFileSystem().ActiveVariant; }
+ }
+
+ ///
+ /// Gets the emulation requested of BIOS when the image is loaded.
+ ///
+ public BootDeviceEmulation BootEmulation
+ {
+ get { return GetRealFileSystem().BootEmulation; }
+ }
+
+ ///
+ /// Gets the absolute start position (in bytes) of the boot image, or zero if not found.
+ ///
+ public long BootImageStart
+ {
+ get { return GetRealFileSystem().BootImageStart; }
+ }
+
+ ///
+ /// Gets the memory segment the image should be loaded into (0 for default).
+ ///
+ public int BootLoadSegment
+ {
+ get { return GetRealFileSystem().BootLoadSegment; }
+ }
+
+ ///
+ /// Gets a value indicating whether a boot image is present.
+ ///
+ public bool HasBootImage
+ {
+ get { return GetRealFileSystem().HasBootImage; }
+ }
+
+ ///
+ /// Gets the size (in bytes) of each cluster.
+ ///
+ public long ClusterSize
+ {
+ get { return GetRealFileSystem().ClusterSize; }
+ }
+
+ ///
+ /// Gets the total number of clusters managed by the file system.
+ ///
+ public long TotalClusters
+ {
+ get { return GetRealFileSystem().TotalClusters; }
+ }
+
+ ///
+ /// Converts a cluster (index) into an absolute byte position in the underlying stream.
+ ///
+ /// The cluster to convert.
+ /// The corresponding absolute byte position.
+ public long ClusterToOffset(long cluster)
+ {
+ return GetRealFileSystem().ClusterToOffset(cluster);
+ }
+
+ ///
+ /// Converts an absolute byte position in the underlying stream to a cluster (index).
+ ///
+ /// The byte position to convert.
+ /// The cluster containing the specified byte.
+ public long OffsetToCluster(long offset)
+ {
+ return GetRealFileSystem().OffsetToCluster(offset);
+ }
+
+ ///
+ /// Converts a file name to the list of clusters occupied by the file's data.
+ ///
+ /// The path to inspect.
+ /// The clusters.
+ /// Note that in some file systems, small files may not have dedicated
+ /// clusters. Only dedicated clusters will be returned.
+ public Range[] PathToClusters(string path)
+ {
+ return GetRealFileSystem().PathToClusters(path);
+ }
+
+ ///
+ /// Converts a file name to the extents containing its data.
+ ///
+ /// The path to inspect.
+ /// The file extents, as absolute byte positions in the underlying stream.
+ /// Use this method with caution - not all file systems will store all bytes
+ /// directly in extents. Files may be compressed, sparse or encrypted. This method
+ /// merely indicates where file data is stored, not what's stored.
+ public StreamExtent[] PathToExtents(string path)
+ {
+ return GetRealFileSystem().PathToExtents(path);
+ }
+
+ ///
+ /// Gets an object that can convert between clusters and files.
+ ///
+ /// The cluster map.
+ public ClusterMap BuildClusterMap()
+ {
+ return GetRealFileSystem().BuildClusterMap();
+ }
+
+ ///
+ /// Retrieves Unix-specific information about a file or directory.
+ ///
+ /// Path to the file or directory.
+ /// Information about the owner, group, permissions and type of the
+ /// file or directory.
+ public UnixFileSystemInfo GetUnixFileInfo(string path)
+ {
+ return GetRealFileSystem().GetUnixFileInfo(path);
+ }
+
+ ///
+ /// Detects if a stream contains a valid ISO file system.
+ ///
+ /// The stream to inspect.
+ /// true if the stream contains an ISO file system, else false.
+ public static bool Detect(Stream data, int sectorSize)
+ {
+ byte[] buffer = new byte[sectorSize];
+
+ if (data.Length < 0x8000 + sectorSize)
+ {
+ return false;
+ }
+
+ data.Position = 0x8000;
+ int numRead = StreamUtilities.ReadMaximum(data, buffer, 0, sectorSize);
+ if (numRead != sectorSize)
+ {
+ return false;
+ }
+
+ BaseVolumeDescriptor bvd = new BaseVolumeDescriptor(buffer, 0);
+
+ return bvd.StandardIdentifier == BaseVolumeDescriptor.Iso9660StandardIdentifier;
+ }
+
+ ///
+ /// Opens a stream containing the boot image.
+ ///
+ /// The boot image as a stream.
+ public Stream OpenBootImage()
+ {
+ return GetRealFileSystem().OpenBootImage();
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/CommonVolumeDescriptor.cs b/DiscUtils/Iso9660Ps1/CommonVolumeDescriptor.cs
new file mode 100644
index 0000000..fb7a571
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/CommonVolumeDescriptor.cs
@@ -0,0 +1,141 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+using DiscUtils.Internal;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class CommonVolumeDescriptor : BaseVolumeDescriptor
+ {
+ public string AbstractFileIdentifier;
+ public string ApplicationIdentifier;
+ public string BibliographicFileIdentifier;
+ public Encoding CharacterEncoding;
+ public string CopyrightFileIdentifier;
+ public DateTime CreationDateAndTime;
+ public string DataPreparerIdentifier;
+ public DateTime EffectiveDateAndTime;
+ public DateTime ExpirationDateAndTime;
+ public byte FileStructureVersion;
+ public ushort LogicalBlockSize;
+ public DateTime ModificationDateAndTime;
+ public uint OptionalTypeLPathTableLocation;
+ public uint OptionalTypeMPathTableLocation;
+ public uint PathTableSize;
+ public string PublisherIdentifier;
+ public DirectoryRecord RootDirectory;
+
+ public string SystemIdentifier;
+ public uint TypeLPathTableLocation;
+ public uint TypeMPathTableLocation;
+ public string VolumeIdentifier;
+ public ushort VolumeSequenceNumber;
+ public string VolumeSetIdentifier;
+ public ushort VolumeSetSize;
+ public uint VolumeSpaceSize;
+
+ public CommonVolumeDescriptor(byte[] src, int offset, Encoding enc)
+ : base(src, offset)
+ {
+ CharacterEncoding = enc;
+
+ SystemIdentifier = IsoUtilities.ReadChars(src, offset + 8, 32, CharacterEncoding);
+ VolumeIdentifier = IsoUtilities.ReadChars(src, offset + 40, 32, CharacterEncoding);
+ VolumeSpaceSize = IsoUtilities.ToUInt32FromBoth(src, offset + 80);
+ VolumeSetSize = IsoUtilities.ToUInt16FromBoth(src, offset + 120);
+ VolumeSequenceNumber = IsoUtilities.ToUInt16FromBoth(src, offset + 124);
+ LogicalBlockSize = IsoUtilities.ToUInt16FromBoth(src, offset + 128);
+ PathTableSize = IsoUtilities.ToUInt32FromBoth(src, offset + 132);
+ TypeLPathTableLocation = EndianUtilities.ToUInt32LittleEndian(src, offset + 140);
+ OptionalTypeLPathTableLocation = EndianUtilities.ToUInt32LittleEndian(src, offset + 144);
+ TypeMPathTableLocation = Utilities.BitSwap(EndianUtilities.ToUInt32LittleEndian(src, offset + 148));
+ OptionalTypeMPathTableLocation = Utilities.BitSwap(EndianUtilities.ToUInt32LittleEndian(src, offset + 152));
+ DirectoryRecord.ReadFrom(src, offset + 156, CharacterEncoding, out RootDirectory);
+ VolumeSetIdentifier = IsoUtilities.ReadChars(src, offset + 190, 318 - 190, CharacterEncoding);
+ PublisherIdentifier = IsoUtilities.ReadChars(src, offset + 318, 446 - 318, CharacterEncoding);
+ DataPreparerIdentifier = IsoUtilities.ReadChars(src, offset + 446, 574 - 446, CharacterEncoding);
+ ApplicationIdentifier = IsoUtilities.ReadChars(src, offset + 574, 702 - 574, CharacterEncoding);
+ CopyrightFileIdentifier = IsoUtilities.ReadChars(src, offset + 702, 739 - 702, CharacterEncoding);
+ AbstractFileIdentifier = IsoUtilities.ReadChars(src, offset + 739, 776 - 739, CharacterEncoding);
+ BibliographicFileIdentifier = IsoUtilities.ReadChars(src, offset + 776, 813 - 776, CharacterEncoding);
+ CreationDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 813);
+ ModificationDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 830);
+ ExpirationDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 847);
+ EffectiveDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 864);
+ FileStructureVersion = src[offset + 881];
+ }
+
+ public CommonVolumeDescriptor(
+ VolumeDescriptorType type,
+ byte version,
+ uint volumeSpaceSize,
+ uint pathTableSize,
+ uint typeLPathTableLocation,
+ uint typeMPathTableLocation,
+ uint rootDirExtentLocation,
+ uint rootDirDataLength,
+ DateTime buildTime,
+ Encoding enc,
+ int sectorSize)
+ : base(type, version, sectorSize)
+ {
+ CharacterEncoding = enc;
+
+ SystemIdentifier = string.Empty;
+ VolumeIdentifier = string.Empty;
+ VolumeSpaceSize = volumeSpaceSize;
+ VolumeSetSize = 1;
+ VolumeSequenceNumber = 1;
+ LogicalBlockSize = (ushort)sectorSize;
+ PathTableSize = pathTableSize;
+ TypeLPathTableLocation = typeLPathTableLocation;
+ ////OptionalTypeLPathTableLocation = 0;
+ TypeMPathTableLocation = typeMPathTableLocation;
+ ////OptionalTypeMPathTableLocation = 0;
+ RootDirectory = new DirectoryRecord();
+ RootDirectory.ExtendedAttributeRecordLength = 0;
+ RootDirectory.LocationOfExtent = rootDirExtentLocation;
+ RootDirectory.DataLength = rootDirDataLength;
+ RootDirectory.RecordingDateAndTime = buildTime;
+ RootDirectory.Flags = FileFlags.Directory;
+ RootDirectory.FileUnitSize = 0;
+ RootDirectory.InterleaveGapSize = 0;
+ RootDirectory.VolumeSequenceNumber = 1;
+ RootDirectory.FileIdentifier = "\0";
+ VolumeSetIdentifier = string.Empty;
+ PublisherIdentifier = string.Empty;
+ DataPreparerIdentifier = string.Empty;
+ ApplicationIdentifier = string.Empty;
+ CopyrightFileIdentifier = string.Empty;
+ AbstractFileIdentifier = string.Empty;
+ BibliographicFileIdentifier = string.Empty;
+ CreationDateAndTime = buildTime;
+ ModificationDateAndTime = buildTime;
+ ExpirationDateAndTime = DateTime.MinValue;
+ EffectiveDateAndTime = buildTime;
+ FileStructureVersion = 1; // V1
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/DirectoryExtent.cs b/DiscUtils/Iso9660Ps1/DirectoryExtent.cs
new file mode 100644
index 0000000..3c3b1f2
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/DirectoryExtent.cs
@@ -0,0 +1,71 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class DirectoryExtent : BuilderExtent
+ {
+ private readonly BuildDirectoryInfo _dirInfo;
+ private readonly Encoding _enc;
+ private readonly Dictionary _locationTable;
+
+ private byte[] _readCache;
+
+ public DirectoryExtent(BuildDirectoryInfo dirInfo, Dictionary locationTable,
+ Encoding enc, long start)
+ : base(start, dirInfo.GetDataSize(enc))
+ {
+ _dirInfo = dirInfo;
+ _locationTable = locationTable;
+ _enc = enc;
+ }
+
+ public override void Dispose() {}
+
+ public override void PrepareForRead()
+ {
+ _readCache = new byte[Length];
+ _dirInfo.Write(_readCache, 0, _locationTable, _enc);
+ }
+
+ public override int Read(long diskOffset, byte[] buffer, int offset, int count)
+ {
+ long relPos = diskOffset - Start;
+
+ int numRead = (int)Math.Min(count, _readCache.Length - relPos);
+
+ Array.Copy(_readCache, (int)relPos, buffer, offset, numRead);
+
+ return numRead;
+ }
+
+ public override void DisposeReadState()
+ {
+ _readCache = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/DirectoryRecord.cs b/DiscUtils/Iso9660Ps1/DirectoryRecord.cs
new file mode 100644
index 0000000..fb6c9ad
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/DirectoryRecord.cs
@@ -0,0 +1,114 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class DirectoryRecord
+ {
+ public uint DataLength;
+ public byte ExtendedAttributeRecordLength;
+ public string FileIdentifier;
+ public byte FileUnitSize;
+ public FileFlags Flags;
+ public byte InterleaveGapSize;
+ public uint LocationOfExtent;
+ public DateTime RecordingDateAndTime;
+ public byte[] SystemUseData;
+ public ushort VolumeSequenceNumber;
+
+ public static int ReadFrom(byte[] src, int offset, Encoding enc, out DirectoryRecord record)
+ {
+ int length = src[offset + 0];
+
+ record = new DirectoryRecord();
+ record.ExtendedAttributeRecordLength = src[offset + 1];
+ record.LocationOfExtent = IsoUtilities.ToUInt32FromBoth(src, offset + 2);
+ record.DataLength = IsoUtilities.ToUInt32FromBoth(src, offset + 10);
+ record.RecordingDateAndTime = IsoUtilities.ToUTCDateTimeFromDirectoryTime(src, offset + 18);
+ record.Flags = (FileFlags)src[offset + 25];
+ record.FileUnitSize = src[offset + 26];
+ record.InterleaveGapSize = src[offset + 27];
+ record.VolumeSequenceNumber = IsoUtilities.ToUInt16FromBoth(src, offset + 28);
+ byte lengthOfFileIdentifier = src[offset + 32];
+ record.FileIdentifier = IsoUtilities.ReadChars(src, offset + 33, lengthOfFileIdentifier, enc);
+
+ int padding = (lengthOfFileIdentifier & 1) == 0 ? 1 : 0;
+ int startSystemArea = lengthOfFileIdentifier + padding + 33;
+ int lenSystemArea = length - startSystemArea;
+ if (lenSystemArea > 0)
+ {
+ record.SystemUseData = new byte[lenSystemArea];
+ Array.Copy(src, offset + startSystemArea, record.SystemUseData, 0, lenSystemArea);
+ }
+
+ return length;
+ }
+
+ public static uint CalcLength(string name, Encoding enc)
+ {
+ int nameBytes;
+ if (name.Length == 1 && name[0] <= 1)
+ {
+ nameBytes = 1;
+ }
+ else
+ {
+ nameBytes = enc.GetByteCount(name);
+ }
+
+ return (uint)(33 + nameBytes + ((nameBytes & 0x1) == 0 ? 1 : 0));
+ }
+
+ internal int WriteTo(byte[] buffer, int offset, Encoding enc)
+ {
+ uint length = CalcLength(FileIdentifier, enc);
+ buffer[offset] = (byte)length;
+ buffer[offset + 1] = ExtendedAttributeRecordLength;
+ IsoUtilities.ToBothFromUInt32(buffer, offset + 2, LocationOfExtent);
+ IsoUtilities.ToBothFromUInt32(buffer, offset + 10, DataLength);
+ IsoUtilities.ToDirectoryTimeFromUTC(buffer, offset + 18, RecordingDateAndTime);
+ buffer[offset + 25] = (byte)Flags;
+ buffer[offset + 26] = FileUnitSize;
+ buffer[offset + 27] = InterleaveGapSize;
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 28, VolumeSequenceNumber);
+ byte lengthOfFileIdentifier;
+
+ if (FileIdentifier.Length == 1 && FileIdentifier[0] <= 1)
+ {
+ buffer[offset + 33] = (byte)FileIdentifier[0];
+ lengthOfFileIdentifier = 1;
+ }
+ else
+ {
+ lengthOfFileIdentifier =
+ (byte)
+ IsoUtilities.WriteString(buffer, offset + 33, (int)(length - 33), false, FileIdentifier, enc);
+ }
+
+ buffer[offset + 32] = lengthOfFileIdentifier;
+ return (int)length;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/ExtentStream.cs b/DiscUtils/Iso9660Ps1/ExtentStream.cs
new file mode 100644
index 0000000..80e4880
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/ExtentStream.cs
@@ -0,0 +1,125 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class ExtentStream : Stream
+ {
+ private readonly uint _dataLength;
+ private readonly byte _fileUnitSize;
+ private readonly byte _interleaveGapSize;
+
+ private readonly Stream _isoStream;
+ private long _position;
+
+ private readonly uint _startBlock;
+ private readonly int _sectorSize;
+
+ public ExtentStream(Stream isoStream, uint startBlock, uint dataLength, byte fileUnitSize,
+ byte interleaveGapSize, int sectorSize)
+ {
+ _isoStream = isoStream;
+ _startBlock = startBlock;
+ _dataLength = dataLength;
+ _fileUnitSize = fileUnitSize;
+ _interleaveGapSize = interleaveGapSize;
+ _sectorSize = sectorSize;
+
+ if (_fileUnitSize != 0 || _interleaveGapSize != 0)
+ {
+ throw new NotSupportedException("Non-contiguous extents not supported");
+ }
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return true; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return false; }
+ }
+
+ public override long Length
+ {
+ get { return _dataLength; }
+ }
+
+ public override long Position
+ {
+ get { return _position; }
+ set { _position = value; }
+ }
+
+ public override void Flush() {}
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (_position > _dataLength)
+ {
+ return 0;
+ }
+
+ int toRead = (int)Math.Min((uint)count, _dataLength - _position);
+
+ _isoStream.Position = _position + _startBlock * (long)_sectorSize;
+ int numRead = _isoStream.Read(buffer, offset, toRead);
+ _position += numRead;
+ return numRead;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ long newPos = offset;
+ if (origin == SeekOrigin.Current)
+ {
+ newPos += _position;
+ }
+ else if (origin == SeekOrigin.End)
+ {
+ newPos += _dataLength;
+ }
+
+ _position = newPos;
+ return newPos;
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/File.cs b/DiscUtils/Iso9660Ps1/File.cs
new file mode 100644
index 0000000..32514fe
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/File.cs
@@ -0,0 +1,119 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using DiscUtils.Vfs;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class File : IVfsFile
+ {
+ protected IsoContext _context;
+ protected ReaderDirEntry _dirEntry;
+
+ public File(IsoContext context, ReaderDirEntry dirEntry)
+ {
+ _context = context;
+ _dirEntry = dirEntry;
+ }
+
+ public virtual byte[] SystemUseData
+ {
+ get { return _dirEntry.Record.SystemUseData; }
+ }
+
+ public UnixFileSystemInfo UnixFileInfo
+ {
+ get
+ {
+ if (!_context.SuspDetected || string.IsNullOrEmpty(_context.RockRidgeIdentifier))
+ {
+ throw new InvalidOperationException("No RockRidge file information available");
+ }
+
+ SuspRecords suspRecords = new SuspRecords(_context, SystemUseData, 0);
+
+ PosixFileInfoSystemUseEntry pfi =
+ suspRecords.GetEntry(_context.RockRidgeIdentifier, "PX");
+ if (pfi != null)
+ {
+ return new UnixFileSystemInfo
+ {
+ FileType = (UnixFileType)((pfi.FileMode >> 12) & 0xff),
+ Permissions = (UnixFilePermissions)(pfi.FileMode & 0xfff),
+ UserId = (int)pfi.UserId,
+ GroupId = (int)pfi.GroupId,
+ Inode = pfi.Inode,
+ LinkCount = (int)pfi.NumLinks
+ };
+ }
+
+ throw new InvalidOperationException("No RockRidge file information available for this file");
+ }
+ }
+
+ public DateTime LastAccessTimeUtc
+ {
+ get { return _dirEntry.LastAccessTimeUtc; }
+
+ set { throw new NotSupportedException(); }
+ }
+
+ public DateTime LastWriteTimeUtc
+ {
+ get { return _dirEntry.LastWriteTimeUtc; }
+
+ set { throw new NotSupportedException(); }
+ }
+
+ public DateTime CreationTimeUtc
+ {
+ get { return _dirEntry.CreationTimeUtc; }
+
+ set { throw new NotSupportedException(); }
+ }
+
+ public FileAttributes FileAttributes
+ {
+ get { return _dirEntry.FileAttributes; }
+
+ set { throw new NotSupportedException(); }
+ }
+
+ public long FileLength
+ {
+ get { return _dirEntry.Record.DataLength; }
+ }
+
+ public IBuffer FileContent
+ {
+ get
+ {
+ ExtentStream es = new ExtentStream(_context.DataStream, _dirEntry.Record.LocationOfExtent,
+ _dirEntry.Record.DataLength, _dirEntry.Record.FileUnitSize, _dirEntry.Record.InterleaveGapSize, _context.SectorSize);
+ return new StreamBuffer(es, Ownership.Dispose);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/FileExtent.cs b/DiscUtils/Iso9660Ps1/FileExtent.cs
new file mode 100644
index 0000000..dbff57a
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/FileExtent.cs
@@ -0,0 +1,85 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.IO;
+using System.Text;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class FileExtent : BuilderExtent
+ {
+ private readonly BuildFileInfo _fileInfo;
+
+ private Stream _readStream;
+
+ public FileExtent(BuildFileInfo fileInfo, long start)
+ : base(start, fileInfo.GetDataSize(Encoding.ASCII))
+ {
+ _fileInfo = fileInfo;
+ }
+
+ public override void Dispose()
+ {
+ if (_readStream != null)
+ {
+ _fileInfo.CloseStream(_readStream);
+ _readStream = null;
+ }
+ }
+
+ public override void PrepareForRead()
+ {
+ _readStream = _fileInfo.OpenStream();
+ }
+
+ public override int Read(long diskOffset, byte[] block, int offset, int count)
+ {
+ long relPos = diskOffset - Start;
+ int totalRead = 0;
+
+ // Don't arbitrarily set position, just in case stream implementation is
+ // non-seeking, and we're doing sequential reads
+ if (_readStream.Position != relPos)
+ {
+ _readStream.Position = relPos;
+ }
+
+ // Read up to EOF
+ int numRead = _readStream.Read(block, offset, count);
+ totalRead += numRead;
+ while (numRead > 0 && totalRead < count)
+ {
+ numRead = _readStream.Read(block, offset + totalRead, count - totalRead);
+ totalRead += numRead;
+ }
+
+ return totalRead;
+ }
+
+ public override void DisposeReadState()
+ {
+ _fileInfo.CloseStream(_readStream);
+ _readStream = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/FileFlags.cs b/DiscUtils/Iso9660Ps1/FileFlags.cs
new file mode 100644
index 0000000..b350c27
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/FileFlags.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ [Flags]
+ internal enum FileFlags : byte
+ {
+ None = 0x00,
+ Hidden = 0x01,
+ Directory = 0x02,
+ AssociatedFile = 0x04,
+ Record = 0x08,
+ Protection = 0x10,
+ MultiExtent = 0x80
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Iso9660Variant.cs b/DiscUtils/Iso9660Ps1/Iso9660Variant.cs
new file mode 100644
index 0000000..fd76c2f
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Iso9660Variant.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ ///
+ /// Enumeration of known file system variants.
+ ///
+ ///
+ /// ISO9660 has a number of significant limitations, and over time
+ /// multiple schemes have been devised for extending the standard
+ /// to support the richer file system semantics typical of most modern
+ /// operating systems. These variants differ functionally and (in the
+ /// case of RockRidge) may represent a logically different directory
+ /// hierarchy to that encoded in the vanilla iso9660 standard.
+ /// Use this enum to control which variants to honour / prefer
+ /// when accessing an ISO image.
+ ///
+ public enum Iso9660Variant
+ {
+ ///
+ /// No known variant.
+ ///
+ None,
+
+ ///
+ /// Vanilla ISO9660.
+ ///
+ Iso9660,
+
+ ///
+ /// Joliet file system (Windows).
+ ///
+ Joliet,
+
+ ///
+ /// Rock Ridge (Unix).
+ ///
+ RockRidge
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/IsoContext.cs b/DiscUtils/Iso9660Ps1/IsoContext.cs
new file mode 100644
index 0000000..318f207
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/IsoContext.cs
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using System.IO;
+using DiscUtils.Vfs;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class IsoContext : VfsContext
+ {
+ public IsoContext(int sectorSize)
+ {
+ SectorSize = sectorSize;
+ }
+
+ public Stream DataStream { get; set; }
+
+ public string RockRidgeIdentifier { get; set; }
+
+ public bool SuspDetected { get; set; }
+
+ public int SectorSize { get; set; }
+
+ public List SuspExtensions { get; set; }
+
+ public int SuspSkipBytes { get; set; }
+ public CommonVolumeDescriptor VolumeDescriptor { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/IsoUtilities.cs b/DiscUtils/Iso9660Ps1/IsoUtilities.cs
new file mode 100644
index 0000000..05e4398
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/IsoUtilities.cs
@@ -0,0 +1,467 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal static class IsoUtilities
+ {
+ //public const int SectorSize = 2048;
+
+ public static uint ToUInt32FromBoth(byte[] data, int offset)
+ {
+ return EndianUtilities.ToUInt32LittleEndian(data, offset);
+ }
+
+ public static ushort ToUInt16FromBoth(byte[] data, int offset)
+ {
+ return EndianUtilities.ToUInt16LittleEndian(data, offset);
+ }
+
+ internal static void ToBothFromUInt32(byte[] buffer, int offset, uint value)
+ {
+ EndianUtilities.WriteBytesLittleEndian(value, buffer, offset);
+ EndianUtilities.WriteBytesBigEndian(value, buffer, offset + 4);
+ }
+
+ internal static void ToBothFromUInt16(byte[] buffer, int offset, ushort value)
+ {
+ EndianUtilities.WriteBytesLittleEndian(value, buffer, offset);
+ EndianUtilities.WriteBytesBigEndian(value, buffer, offset + 2);
+ }
+
+ internal static void ToBytesFromUInt32(byte[] buffer, int offset, uint value)
+ {
+ EndianUtilities.WriteBytesLittleEndian(value, buffer, offset);
+ }
+
+ internal static void ToBytesFromUInt16(byte[] buffer, int offset, ushort value)
+ {
+ EndianUtilities.WriteBytesLittleEndian(value, buffer, offset);
+ }
+
+ internal static void WriteAChars(byte[] buffer, int offset, int numBytes, string str)
+ {
+ // Validate string
+ if (!IsValidAString(str))
+ {
+ throw new IOException("Attempt to write string with invalid a-characters");
+ }
+
+ ////WriteASCII(buffer, offset, numBytes, true, str);
+ WriteString(buffer, offset, numBytes, true, str, Encoding.ASCII);
+ }
+
+ internal static void WriteDChars(byte[] buffer, int offset, int numBytes, string str)
+ {
+ // Validate string
+ if (!IsValidDString(str))
+ {
+ throw new IOException("Attempt to write string with invalid d-characters");
+ }
+
+ ////WriteASCII(buffer, offset, numBytes, true, str);
+ WriteString(buffer, offset, numBytes, true, str, Encoding.ASCII);
+ }
+
+ internal static void WriteA1Chars(byte[] buffer, int offset, int numBytes, string str, Encoding enc)
+ {
+ // Validate string
+ if (!IsValidAString(str))
+ {
+ throw new IOException("Attempt to write string with invalid a-characters");
+ }
+
+ WriteString(buffer, offset, numBytes, true, str, enc);
+ }
+
+ internal static void WriteD1Chars(byte[] buffer, int offset, int numBytes, string str, Encoding enc)
+ {
+ // Validate string
+ if (!IsValidDString(str))
+ {
+ throw new IOException("Attempt to write string with invalid d-characters");
+ }
+
+ WriteString(buffer, offset, numBytes, true, str, enc);
+ }
+
+ internal static string ReadChars(byte[] buffer, int offset, int numBytes, Encoding enc)
+ {
+ char[] chars;
+
+ // Special handling for 'magic' names '\x00' and '\x01', which indicate root and parent, respectively
+ if (numBytes == 1)
+ {
+ chars = new char[1];
+ chars[0] = (char)buffer[offset];
+ }
+ else
+ {
+ Decoder decoder = enc.GetDecoder();
+ chars = new char[decoder.GetCharCount(buffer, offset, numBytes, false)];
+ decoder.GetChars(buffer, offset, numBytes, chars, 0, false);
+ }
+
+ return new string(chars).TrimEnd(' ');
+ }
+
+#if false
+ public static byte WriteFileName(byte[] buffer, int offset, int numBytes, string str, Encoding enc)
+ {
+ if (numBytes > 255 || numBytes < 0)
+ {
+ throw new ArgumentOutOfRangeException("numBytes", "Attempt to write overlength or underlength file name");
+ }
+
+ // Validate string
+ if (!isValidFileName(str))
+ {
+ throw new IOException("Attempt to write string with invalid file name characters");
+ }
+
+ return (byte)WriteString(buffer, offset, numBytes, false, str, enc);
+ }
+
+ public static byte WriteDirectoryName(byte[] buffer, int offset, int numBytes, string str, Encoding enc)
+ {
+ if (numBytes > 255 || numBytes < 0)
+ {
+ throw new ArgumentOutOfRangeException("numBytes", "Attempt to write overlength or underlength directory name");
+ }
+
+ // Validate string
+ if (!isValidDirectoryName(str))
+ {
+ throw new IOException("Attempt to write string with invalid directory name characters");
+ }
+
+ return (byte)WriteString(buffer, offset, numBytes, false, str, enc);
+ }
+#endif
+
+ internal static int WriteString(byte[] buffer, int offset, int numBytes, bool pad, string str, Encoding enc)
+ {
+ return WriteString(buffer, offset, numBytes, pad, str, enc, false);
+ }
+
+ internal static int WriteString(byte[] buffer, int offset, int numBytes, bool pad, string str, Encoding enc,
+ bool canTruncate)
+ {
+ Encoder encoder = enc.GetEncoder();
+
+ string paddedString = pad ? str + new string(' ', numBytes) : str;
+
+ // Assumption: never less than one byte per character
+
+ int charsUsed;
+ int bytesUsed;
+ bool completed;
+ encoder.Convert(paddedString.ToCharArray(), 0, paddedString.Length, buffer, offset, numBytes, false,
+ out charsUsed, out bytesUsed, out completed);
+
+ if (!canTruncate && charsUsed < str.Length)
+ {
+ throw new IOException("Failed to write entire string");
+ }
+
+ return bytesUsed;
+ }
+
+ internal static bool IsValidAString(string str)
+ {
+ for (int i = 0; i < str.Length; ++i)
+ {
+ if (!(
+ (str[i] >= ' ' && str[i] <= '\"')
+ || (str[i] >= '%' && str[i] <= '/')
+ || (str[i] >= ':' && str[i] <= '?')
+ || (str[i] >= '0' && str[i] <= '9')
+ || (str[i] >= 'A' && str[i] <= 'Z')
+ || (str[i] == '_')))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal static bool IsValidDString(string str)
+ {
+ for (int i = 0; i < str.Length; ++i)
+ {
+ if (!IsValidDChar(str[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal static bool IsValidDChar(char ch)
+ {
+ return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch == '_');
+ }
+
+ internal static bool IsValidFileName(string str)
+ {
+ for (int i = 0; i < str.Length; ++i)
+ {
+ if (
+ !((str[i] >= '0' && str[i] <= '9') || (str[i] >= 'A' && str[i] <= 'Z') || (str[i] == '_') ||
+ (str[i] == '.') || (str[i] == ';')))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal static bool IsValidDirectoryName(string str)
+ {
+ if (str.Length == 1 && (str[0] == 0 || str[0] == 1))
+ {
+ return true;
+ }
+ return IsValidDString(str);
+ }
+
+ internal static string NormalizeFileName(string name)
+ {
+ string[] parts = SplitFileName(name);
+ return parts[0] + '.' + parts[1] + ';' + parts[2];
+ }
+
+ internal static string[] SplitFileName(string name)
+ {
+ string[] parts = { name, string.Empty, "1" };
+
+ if (name.Contains("."))
+ {
+ int endOfFilePart = name.IndexOf('.');
+ parts[0] = name.Substring(0, endOfFilePart);
+ if (name.Contains(";"))
+ {
+ int verSep = name.IndexOf(';', endOfFilePart + 1);
+ parts[1] = name.Substring(endOfFilePart + 1, verSep - (endOfFilePart + 1));
+ parts[2] = name.Substring(verSep + 1);
+ }
+ else
+ {
+ parts[1] = name.Substring(endOfFilePart + 1);
+ }
+ }
+ else
+ {
+ if (name.Contains(";"))
+ {
+ int verSep = name.IndexOf(';');
+ parts[0] = name.Substring(0, verSep);
+ parts[2] = name.Substring(verSep + 1);
+ }
+ }
+
+ ushort ver;
+ if (!ushort.TryParse(parts[2], out ver) || ver > 32767 || ver < 1)
+ {
+ ver = 1;
+ }
+
+ parts[2] = string.Format(CultureInfo.InvariantCulture, "{0}", ver);
+
+ return parts;
+ }
+
+ ///
+ /// Converts a DirectoryRecord time to UTC.
+ ///
+ /// Buffer containing the time data.
+ /// Offset in buffer of the time data.
+ /// The time in UTC.
+ internal static DateTime ToUTCDateTimeFromDirectoryTime(byte[] data, int offset)
+ {
+ try
+ {
+ DateTime relTime = new DateTime(
+ 1900 + data[offset],
+ data[offset + 1],
+ data[offset + 2],
+ data[offset + 3],
+ data[offset + 4],
+ data[offset + 5],
+ DateTimeKind.Utc);
+ return relTime - TimeSpan.FromMinutes(15 * (sbyte)data[offset + 6]);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ // In case the ISO has a bad date encoded, we'll just fall back to using a fixed date
+ return DateTime.MinValue;
+ }
+ }
+
+ internal static void ToDirectoryTimeFromUTC(byte[] data, int offset, DateTime dateTime)
+ {
+ if (dateTime == DateTime.MinValue)
+ {
+ Array.Clear(data, offset, 7);
+ }
+ else
+ {
+ if (dateTime.Year < 1900)
+ {
+ throw new IOException("Year is out of range");
+ }
+
+ data[offset] = (byte)(dateTime.Year - 1900);
+ data[offset + 1] = (byte)dateTime.Month;
+ data[offset + 2] = (byte)dateTime.Day;
+ data[offset + 3] = (byte)dateTime.Hour;
+ data[offset + 4] = (byte)dateTime.Minute;
+ data[offset + 5] = (byte)dateTime.Second;
+ data[offset + 6] = 0;
+ }
+ }
+
+ internal static DateTime ToDateTimeFromVolumeDescriptorTime(byte[] data, int offset)
+ {
+ bool allNull = true;
+ for (int i = 0; i < 16; ++i)
+ {
+ if (data[offset + i] != (byte)'0' && data[offset + i] != 0)
+ {
+ allNull = false;
+ break;
+ }
+ }
+
+ if (allNull)
+ {
+ return DateTime.MinValue;
+ }
+
+ string strForm = Encoding.ASCII.GetString(data, offset, 16);
+
+ // Work around bugs in burning software that may use zero bytes (rather than '0' characters)
+ strForm = strForm.Replace('\0', '0');
+
+ int year = SafeParseInt(1, 9999, strForm.Substring(0, 4));
+ int month = SafeParseInt(1, 12, strForm.Substring(4, 2));
+ int day = SafeParseInt(1, 31, strForm.Substring(6, 2));
+ int hour = SafeParseInt(0, 23, strForm.Substring(8, 2));
+ int min = SafeParseInt(0, 59, strForm.Substring(10, 2));
+ int sec = SafeParseInt(0, 59, strForm.Substring(12, 2));
+ int hundredths = SafeParseInt(0, 99, strForm.Substring(14, 2));
+
+ try
+ {
+ DateTime time = new DateTime(year, month, day, hour, min, sec, hundredths * 10, DateTimeKind.Utc);
+ return time - TimeSpan.FromMinutes(15 * (sbyte)data[offset + 16]);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ return DateTime.MinValue;
+ }
+ }
+
+ internal static void ToVolumeDescriptorTimeFromUTC(byte[] buffer, int offset, DateTime dateTime)
+ {
+ if (dateTime == DateTime.MinValue)
+ {
+ for (int i = offset; i < offset + 16; ++i)
+ {
+ buffer[i] = (byte)'0';
+ }
+
+ buffer[offset + 16] = 0;
+ return;
+ }
+
+ string strForm = dateTime.ToString("yyyyMMddHHmmssff", CultureInfo.InvariantCulture);
+ EndianUtilities.StringToBytes(strForm, buffer, offset, 16);
+ buffer[offset + 16] = 0;
+ }
+
+ internal static void EncodingToBytes(Encoding enc, byte[] data, int offset)
+ {
+ Array.Clear(data, offset, 32);
+ if (enc == Encoding.ASCII)
+ {
+ // Nothing to do
+ }
+ else if (enc == Encoding.BigEndianUnicode)
+ {
+ data[offset + 0] = 0x25;
+ data[offset + 1] = 0x2F;
+ data[offset + 2] = 0x45;
+ }
+ else
+ {
+ throw new ArgumentException("Unrecognized character encoding");
+ }
+ }
+
+ internal static Encoding EncodingFromBytes(byte[] data, int offset)
+ {
+ Encoding enc = Encoding.ASCII;
+ if (data[offset + 0] == 0x25 && data[offset + 1] == 0x2F
+ && (data[offset + 2] == 0x40 || data[offset + 2] == 0x43 || data[offset + 2] == 0x45))
+ {
+ // I.e. this is a joliet disc!
+ enc = Encoding.BigEndianUnicode;
+ }
+
+ return enc;
+ }
+
+ internal static bool IsSpecialDirectory(DirectoryRecord r)
+ {
+ return r.FileIdentifier == "\0" || r.FileIdentifier == "\x01";
+ }
+
+ private static int SafeParseInt(int minVal, int maxVal, string str)
+ {
+ int val;
+ if (!int.TryParse(str, out val))
+ {
+ return minVal;
+ }
+
+ if (val < minVal)
+ {
+ return minVal;
+ }
+ if (val > maxVal)
+ {
+ return maxVal;
+ }
+ return val;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/PathTable.cs b/DiscUtils/Iso9660Ps1/PathTable.cs
new file mode 100644
index 0000000..e314cd4
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/PathTable.cs
@@ -0,0 +1,100 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class PathTable : BuilderExtent
+ {
+ private readonly bool _byteSwap;
+ private readonly List _dirs;
+ private readonly Encoding _enc;
+ private readonly Dictionary _locations;
+
+ private byte[] _readCache;
+
+ public PathTable(bool byteSwap, Encoding enc, List dirs,
+ Dictionary locations, long start)
+ : base(start, CalcLength(enc, dirs))
+ {
+ _byteSwap = byteSwap;
+ _enc = enc;
+ _dirs = dirs;
+ _locations = locations;
+ }
+
+ public override void Dispose() {}
+
+ public override void PrepareForRead()
+ {
+ _readCache = new byte[Length];
+ int pos = 0;
+
+ List sortedList = new List(_dirs);
+ sortedList.Sort(BuildDirectoryInfo.PathTableSortComparison);
+
+ Dictionary dirNumbers = new Dictionary(_dirs.Count);
+ ushort i = 1;
+ foreach (BuildDirectoryInfo di in sortedList)
+ {
+ dirNumbers[di] = i++;
+ PathTableRecord ptr = new PathTableRecord();
+ ptr.DirectoryIdentifier = di.PickName(null, _enc);
+ ptr.LocationOfExtent = _locations[di];
+ ptr.ParentDirectoryNumber = dirNumbers[di.Parent];
+
+ pos += ptr.Write(_byteSwap, _enc, _readCache, pos);
+ }
+ }
+
+ public override int Read(long diskOffset, byte[] buffer, int offset, int count)
+ {
+ long relPos = diskOffset - Start;
+
+ int numRead = (int)Math.Min(count, _readCache.Length - relPos);
+
+ Array.Copy(_readCache, (int)relPos, buffer, offset, numRead);
+
+ return numRead;
+ }
+
+ public override void DisposeReadState()
+ {
+ _readCache = null;
+ }
+
+ private static uint CalcLength(Encoding enc, List dirs)
+ {
+ uint length = 0;
+ foreach (BuildDirectoryInfo di in dirs)
+ {
+ length += di.GetPathTableEntrySize(enc);
+ }
+
+ return length;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/PathTableRecord.cs b/DiscUtils/Iso9660Ps1/PathTableRecord.cs
new file mode 100644
index 0000000..0480e18
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/PathTableRecord.cs
@@ -0,0 +1,71 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Text;
+using DiscUtils.Internal;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal struct PathTableRecord
+ {
+ ////public byte ExtendedAttributeRecordLength;
+ public uint LocationOfExtent;
+ public ushort ParentDirectoryNumber;
+ public string DirectoryIdentifier;
+
+ ////public static int ReadFrom(byte[] src, int offset, bool byteSwap, Encoding enc, out PathTableRecord record)
+ ////{
+ //// byte directoryIdentifierLength = src[offset + 0];
+ //// record.ExtendedAttributeRecordLength = src[offset + 1];
+ //// record.LocationOfExtent = EndianUtilities.ToUInt32LittleEndian(src, offset + 2);
+ //// record.ParentDirectoryNumber = EndianUtilities.ToUInt16LittleEndian(src, offset + 6);
+ //// record.DirectoryIdentifier = IsoUtilities.ReadChars(src, offset + 8, directoryIdentifierLength, enc);
+ ////
+ //// if (byteSwap)
+ //// {
+ //// record.LocationOfExtent = Utilities.BitSwap(record.LocationOfExtent);
+ //// record.ParentDirectoryNumber = Utilities.BitSwap(record.ParentDirectoryNumber);
+ //// }
+ ////
+ //// return directoryIdentifierLength + 8 + (((directoryIdentifierLength & 1) == 1) ? 1 : 0);
+ ////}
+
+ internal int Write(bool byteSwap, Encoding enc, byte[] buffer, int offset)
+ {
+ int nameBytes = enc.GetByteCount(DirectoryIdentifier);
+
+ buffer[offset + 0] = (byte)nameBytes;
+ buffer[offset + 1] = 0; // ExtendedAttributeRecordLength;
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 2,
+ byteSwap ? Utilities.BitSwap(LocationOfExtent) : LocationOfExtent);
+ IsoUtilities.ToBytesFromUInt16(buffer, offset + 6,
+ byteSwap ? Utilities.BitSwap(ParentDirectoryNumber) : ParentDirectoryNumber);
+ IsoUtilities.WriteString(buffer, offset + 8, nameBytes, false, DirectoryIdentifier, enc);
+ if ((nameBytes & 1) == 1)
+ {
+ buffer[offset + 8 + nameBytes] = 0;
+ }
+
+ return 8 + nameBytes + ((nameBytes & 0x1) == 1 ? 1 : 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptor.cs b/DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptor.cs
new file mode 100644
index 0000000..75be21b
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptor.cs
@@ -0,0 +1,76 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+using DiscUtils.Internal;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class PrimaryVolumeDescriptor : CommonVolumeDescriptor
+ {
+ public PrimaryVolumeDescriptor(byte[] src, int offset)
+ : base(src, offset, Encoding.ASCII) {}
+
+ public PrimaryVolumeDescriptor(
+ uint volumeSpaceSize,
+ uint pathTableSize,
+ uint typeLPathTableLocation,
+ uint typeMPathTableLocation,
+ uint rootDirExtentLocation,
+ uint rootDirDataLength,
+ DateTime buildTime,
+ int sectorSize)
+ : base(
+ VolumeDescriptorType.Primary, 1, volumeSpaceSize, pathTableSize, typeLPathTableLocation,
+ typeMPathTableLocation, rootDirExtentLocation, rootDirDataLength, buildTime, Encoding.ASCII, sectorSize) {}
+
+ internal override void WriteTo(byte[] buffer, int offset)
+ {
+ base.WriteTo(buffer, offset);
+ IsoUtilities.WriteAChars(buffer, offset + 8, 32, SystemIdentifier);
+ IsoUtilities.WriteString(buffer, offset + 40, 32, true, VolumeIdentifier, Encoding.ASCII, true);
+ IsoUtilities.ToBothFromUInt32(buffer, offset + 80, VolumeSpaceSize);
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 120, VolumeSetSize);
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 124, VolumeSequenceNumber);
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 128, LogicalBlockSize);
+ IsoUtilities.ToBothFromUInt32(buffer, offset + 132, PathTableSize);
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 140, TypeLPathTableLocation);
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 144, OptionalTypeLPathTableLocation);
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 148, Utilities.BitSwap(TypeMPathTableLocation));
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 152, Utilities.BitSwap(OptionalTypeMPathTableLocation));
+ RootDirectory.WriteTo(buffer, offset + 156, Encoding.ASCII);
+ IsoUtilities.WriteDChars(buffer, offset + 190, 129, VolumeSetIdentifier);
+ IsoUtilities.WriteAChars(buffer, offset + 318, 129, PublisherIdentifier);
+ IsoUtilities.WriteAChars(buffer, offset + 446, 129, DataPreparerIdentifier);
+ IsoUtilities.WriteAChars(buffer, offset + 574, 129, ApplicationIdentifier);
+ IsoUtilities.WriteDChars(buffer, offset + 702, 37, CopyrightFileIdentifier); // FIXME!!
+ IsoUtilities.WriteDChars(buffer, offset + 739, 37, AbstractFileIdentifier); // FIXME!!
+ IsoUtilities.WriteDChars(buffer, offset + 776, 37, BibliographicFileIdentifier); // FIXME!!
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 813, CreationDateAndTime);
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 830, ModificationDateAndTime);
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 847, ExpirationDateAndTime);
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 864, EffectiveDateAndTime);
+ buffer[offset + 881] = FileStructureVersion;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptorRegion.cs b/DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptorRegion.cs
new file mode 100644
index 0000000..d327ae3
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/PrimaryVolumeDescriptorRegion.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class PrimaryVolumeDescriptorRegion : VolumeDescriptorDiskRegion
+ {
+ private readonly PrimaryVolumeDescriptor _descriptor;
+
+ public PrimaryVolumeDescriptorRegion(PrimaryVolumeDescriptor descriptor, long start, int sectorSize)
+ : base(start, sectorSize)
+ {
+ _descriptor = descriptor;
+ }
+
+ protected override byte[] GetBlockData()
+ {
+ byte[] buffer = new byte[Length];
+ _descriptor.WriteTo(buffer, 0);
+ return buffer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/ReaderDirEntry.cs b/DiscUtils/Iso9660Ps1/ReaderDirEntry.cs
new file mode 100644
index 0000000..3678b95
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/ReaderDirEntry.cs
@@ -0,0 +1,195 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using DiscUtils.Internal;
+using DiscUtils.Streams;
+using DiscUtils.Vfs;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class ReaderDirEntry : VfsDirEntry
+ {
+ private readonly IsoContext _context;
+ private readonly string _fileName;
+ private readonly DirectoryRecord _record;
+
+ public ReaderDirEntry(IsoContext context, DirectoryRecord dirRecord)
+ {
+ _context = context;
+ _record = dirRecord;
+ _fileName = _record.FileIdentifier;
+
+ bool rockRidge = !string.IsNullOrEmpty(_context.RockRidgeIdentifier);
+
+ if (context.SuspDetected && _record.SystemUseData != null)
+ {
+ SuspRecords = new SuspRecords(_context, _record.SystemUseData, 0);
+ }
+
+ if (rockRidge && SuspRecords != null)
+ {
+ // The full name is taken from this record, even if it's a child-link record
+ List nameEntries = SuspRecords.GetEntries(_context.RockRidgeIdentifier, "NM");
+ StringBuilder rrName = new StringBuilder();
+ if (nameEntries != null && nameEntries.Count > 0)
+ {
+ foreach (PosixNameSystemUseEntry nameEntry in nameEntries)
+ {
+ rrName.Append(nameEntry.NameData);
+ }
+
+ _fileName = rrName.ToString();
+ }
+
+ // If this is a Rock Ridge child link, replace the dir record with that from the 'self' record
+ // in the child directory.
+ ChildLinkSystemUseEntry clEntry =
+ SuspRecords.GetEntry(_context.RockRidgeIdentifier, "CL");
+ if (clEntry != null)
+ {
+ _context.DataStream.Position = clEntry.ChildDirLocation * _context.VolumeDescriptor.LogicalBlockSize;
+ byte[] firstSector = StreamUtilities.ReadExact(_context.DataStream,
+ _context.VolumeDescriptor.LogicalBlockSize);
+
+ DirectoryRecord.ReadFrom(firstSector, 0, _context.VolumeDescriptor.CharacterEncoding, out _record);
+ if (_record.SystemUseData != null)
+ {
+ SuspRecords = new SuspRecords(_context, _record.SystemUseData, 0);
+ }
+ }
+ }
+
+ LastAccessTimeUtc = _record.RecordingDateAndTime;
+ LastWriteTimeUtc = _record.RecordingDateAndTime;
+ CreationTimeUtc = _record.RecordingDateAndTime;
+
+ if (rockRidge && SuspRecords != null)
+ {
+ FileTimeSystemUseEntry tfEntry =
+ SuspRecords.GetEntry(_context.RockRidgeIdentifier, "TF");
+
+ if (tfEntry != null)
+ {
+ if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Access) != 0)
+ {
+ LastAccessTimeUtc = tfEntry.AccessTime;
+ }
+
+ if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Modify) != 0)
+ {
+ LastWriteTimeUtc = tfEntry.ModifyTime;
+ }
+
+ if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Creation) != 0)
+ {
+ CreationTimeUtc = tfEntry.CreationTime;
+ }
+ }
+ }
+ }
+
+ public override DateTime CreationTimeUtc { get; }
+
+ public override FileAttributes FileAttributes
+ {
+ get
+ {
+ FileAttributes attrs = 0;
+
+ if (!string.IsNullOrEmpty(_context.RockRidgeIdentifier))
+ {
+ // If Rock Ridge PX info is present, derive the attributes from the RR info.
+ PosixFileInfoSystemUseEntry pfi =
+ SuspRecords.GetEntry(_context.RockRidgeIdentifier, "PX");
+ if (pfi != null)
+ {
+ attrs = Utilities.FileAttributesFromUnixFileType((UnixFileType)((pfi.FileMode >> 12) & 0xF));
+ }
+
+ if (_fileName.StartsWith(".", StringComparison.Ordinal))
+ {
+ attrs |= FileAttributes.Hidden;
+ }
+ }
+
+ attrs |= FileAttributes.ReadOnly;
+
+ if ((_record.Flags & FileFlags.Directory) != 0)
+ {
+ attrs |= FileAttributes.Directory;
+ }
+
+ if ((_record.Flags & FileFlags.Hidden) != 0)
+ {
+ attrs |= FileAttributes.Hidden;
+ }
+
+ return attrs;
+ }
+ }
+
+ public override string FileName
+ {
+ get { return _fileName; }
+ }
+
+ public override bool HasVfsFileAttributes
+ {
+ get { return true; }
+ }
+
+ public override bool HasVfsTimeInfo
+ {
+ get { return true; }
+ }
+
+ public override bool IsDirectory
+ {
+ get { return (_record.Flags & FileFlags.Directory) != 0; }
+ }
+
+ public override bool IsSymlink
+ {
+ get { return false; }
+ }
+
+ public override DateTime LastAccessTimeUtc { get; }
+
+ public override DateTime LastWriteTimeUtc { get; }
+
+ public DirectoryRecord Record
+ {
+ get { return _record; }
+ }
+
+ public SuspRecords SuspRecords { get; }
+
+ public override long UniqueCacheId
+ {
+ get { return ((long)_record.LocationOfExtent << 32) | _record.DataLength; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/ReaderDirectory.cs b/DiscUtils/Iso9660Ps1/ReaderDirectory.cs
new file mode 100644
index 0000000..1e43f49
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/ReaderDirectory.cs
@@ -0,0 +1,130 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using DiscUtils.CoreCompat;
+using DiscUtils.Streams;
+using DiscUtils.Vfs;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class ReaderDirectory : File, IVfsDirectory
+ {
+ private readonly List _records;
+
+ public ReaderDirectory(IsoContext context, ReaderDirEntry dirEntry)
+ : base(context, dirEntry)
+ {
+ byte[] buffer = new byte[context.SectorSize];
+ Stream extent = new ExtentStream(_context.DataStream, dirEntry.Record.LocationOfExtent, uint.MaxValue, 0, 0, context.SectorSize);
+
+ _records = new List();
+
+ uint totalLength = dirEntry.Record.DataLength;
+ uint totalRead = 0;
+ while (totalRead < totalLength)
+ {
+ int bytesRead = (int)Math.Min(buffer.Length, totalLength - totalRead);
+
+ extent.Seek(24, SeekOrigin.Current);
+
+ StreamUtilities.ReadExact(extent, buffer, 0, bytesRead);
+ totalRead += (uint)bytesRead;
+
+ uint pos = 0;
+ while (pos < bytesRead && buffer[pos] != 0)
+ {
+ DirectoryRecord dr;
+ uint length = (uint)DirectoryRecord.ReadFrom(buffer, (int)pos, context.VolumeDescriptor.CharacterEncoding, out dr);
+
+ if (!IsoUtilities.IsSpecialDirectory(dr))
+ {
+ ReaderDirEntry childDirEntry = new ReaderDirEntry(_context, dr);
+
+ if (context.SuspDetected && !string.IsNullOrEmpty(context.RockRidgeIdentifier))
+ {
+ if (childDirEntry.SuspRecords == null || !childDirEntry.SuspRecords.HasEntry(context.RockRidgeIdentifier, "RE"))
+ {
+ _records.Add(childDirEntry);
+ }
+ }
+ else
+ {
+ _records.Add(childDirEntry);
+ }
+ }
+ else if (dr.FileIdentifier == "\0")
+ {
+ Self = new ReaderDirEntry(_context, dr);
+ }
+
+ pos += length;
+ }
+ }
+ }
+
+ public override byte[] SystemUseData
+ {
+ get { return Self.Record.SystemUseData; }
+ }
+
+ public ICollection AllEntries
+ {
+ get { return _records; }
+ }
+
+ public ReaderDirEntry Self { get; }
+
+ public ReaderDirEntry GetEntryByName(string name)
+ {
+ bool anyVerMatch = name.IndexOf(';') < 0;
+ string normName = IsoUtilities.NormalizeFileName(name).ToUpper(CultureInfo.InvariantCulture);
+ if (anyVerMatch)
+ {
+ normName = normName.Substring(0, normName.LastIndexOf(';') + 1);
+ }
+
+ foreach (ReaderDirEntry r in _records)
+ {
+ string toComp = IsoUtilities.NormalizeFileName(r.FileName).ToUpper(CultureInfo.InvariantCulture);
+ if (!anyVerMatch && toComp == normName)
+ {
+ return r;
+ }
+ if (anyVerMatch && toComp.StartsWith(normName, StringComparison.Ordinal))
+ {
+ return r;
+ }
+ }
+
+ return null;
+ }
+
+ public ReaderDirEntry CreateNewFile(string name)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/RockRidge/ChildLinkSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/RockRidge/ChildLinkSystemUseEntry.cs
new file mode 100644
index 0000000..5806eee
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/RockRidge/ChildLinkSystemUseEntry.cs
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class ChildLinkSystemUseEntry : SystemUseEntry
+ {
+ public uint ChildDirLocation;
+
+ public ChildLinkSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 12, 1);
+
+ ChildDirLocation = IsoUtilities.ToUInt32FromBoth(data, offset + 4);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/RockRidge/FileTimeSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/RockRidge/FileTimeSystemUseEntry.cs
new file mode 100644
index 0000000..d8e9780
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/RockRidge/FileTimeSystemUseEntry.cs
@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class FileTimeSystemUseEntry : SystemUseEntry
+ {
+ [Flags]
+ public enum Timestamps : byte
+ {
+ None = 0x00,
+ Creation = 0x01,
+ Modify = 0x02,
+ Access = 0x04,
+ Attributes = 0x08,
+ Backup = 0x10,
+ Expiration = 0x20,
+ Effective = 0x40
+ }
+
+ public DateTime AccessTime;
+ public DateTime AttributesTime;
+ public DateTime BackupTime;
+ public DateTime CreationTime;
+ public DateTime EffectiveTime;
+ public DateTime ExpirationTime;
+ public DateTime ModifyTime;
+ public Timestamps TimestampsPresent = Timestamps.None;
+
+ public FileTimeSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 5, 1);
+
+ byte flags = data[offset + 4];
+
+ bool longForm = (flags & 0x80) != 0;
+ int fieldLen = longForm ? 17 : 7;
+
+ TimestampsPresent = (Timestamps)(flags & 0x7F);
+
+ int pos = offset + 5;
+
+ CreationTime = ReadTimestamp(Timestamps.Creation, data, longForm, ref pos);
+ ModifyTime = ReadTimestamp(Timestamps.Modify, data, longForm, ref pos);
+ AccessTime = ReadTimestamp(Timestamps.Access, data, longForm, ref pos);
+ AttributesTime = ReadTimestamp(Timestamps.Attributes, data, longForm, ref pos);
+ BackupTime = ReadTimestamp(Timestamps.Backup, data, longForm, ref pos);
+ ExpirationTime = ReadTimestamp(Timestamps.Expiration, data, longForm, ref pos);
+ EffectiveTime = ReadTimestamp(Timestamps.Effective, data, longForm, ref pos);
+ }
+
+ private DateTime ReadTimestamp(Timestamps timestamp, byte[] data, bool longForm, ref int pos)
+ {
+ DateTime result = DateTime.MinValue;
+
+ if ((TimestampsPresent & timestamp) != 0)
+ {
+ if (longForm)
+ {
+ result = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(data, pos);
+ pos += 17;
+ }
+ else
+ {
+ result = IsoUtilities.ToUTCDateTimeFromDirectoryTime(data, pos);
+ pos += 7;
+ }
+ }
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/RockRidge/PosixFileInfoSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/RockRidge/PosixFileInfoSystemUseEntry.cs
new file mode 100644
index 0000000..aa9cbd4
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/RockRidge/PosixFileInfoSystemUseEntry.cs
@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class PosixFileInfoSystemUseEntry : SystemUseEntry
+ {
+ public uint FileMode;
+ public uint GroupId;
+ public uint Inode;
+ public uint NumLinks;
+ public uint UserId;
+
+ public PosixFileInfoSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 36, 1);
+
+ FileMode = IsoUtilities.ToUInt32FromBoth(data, offset + 4);
+ NumLinks = IsoUtilities.ToUInt32FromBoth(data, offset + 12);
+ UserId = IsoUtilities.ToUInt32FromBoth(data, offset + 20);
+ GroupId = IsoUtilities.ToUInt32FromBoth(data, offset + 28);
+ Inode = 0;
+ if (length >= 44)
+ {
+ Inode = IsoUtilities.ToUInt32FromBoth(data, offset + 36);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/RockRidge/PosixNameSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/RockRidge/PosixNameSystemUseEntry.cs
new file mode 100644
index 0000000..ba32771
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/RockRidge/PosixNameSystemUseEntry.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class PosixNameSystemUseEntry : SystemUseEntry
+ {
+ public byte Flags;
+ public string NameData;
+
+ public PosixNameSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 5, 1);
+
+ Flags = data[offset + 4];
+ NameData = EndianUtilities.BytesToString(data, offset + 5, length - 5);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/RockRidge/RockRidgeExtension.cs b/DiscUtils/Iso9660Ps1/RockRidge/RockRidgeExtension.cs
new file mode 100644
index 0000000..9c2f422
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/RockRidge/RockRidgeExtension.cs
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class RockRidgeExtension : SuspExtension
+ {
+ public RockRidgeExtension(string identifier)
+ {
+ Identifier = identifier;
+ }
+
+ public override string Identifier { get; }
+
+ public override SystemUseEntry Parse(string name, byte length, byte version, byte[] data, int offset, Encoding encoding)
+ {
+ switch (name)
+ {
+ case "PX":
+ return new PosixFileInfoSystemUseEntry(name, length, version, data, offset);
+
+ case "NM":
+ return new PosixNameSystemUseEntry(name, length, version, data, offset);
+
+ case "CL":
+ return new ChildLinkSystemUseEntry(name, length, version, data, offset);
+
+ case "TF":
+ return new FileTimeSystemUseEntry(name, length, version, data, offset);
+
+ default:
+ return new GenericSystemUseEntry(name, length, version, data, offset);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptor.cs b/DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptor.cs
new file mode 100644
index 0000000..719b70b
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptor.cs
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Text;
+using DiscUtils.Internal;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class SupplementaryVolumeDescriptor : CommonVolumeDescriptor
+ {
+ public SupplementaryVolumeDescriptor(byte[] src, int offset)
+ : base(src, offset, IsoUtilities.EncodingFromBytes(src, offset + 88)) {}
+
+ public SupplementaryVolumeDescriptor(
+ uint volumeSpaceSize,
+ uint pathTableSize,
+ uint typeLPathTableLocation,
+ uint typeMPathTableLocation,
+ uint rootDirExtentLocation,
+ uint rootDirDataLength,
+ DateTime buildTime,
+ Encoding enc,
+ int sectorSize)
+ : base(
+ VolumeDescriptorType.Supplementary, 1, volumeSpaceSize, pathTableSize, typeLPathTableLocation,
+ typeMPathTableLocation, rootDirExtentLocation, rootDirDataLength, buildTime, enc, sectorSize) {}
+
+ internal override void WriteTo(byte[] buffer, int offset)
+ {
+ base.WriteTo(buffer, offset);
+ IsoUtilities.WriteA1Chars(buffer, offset + 8, 32, SystemIdentifier, CharacterEncoding);
+ IsoUtilities.WriteString(buffer, offset + 40, 32, true, VolumeIdentifier, CharacterEncoding, true);
+ IsoUtilities.ToBothFromUInt32(buffer, offset + 80, VolumeSpaceSize);
+ IsoUtilities.EncodingToBytes(CharacterEncoding, buffer, offset + 88);
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 120, VolumeSetSize);
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 124, VolumeSequenceNumber);
+ IsoUtilities.ToBothFromUInt16(buffer, offset + 128, LogicalBlockSize);
+ IsoUtilities.ToBothFromUInt32(buffer, offset + 132, PathTableSize);
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 140, TypeLPathTableLocation);
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 144, OptionalTypeLPathTableLocation);
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 148, Utilities.BitSwap(TypeMPathTableLocation));
+ IsoUtilities.ToBytesFromUInt32(buffer, offset + 152, Utilities.BitSwap(OptionalTypeMPathTableLocation));
+ RootDirectory.WriteTo(buffer, offset + 156, CharacterEncoding);
+ IsoUtilities.WriteD1Chars(buffer, offset + 190, 129, VolumeSetIdentifier, CharacterEncoding);
+ IsoUtilities.WriteA1Chars(buffer, offset + 318, 129, PublisherIdentifier, CharacterEncoding);
+ IsoUtilities.WriteA1Chars(buffer, offset + 446, 129, DataPreparerIdentifier, CharacterEncoding);
+ IsoUtilities.WriteA1Chars(buffer, offset + 574, 129, ApplicationIdentifier, CharacterEncoding);
+ IsoUtilities.WriteD1Chars(buffer, offset + 702, 37, CopyrightFileIdentifier, CharacterEncoding); // FIXME!!
+ IsoUtilities.WriteD1Chars(buffer, offset + 739, 37, AbstractFileIdentifier, CharacterEncoding); // FIXME!!
+ IsoUtilities.WriteD1Chars(buffer, offset + 776, 37, BibliographicFileIdentifier, CharacterEncoding);
+
+ // FIXME!!
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 813, CreationDateAndTime);
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 830, ModificationDateAndTime);
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 847, ExpirationDateAndTime);
+ IsoUtilities.ToVolumeDescriptorTimeFromUTC(buffer, offset + 864, EffectiveDateAndTime);
+ buffer[offset + 881] = FileStructureVersion;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptorRegion.cs b/DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptorRegion.cs
new file mode 100644
index 0000000..329f0f5
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/SupplementaryVolumeDescriptorRegion.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class SupplementaryVolumeDescriptorRegion : VolumeDescriptorDiskRegion
+ {
+ private readonly SupplementaryVolumeDescriptor _descriptor;
+
+ public SupplementaryVolumeDescriptorRegion(SupplementaryVolumeDescriptor descriptor, long start, int sectorSize)
+ : base(start, sectorSize)
+ {
+ _descriptor = descriptor;
+ }
+
+ protected override byte[] GetBlockData()
+ {
+ byte[] buffer = new byte[Length];
+ _descriptor.WriteTo(buffer, 0);
+ return buffer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/ContinuationSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/ContinuationSystemUseEntry.cs
new file mode 100644
index 0000000..23ea48f
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/ContinuationSystemUseEntry.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class ContinuationSystemUseEntry : SystemUseEntry
+ {
+ public uint Block;
+ public uint BlockOffset;
+ public uint Length;
+
+ public ContinuationSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 28, 1);
+
+ Block = IsoUtilities.ToUInt32FromBoth(data, offset + 4);
+ BlockOffset = IsoUtilities.ToUInt32FromBoth(data, offset + 12);
+ Length = IsoUtilities.ToUInt32FromBoth(data, offset + 20);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/ExtensionSelectSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/ExtensionSelectSystemUseEntry.cs
new file mode 100644
index 0000000..9001da4
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/ExtensionSelectSystemUseEntry.cs
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class ExtensionSelectSystemUseEntry : SystemUseEntry
+ {
+ public byte SelectedExtension;
+
+ public ExtensionSelectSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 5, 1);
+
+ SelectedExtension = data[offset + 4];
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/ExtensionSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/ExtensionSystemUseEntry.cs
new file mode 100644
index 0000000..dc6d382
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/ExtensionSystemUseEntry.cs
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.IO;
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class ExtensionSystemUseEntry : SystemUseEntry
+ {
+ public string ExtensionDescriptor;
+ public string ExtensionIdentifier;
+ public string ExtensionSource;
+ public byte ExtensionVersion;
+
+ public ExtensionSystemUseEntry(string name, byte length, byte version, byte[] data, int offset, Encoding encoding)
+ {
+ CheckAndSetCommonProperties(name, length, version, 8, 1);
+
+ int lenId = data[offset + 4];
+ int lenDescriptor = data[offset + 5];
+ int lenSource = data[offset + 6];
+
+ ExtensionVersion = data[offset + 7];
+
+ if (length < 8 + lenId + lenDescriptor + lenSource)
+ {
+ throw new InvalidDataException("Invalid SUSP ER entry - too short, only " + length + " bytes - expected: " +
+ (8 + lenId + lenDescriptor + lenSource));
+ }
+
+ ExtensionIdentifier = IsoUtilities.ReadChars(data, offset + 8, lenId, encoding);
+ ExtensionDescriptor = IsoUtilities.ReadChars(data, offset + 8 + lenId, lenDescriptor, encoding);
+ ExtensionSource = IsoUtilities.ReadChars(data, offset + 8 + lenId + lenDescriptor, lenSource, encoding);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/GenericSuspExtension.cs b/DiscUtils/Iso9660Ps1/Susp/GenericSuspExtension.cs
new file mode 100644
index 0000000..0b2af9c
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/GenericSuspExtension.cs
@@ -0,0 +1,41 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class GenericSuspExtension : SuspExtension
+ {
+ public GenericSuspExtension(string identifier)
+ {
+ Identifier = identifier;
+ }
+
+ public override string Identifier { get; }
+
+ public override SystemUseEntry Parse(string name, byte length, byte version, byte[] data, int offset, Encoding encoding)
+ {
+ return new GenericSystemUseEntry(name, length, version, data, offset);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/GenericSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/GenericSystemUseEntry.cs
new file mode 100644
index 0000000..e1d95b5
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/GenericSystemUseEntry.cs
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class GenericSystemUseEntry : SystemUseEntry
+ {
+ public byte[] Data;
+
+ public GenericSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 4, 0xFF);
+
+ Data = new byte[length - 4];
+ Array.Copy(data, offset + 4, Data, 0, length - 4);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/PaddingSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/PaddingSystemUseEntry.cs
new file mode 100644
index 0000000..49c2134
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/PaddingSystemUseEntry.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class PaddingSystemUseEntry : SystemUseEntry
+ {
+ public PaddingSystemUseEntry(string name, byte length, byte version)
+ {
+ CheckAndSetCommonProperties(name, length, version, 4, 1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/SharingProtocolSystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/SharingProtocolSystemUseEntry.cs
new file mode 100644
index 0000000..b35520d
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/SharingProtocolSystemUseEntry.cs
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.IO;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class SharingProtocolSystemUseEntry : SystemUseEntry
+ {
+ public byte SystemAreaSkip;
+
+ public SharingProtocolSystemUseEntry(string name, byte length, byte version, byte[] data, int offset)
+ {
+ CheckAndSetCommonProperties(name, length, version, 7, 1);
+
+ if (data[offset + 4] != 0xBE || data[offset + 5] != 0xEF)
+ {
+ throw new InvalidDataException("Invalid SUSP SP entry - invalid checksum bytes");
+ }
+
+ SystemAreaSkip = data[offset + 6];
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/SuspExtension.cs b/DiscUtils/Iso9660Ps1/Susp/SuspExtension.cs
new file mode 100644
index 0000000..fd220b2
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/SuspExtension.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Text;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal abstract class SuspExtension
+ {
+ public abstract string Identifier { get; }
+
+ public abstract SystemUseEntry Parse(string name, byte length, byte version, byte[] data, int offset, Encoding encoding);
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/SuspRecords.cs b/DiscUtils/Iso9660Ps1/Susp/SuspRecords.cs
new file mode 100644
index 0000000..174ee40
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/SuspRecords.cs
@@ -0,0 +1,182 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections.Generic;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal sealed class SuspRecords
+ {
+ private readonly Dictionary>> _records;
+
+ public SuspRecords(IsoContext context, byte[] data, int offset)
+ {
+ _records = new Dictionary>>();
+
+ ContinuationSystemUseEntry contEntry = Parse(context, data, offset + context.SuspSkipBytes);
+ while (contEntry != null)
+ {
+ context.DataStream.Position = contEntry.Block * (long)context.VolumeDescriptor.LogicalBlockSize +
+ contEntry.BlockOffset;
+ byte[] contData = StreamUtilities.ReadExact(context.DataStream, (int)contEntry.Length);
+
+ contEntry = Parse(context, contData, 0);
+ }
+ }
+
+ public static bool DetectSharingProtocol(byte[] data, int offset)
+ {
+ if (data == null || data.Length - offset < 7)
+ {
+ return false;
+ }
+
+ return data[offset] == 83
+ && data[offset + 1] == 80
+ && data[offset + 2] == 7
+ && data[offset + 3] == 1
+ && data[offset + 4] == 0xBE
+ && data[offset + 5] == 0xEF;
+ }
+
+ public List GetEntries(string extension, string name)
+ {
+ if (string.IsNullOrEmpty(extension))
+ {
+ extension = string.Empty;
+ }
+
+ Dictionary> extensionData;
+ if (!_records.TryGetValue(extension, out extensionData))
+ {
+ return null;
+ }
+
+ List result;
+ if (extensionData.TryGetValue(name, out result))
+ {
+ return result;
+ }
+
+ return null;
+ }
+
+ public T GetEntry(string extension, string name)
+ where T : SystemUseEntry
+ {
+ List entries = GetEntries(extension, name);
+ if (entries == null)
+ {
+ return null;
+ }
+
+ foreach (T entry in entries)
+ {
+ return entry;
+ }
+
+ return null;
+ }
+
+ public bool HasEntry(string extension, string name)
+ {
+ List entries = GetEntries(extension, name);
+ return entries != null && entries.Count != 0;
+ }
+
+ private ContinuationSystemUseEntry Parse(IsoContext context, byte[] data, int offset)
+ {
+ ContinuationSystemUseEntry contEntry = null;
+ SuspExtension extension = null;
+
+ if (context.SuspExtensions != null && context.SuspExtensions.Count > 0)
+ {
+ extension = context.SuspExtensions[0];
+ }
+
+ int pos = offset;
+ while (data.Length - pos > 4)
+ {
+ byte len;
+ SystemUseEntry entry = SystemUseEntry.Parse(data, pos, context.VolumeDescriptor.CharacterEncoding,
+ extension, out len);
+ pos += len;
+
+ if (entry == null)
+ {
+ // A null entry indicates SUSP parsing must terminate.
+ // This will occur if a termination record is found,
+ // or if there is a problem with the SUSP data.
+ return contEntry;
+ }
+
+ switch (entry.Name)
+ {
+ case "CE":
+ contEntry = (ContinuationSystemUseEntry)entry;
+ break;
+
+ case "ES":
+ ExtensionSelectSystemUseEntry esEntry = (ExtensionSelectSystemUseEntry)entry;
+ extension = context.SuspExtensions[esEntry.SelectedExtension];
+ break;
+
+ case "PD":
+ break;
+
+ case "SP":
+ case "ER":
+ StoreEntry(null, entry);
+ break;
+
+ default:
+ StoreEntry(extension, entry);
+ break;
+ }
+ }
+
+ return contEntry;
+ }
+
+ private void StoreEntry(SuspExtension extension, SystemUseEntry entry)
+ {
+ string extensionId = extension == null ? string.Empty : extension.Identifier;
+
+ Dictionary> extensionEntries;
+ if (!_records.TryGetValue(extensionId, out extensionEntries))
+ {
+ extensionEntries = new Dictionary>();
+ _records.Add(extensionId, extensionEntries);
+ }
+
+ List entries;
+ if (!extensionEntries.TryGetValue(entry.Name, out entries))
+ {
+ entries = new List();
+ extensionEntries.Add(entry.Name, entries);
+ }
+
+ entries.Add(entry);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/Susp/SystemUseEntry.cs b/DiscUtils/Iso9660Ps1/Susp/SystemUseEntry.cs
new file mode 100644
index 0000000..91877ca
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/Susp/SystemUseEntry.cs
@@ -0,0 +1,105 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Text;
+using DiscUtils.Streams;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal abstract class SystemUseEntry
+ {
+ public string Name;
+ public byte Version;
+
+ public static SystemUseEntry Parse(byte[] data, int offset, Encoding encoding, SuspExtension extension,
+ out byte length)
+ {
+ if (data[offset] == 0)
+ {
+ // A zero-byte here is invalid and indicates an incorrectly written SUSP field.
+ // Return null to indicate to the caller that SUSP parsing is terminated.
+ length = 0;
+
+ return null;
+ }
+
+ string name = EndianUtilities.BytesToString(data, offset, 2);
+ length = data[offset + 2];
+ byte version = data[offset + 3];
+
+ switch (name)
+ {
+ case "CE":
+ return new ContinuationSystemUseEntry(name, length, version, data, offset);
+
+ case "PD":
+ return new PaddingSystemUseEntry(name, length, version);
+
+ case "SP":
+ return new SharingProtocolSystemUseEntry(name, length, version, data, offset);
+
+ case "ST":
+ // Termination entry. There's no point in storing or validating this one.
+ // Return null to indicate to the caller that SUSP parsing is terminated.
+ return null;
+
+ case "ER":
+ return new ExtensionSystemUseEntry(name, length, version, data, offset, encoding);
+
+ case "ES":
+ return new ExtensionSelectSystemUseEntry(name, length, version, data, offset);
+
+ case "AA":
+ case "AB":
+ case "AS":
+ // Placeholder support for Apple and Amiga extension records.
+ return new GenericSystemUseEntry(name, length, version, data, offset);
+
+ default:
+ if (extension == null)
+ {
+ return new GenericSystemUseEntry(name, length, version, data, offset);
+ }
+
+ return extension.Parse(name, length, version, data, offset, encoding);
+ }
+ }
+
+ protected void CheckAndSetCommonProperties(string name, byte length, byte version, byte minLength, byte maxVersion)
+ {
+ if (length < minLength)
+ {
+ throw new InvalidDataException("Invalid SUSP " + Name + " entry - too short, only " + length + " bytes");
+ }
+
+ if (version > maxVersion || version == 0)
+ {
+ throw new NotSupportedException("Unknown SUSP " + Name + " entry version: " + version);
+ }
+
+ Name = name;
+ Version = version;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DiscUtils/Iso9660Ps1/VfsCDReader.cs b/DiscUtils/Iso9660Ps1/VfsCDReader.cs
new file mode 100644
index 0000000..c694ec3
--- /dev/null
+++ b/DiscUtils/Iso9660Ps1/VfsCDReader.cs
@@ -0,0 +1,530 @@
+//
+// Copyright (c) 2008-2011, Kenneth Bell
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using DiscUtils.Streams;
+using DiscUtils.Vfs;
+
+namespace DiscUtils.Iso9660Ps1
+{
+ internal class VfsCDReader : VfsReadOnlyFileSystem,
+ IClusterBasedFileSystem, IUnixFileSystem
+ {
+ private static readonly Iso9660Variant[] DefaultVariantsNoJoliet = { Iso9660Variant.RockRidge, Iso9660Variant.Iso9660 };
+
+ private static readonly Iso9660Variant[] DefaultVariantsWithJoliet = { Iso9660Variant.Joliet, Iso9660Variant.RockRidge, Iso9660Variant.Iso9660 };
+
+ private byte[] _bootCatalog;
+ private readonly BootVolumeDescriptor _bootVolDesc;
+
+ private readonly Stream _data;
+ private readonly bool _hideVersions;
+ protected readonly int _sectorSize;
+
+ ///
+ /// Initializes a new instance of the VfsCDReader class.
+ ///
+ /// The stream to read the ISO image from.
+ /// Whether to read Joliet extensions.
+ /// Hides version numbers (e.g. ";1") from the end of files.
+ public VfsCDReader(Stream data, bool joliet, bool hideVersions, int sectorSize)
+ : this(data, joliet ? DefaultVariantsWithJoliet : DefaultVariantsNoJoliet, hideVersions, sectorSize) {
+ }
+
+ ///
+ /// Initializes a new instance of the VfsCDReader class.
+ ///
+ /// The stream to read the ISO image from.
+ /// Which possible file system variants to use, and with which priority.
+ /// Hides version numbers (e.g. ";1") from the end of files.
+ ///
+ ///
+ /// The implementation considers each of the file system variants in variantProperties and selects
+ /// the first which is determined to be present. In this example Joliet, then Rock Ridge, then vanilla
+ /// Iso9660 will be considered:
+ ///
+ ///
+ /// VfsCDReader(stream, new Iso9660Variant[] {Joliet, RockRidge, Iso9660}, true);
+ ///
+ /// The Iso9660 variant should normally be specified as the final entry in the list. Placing it earlier
+ /// in the list will effectively mask later items and not including it may prevent some ISOs from being read.
+ ///
+ public VfsCDReader(Stream data, Iso9660Variant[] variantPriorities, bool hideVersions, int sectorSize)
+ : base(new DiscFileSystemOptions())
+ {
+ _data = data;
+ _sectorSize = sectorSize;
+ _hideVersions = hideVersions;
+
+ long vdpos = _sectorSize * 16; // Skip lead-in
+
+ byte[] buffer = new byte[_sectorSize];
+
+ long pvdPos = 0;
+ long svdPos = 0;
+
+ BaseVolumeDescriptor bvd;
+ do
+ {
+ data.Position = vdpos;
+ int numRead = data.Read(buffer, 0, _sectorSize);
+ if (numRead != _sectorSize)
+ {
+ break;
+ }
+
+ var offset = 24;
+
+ bvd = new BaseVolumeDescriptor(buffer, offset);
+
+ if (bvd.StandardIdentifier != BaseVolumeDescriptor.Iso9660StandardIdentifier)
+ {
+ throw new InvalidFileSystemException("Volume is not ISO-9660");
+ }
+
+ switch (bvd.VolumeDescriptorType)
+ {
+ case VolumeDescriptorType.Boot:
+ _bootVolDesc = new BootVolumeDescriptor(buffer, offset);
+ if (_bootVolDesc.SystemId != BootVolumeDescriptor.ElToritoSystemIdentifier)
+ {
+ _bootVolDesc = null;
+ }
+
+ break;
+
+ case VolumeDescriptorType.Primary: // Primary Vol Descriptor
+ pvdPos = vdpos;
+ break;
+
+ case VolumeDescriptorType.Supplementary: // Supplementary Vol Descriptor
+ svdPos = vdpos;
+ break;
+
+ case VolumeDescriptorType.Partition: // Volume Partition Descriptor
+ break;
+ case VolumeDescriptorType.SetTerminator: // Volume Descriptor Set Terminator
+ break;
+ }
+
+ vdpos += _sectorSize;
+ } while (bvd.VolumeDescriptorType != VolumeDescriptorType.SetTerminator);
+
+ ActiveVariant = Iso9660Variant.None;
+ foreach (Iso9660Variant variant in variantPriorities)
+ {
+ switch (variant)
+ {
+ case Iso9660Variant.Joliet:
+ if (svdPos != 0)
+ {
+ data.Position = svdPos;
+ data.Read(buffer, 0, _sectorSize);
+ SupplementaryVolumeDescriptor volDesc = new SupplementaryVolumeDescriptor(buffer, 0);
+
+ Context = new IsoContext(_sectorSize) { VolumeDescriptor = volDesc, DataStream = _data };
+ RootDirectory = new ReaderDirectory(Context,
+ new ReaderDirEntry(Context, volDesc.RootDirectory));
+ ActiveVariant = Iso9660Variant.Iso9660;
+ }
+
+ break;
+
+ case Iso9660Variant.RockRidge:
+ case Iso9660Variant.Iso9660:
+ if (pvdPos != 0)
+ {
+ data.Position = pvdPos + 24;
+ data.Read(buffer, 0, _sectorSize);
+ PrimaryVolumeDescriptor volDesc = new PrimaryVolumeDescriptor(buffer, 0);
+
+ volDesc.LogicalBlockSize = 2352;
+
+ IsoContext context = new IsoContext(_sectorSize) { VolumeDescriptor = volDesc, DataStream = _data };
+ DirectoryRecord rootSelfRecord = ReadRootSelfRecord(context);
+
+ InitializeSusp(context, rootSelfRecord);
+
+ if (variant == Iso9660Variant.Iso9660
+ ||
+ (variant == Iso9660Variant.RockRidge &&
+ !string.IsNullOrEmpty(context.RockRidgeIdentifier)))
+ {
+ Context = context;
+ RootDirectory = new ReaderDirectory(context, new ReaderDirEntry(context, rootSelfRecord));
+ ActiveVariant = variant;
+ }
+ }
+
+ break;
+ }
+
+ if (ActiveVariant != Iso9660Variant.None)
+ {
+ break;
+ }
+ }
+
+ if (ActiveVariant == Iso9660Variant.None)
+ {
+ throw new IOException("None of the permitted ISO9660 file system variants was detected");
+ }
+ }
+
+ public Iso9660Variant ActiveVariant { get; }
+
+ public BootDeviceEmulation BootEmulation
+ {
+ get
+ {
+ BootInitialEntry initialEntry = GetBootInitialEntry();
+ if (initialEntry != null)
+ {
+ return initialEntry.BootMediaType;
+ }
+
+ return BootDeviceEmulation.NoEmulation;
+ }
+ }
+
+ public long BootImageStart
+ {
+ get
+ {
+ BootInitialEntry initialEntry = GetBootInitialEntry();
+ if (initialEntry != null)
+ {
+ return initialEntry.ImageStart * _sectorSize;
+ }
+ return 0;
+ }
+ }
+
+ public int BootLoadSegment
+ {
+ get
+ {
+ BootInitialEntry initialEntry = GetBootInitialEntry();
+ if (initialEntry != null)
+ {
+ return initialEntry.LoadSegment;
+ }
+
+ return 0;
+ }
+ }
+
+ ///
+ /// Provides the friendly name for the CD filesystem.
+ ///
+ public override string FriendlyName
+ {
+ get { return "ISO 9660 (CD-ROM)"; }
+ }
+
+ public bool HasBootImage
+ {
+ get
+ {
+ if (_bootVolDesc == null)
+ {
+ return false;
+ }
+
+ byte[] bootCatalog = GetBootCatalog();
+ if (bootCatalog == null)
+ {
+ return false;
+ }
+
+ BootValidationEntry entry = new BootValidationEntry(bootCatalog, 0);
+ return entry.ChecksumValid;
+ }
+ }
+
+ ///
+ /// Gets the Volume Identifier.
+ ///
+ public override string VolumeLabel
+ {
+ get { return Context.VolumeDescriptor.VolumeIdentifier; }
+ }
+
+ public long ClusterSize
+ {
+ get { return _sectorSize; }
+ }
+
+ public long TotalClusters
+ {
+ get { return Context.VolumeDescriptor.VolumeSpaceSize; }
+ }
+
+ public long ClusterToOffset(long cluster)
+ {
+ return cluster * ClusterSize;
+ }
+
+ public long OffsetToCluster(long offset)
+ {
+ return offset / ClusterSize;
+ }
+
+ ///
+ /// Size of the Filesystem in bytes
+ ///
+ public override long Size
+ {
+ get { throw new NotSupportedException("Filesystem size is not (yet) supported"); }
+ }
+
+ ///
+ /// Used space of the Filesystem in bytes
+ ///
+ public override long UsedSpace
+ {
+ get { throw new NotSupportedException("Filesystem size is not (yet) supported"); }
+ }
+
+ ///
+ /// Available space of the Filesystem in bytes
+ ///
+ public override long AvailableSpace
+ {
+ get { throw new NotSupportedException("Filesystem size is not (yet) supported"); }
+ }
+
+ public Range[] PathToClusters(string path)
+ {
+ ReaderDirEntry entry = GetDirectoryEntry(path);
+ if (entry == null)
+ {
+ throw new FileNotFoundException("File not found", path);
+ }
+
+ if (entry.Record.FileUnitSize != 0 || entry.Record.InterleaveGapSize != 0)
+ {
+ throw new NotSupportedException("Non-contiguous extents not supported");
+ }
+
+ return new[]
+ {
+ new Range(entry.Record.LocationOfExtent,
+ MathUtilities.Ceil(entry.Record.DataLength, _sectorSize))
+ };
+ }
+
+ public StreamExtent[] PathToExtents(string path)
+ {
+ ReaderDirEntry entry = GetDirectoryEntry(path);
+ if (entry == null)
+ {
+ throw new FileNotFoundException("File not found", path);
+ }
+
+ if (entry.Record.FileUnitSize != 0 || entry.Record.InterleaveGapSize != 0)
+ {
+ throw new NotSupportedException("Non-contiguous extents not supported");
+ }
+
+ return new[]
+ { new StreamExtent(entry.Record.LocationOfExtent * _sectorSize, entry.Record.DataLength) };
+ }
+
+ public ClusterMap BuildClusterMap()
+ {
+ long totalClusters = TotalClusters;
+ ClusterRoles[] clusterToRole = new ClusterRoles[totalClusters];
+ object[] clusterToFileId = new object[totalClusters];
+ Dictionary