Improved file table parsing in ISO format; still a lot of work to be done

This commit is contained in:
Michael Becker 2014-11-27 22:33:37 -05:00
parent bb311f2979
commit 096c70a133

View File

@ -7,277 +7,324 @@ using UniversalEditor.ObjectModels.FileSystem;
namespace UniversalEditor.DataFormats.FileSystem.ISO
{
public class ISODataFormat : DataFormat
{
private static DataFormatReference _dfr = null;
public override DataFormatReference MakeReference()
{
if (_dfr == null)
{
_dfr = base.MakeReference();
_dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
_dfr.Filters.Add("ISO 9660 optical disc image", new string[] { "*.iso" });
_dfr.ContentTypes.Add("application/x-iso9660-image");
public class ISODataFormat : DataFormat
{
private static DataFormatReference _dfr = null;
public override DataFormatReference MakeReference()
{
if (_dfr == null)
{
_dfr = base.MakeReference();
_dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All);
_dfr.Filters.Add("ISO 9660 optical disc image", new string[] { "*.iso" });
_dfr.ContentTypes.Add("application/x-iso9660-image");
_dfr.ExportOptions.Add(new CustomOptionText("SystemName", "System &name:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("VolumeName", "&Volume name:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionNumber("VolumeSetSize", "Number of volumes in this set:", 1, 0, UInt16.MaxValue));
_dfr.ExportOptions.Add(new CustomOptionNumber("VolumeSequenceNumber", "Index of this volume in set:", 0, 0, UInt16.MaxValue));
_dfr.ExportOptions.Add(new CustomOptionText("VolumeSet", "Volume &set:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("Publisher", "&Publisher:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("DataPreparer", "&Data preparer:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("Application", "&Application:", "Universal Editor", 128));
_dfr.ExportOptions.Add(new CustomOptionText("CopyrightFile", "&Copyright file:", String.Empty, 38));
_dfr.ExportOptions.Add(new CustomOptionText("AbstractFile", "&Abstract file:", String.Empty, 36));
_dfr.ExportOptions.Add(new CustomOptionText("BibliographicFile", "&Bibliographic file:", String.Empty, 37));
}
return _dfr;
}
_dfr.ExportOptions.Add(new CustomOptionText("SystemName", "System &name:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("VolumeName", "&Volume name:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionNumber("VolumeSetSize", "Number of volumes in this set:", 1, 0, UInt16.MaxValue));
_dfr.ExportOptions.Add(new CustomOptionNumber("VolumeSequenceNumber", "Index of this volume in set:", 0, 0, UInt16.MaxValue));
_dfr.ExportOptions.Add(new CustomOptionText("VolumeSet", "Volume &set:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("Publisher", "&Publisher:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("DataPreparer", "&Data preparer:", String.Empty, 128));
_dfr.ExportOptions.Add(new CustomOptionText("Application", "&Application:", "Universal Editor", 128));
_dfr.ExportOptions.Add(new CustomOptionText("CopyrightFile", "&Copyright file:", String.Empty, 38));
_dfr.ExportOptions.Add(new CustomOptionText("AbstractFile", "&Abstract file:", String.Empty, 36));
_dfr.ExportOptions.Add(new CustomOptionText("BibliographicFile", "&Bibliographic file:", String.Empty, 37));
}
return _dfr;
}
private string mvarSystemName = String.Empty;
public string SystemName { get { return mvarSystemName; } set { mvarSystemName = value; } }
private string mvarSystemName = String.Empty;
public string SystemName { get { return mvarSystemName; } set { mvarSystemName = value; } }
private string mvarVolumeName = String.Empty;
public string VolumeName { get { return mvarVolumeName; } set { mvarVolumeName = value; } }
private string mvarVolumeName = String.Empty;
public string VolumeName { get { return mvarVolumeName; } set { mvarVolumeName = value; } }
private ushort mvarVolumeSetSize = 0;
public ushort VolumeSetSize { get { return mvarVolumeSetSize; } set { mvarVolumeSetSize = value; } }
private ushort mvarVolumeSetSize = 0;
public ushort VolumeSetSize { get { return mvarVolumeSetSize; } set { mvarVolumeSetSize = value; } }
private ushort mvarVolumeSequenceNumber = 0;
public ushort VolumeSequenceNumber { get { return mvarVolumeSequenceNumber; } set { mvarVolumeSequenceNumber = value; } }
private ushort mvarVolumeSequenceNumber = 0;
public ushort VolumeSequenceNumber { get { return mvarVolumeSequenceNumber; } set { mvarVolumeSequenceNumber = value; } }
private ushort mvarLogicalBlockSize = 2048;
public ushort LogicalBlockSize { get { return mvarLogicalBlockSize; } set { mvarLogicalBlockSize = value; } }
private ushort mvarLogicalBlockSize = 2048;
public ushort LogicalBlockSize { get { return mvarLogicalBlockSize; } set { mvarLogicalBlockSize = value; } }
private string mvarVolumeSet = String.Empty;
public string VolumeSet { get { return mvarVolumeSet; } set { mvarVolumeSet = value; } }
private string mvarVolumeSet = String.Empty;
public string VolumeSet { get { return mvarVolumeSet; } set { mvarVolumeSet = value; } }
private string mvarPublisher = String.Empty;
public string Publisher { get { return mvarPublisher; } set { mvarPublisher = value; } }
private string mvarPublisher = String.Empty;
public string Publisher { get { return mvarPublisher; } set { mvarPublisher = value; } }
private string mvarDataPreparer = String.Empty;
public string DataPreparer { get { return mvarDataPreparer; } set { mvarDataPreparer = value; } }
private string mvarDataPreparer = String.Empty;
public string DataPreparer { get { return mvarDataPreparer; } set { mvarDataPreparer = value; } }
private string mvarApplication = String.Empty;
public string Application { get { return mvarApplication; } set { mvarApplication = value; } }
private string mvarApplication = String.Empty;
public string Application { get { return mvarApplication; } set { mvarApplication = value; } }
private string mvarCopyrightFile = String.Empty;
public string CopyrightFile { get { return mvarCopyrightFile; } set { mvarCopyrightFile = value; } }
private string mvarCopyrightFile = String.Empty;
public string CopyrightFile { get { return mvarCopyrightFile; } set { mvarCopyrightFile = value; } }
private string mvarAbstractFile = String.Empty;
public string AbstractFile { get { return mvarAbstractFile; } set { mvarAbstractFile = value; } }
private string mvarAbstractFile = String.Empty;
public string AbstractFile { get { return mvarAbstractFile; } set { mvarAbstractFile = value; } }
private string mvarBibliographicFile = String.Empty;
public string BibliographicFile { get { return mvarBibliographicFile; } set { mvarBibliographicFile = value; } }
private string mvarBibliographicFile = String.Empty;
public string BibliographicFile { get { return mvarBibliographicFile; } set { mvarBibliographicFile = value; } }
protected override void LoadInternal(ref ObjectModel objectModel)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
IO.Reader br = base.Accessor.Reader;
protected override void LoadInternal(ref ObjectModel objectModel)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
IO.Reader br = base.Accessor.Reader;
// skip system area (32768 bytes... WHY???)
br.Accessor.Seek(32768, SeekOrigin.Current);
br.Seek(0, SeekOrigin.Begin);
while (true)
{
ISOVolumeDescriptorType type = (ISOVolumeDescriptorType)br.ReadByte();
string identifier = br.ReadFixedLengthString(5);
byte version = br.ReadByte();
// skip system area (32768 bytes... WHY???)
br.Accessor.Seek(32768, SeekOrigin.Current);
switch (type)
{
case ISOVolumeDescriptorType.Primary:
{
Internal.PrimaryVolumeDescriptor descriptor = ReadPrimaryVolumeDescriptor(br);
mvarSystemName = descriptor.systemName;
mvarVolumeName = descriptor.volumeName;
mvarVolumeSetSize = descriptor.volumeSetSize;
mvarVolumeSequenceNumber = descriptor.volumeSequenceNumber;
mvarLogicalBlockSize = descriptor.logicalBlockSize;
mvarVolumeSet = descriptor.volumeSet;
mvarPublisher = descriptor.publisher;
mvarDataPreparer = descriptor.dataPreparer;
mvarApplication = descriptor.application;
mvarCopyrightFile = descriptor.copyrightFile;
mvarAbstractFile = descriptor.abstractFile;
mvarBibliographicFile = descriptor.bibliographicFile;
break;
}
default:
{
br.Accessor.Seek(2041, SeekOrigin.Current);
break;
}
}
if (type == ISOVolumeDescriptorType.Terminator) break;
}
uint pathTableLocationTypeL = 0;
uint pathTableLocationTypeM = 0;
// skip 4 sectors of unknown data to get to the file names
br.Accessor.Seek(mvarLogicalBlockSize * 4, SeekOrigin.Current);
while (true)
{
ISOVolumeDescriptorType type = (ISOVolumeDescriptorType)br.ReadByte();
string identifier = br.ReadFixedLengthString(5);
byte version = br.ReadByte();
// sector 5 = file names, sector 6 = unicode file names (?)
// sector 7 starts the file data...
while (!br.EndOfStream)
{
byte[] nextSectorData = br.ReadBytes(mvarLogicalBlockSize);
// TODO: remove this after testing
System.IO.File.WriteAllBytes(@"T:\Libraries\UniversalEditor\Tests\FileSystem\ISO\NEXT.DAT", nextSectorData);
}
}
switch (type)
{
case ISOVolumeDescriptorType.Primary:
{
Internal.PrimaryVolumeDescriptor descriptor = ReadPrimaryVolumeDescriptor(br);
mvarSystemName = descriptor.systemName;
mvarVolumeName = descriptor.volumeName;
mvarVolumeSetSize = descriptor.volumeSetSize;
mvarVolumeSequenceNumber = descriptor.volumeSequenceNumber;
mvarLogicalBlockSize = descriptor.logicalBlockSize;
mvarVolumeSet = descriptor.volumeSet;
mvarPublisher = descriptor.publisher;
mvarDataPreparer = descriptor.dataPreparer;
mvarApplication = descriptor.application;
mvarCopyrightFile = descriptor.copyrightFile;
mvarAbstractFile = descriptor.abstractFile;
mvarBibliographicFile = descriptor.bibliographicFile;
pathTableLocationTypeL = descriptor.pathTableLocationTypeL;
pathTableLocationTypeM = descriptor.pathTableLocationTypeM;
break;
}
case ISOVolumeDescriptorType.Terminator:
{
break;
}
default:
{
br.Accessor.Seek(2041, SeekOrigin.Current);
break;
}
}
if (type == ISOVolumeDescriptorType.Terminator) break;
}
private Internal.PrimaryVolumeDescriptor ReadPrimaryVolumeDescriptor(IO.Reader br)
{
Internal.PrimaryVolumeDescriptor descriptor = new Internal.PrimaryVolumeDescriptor();
descriptor.unused1 = br.ReadByte(); // Always 0x00.
descriptor.systemName = br.ReadFixedLengthString(32); // The name of the system that can act upon sectors 0x00-0x0F for the volume.
descriptor.volumeName = br.ReadFixedLengthString(32); // Identification of this volume.
descriptor.unused2 = br.ReadUInt64(); // All zeroes.
descriptor.volumeSpaceSize = br.ReadDoubleEndianUInt32();
descriptor.unused3 = br.ReadBytes(32);
descriptor.volumeSetSize = br.ReadDoubleEndianUInt16();
descriptor.volumeSequenceNumber = br.ReadDoubleEndianUInt16();
descriptor.logicalBlockSize = br.ReadDoubleEndianUInt16();
descriptor.pathTableSize = br.ReadDoubleEndianUInt32();
// go to the little-endian path table sector and read it
br.Accessor.Seek(mvarLogicalBlockSize * pathTableLocationTypeL, SeekOrigin.Begin);
descriptor.pathTableLocationTypeL = br.ReadUInt32();
descriptor.optionalPathTableLocationTypeL = br.ReadUInt32();
// go to the big-endian path table sector and read it
br.Accessor.Seek(mvarLogicalBlockSize * pathTableLocationTypeM, SeekOrigin.Begin);
br.Endianness = IO.Endianness.BigEndian;
descriptor.pathTableLocationTypeM = br.ReadUInt32();
descriptor.optionalPathTableLocationTypeM = br.ReadUInt32();
br.Endianness = IO.Endianness.LittleEndian;
descriptor.rootDirectoryEntry = br.ReadBytes(34);
br.Accessor.Position -= 34;
#region Root Directory
ushort rootDirectoryEntrySize = br.ReadUInt16();
uint unknown1 = br.ReadDoubleEndianUInt32();
uint unknown2 = br.ReadDoubleEndianUInt32();
byte[] unknown3 = br.ReadBytes(16);
#endregion
// our test file (C:\TEMP\ISOTEST\test-one-file-noextensions.iso) has file table in the
// sector right after pathTableLocationTypeM
br.Accessor.Seek(mvarLogicalBlockSize * 20, SeekOrigin.Begin);
descriptor.volumeSet = br.ReadFixedLengthString(128);
descriptor.publisher = br.ReadFixedLengthString(128);
descriptor.dataPreparer = br.ReadFixedLengthString(128);
descriptor.application = br.ReadFixedLengthString(128);
descriptor.copyrightFile = br.ReadFixedLengthString(38);
descriptor.abstractFile = br.ReadFixedLengthString(36);
descriptor.bibliographicFile = br.ReadFixedLengthString(37);
for (int i = 0; i < 2; i++)
{
ushort unknown1 = br.ReadUInt16();
uint unknown2 = br.ReadDoubleEndianUInt32();
uint unknown3 = br.ReadDoubleEndianUInt32();
ulong unknown4 = br.ReadUInt64();
uint unknown5 = br.ReadUInt32();
ushort unknown6 = br.ReadUInt16();
ushort unknown7 = br.ReadUInt16();
}
descriptor.timestampVolumeCreation = ReadDECDateTime(br);
descriptor.timestampVolumeModification = ReadDECDateTime(br);
descriptor.timestampVolumeExpiration = ReadDECDateTime(br);
descriptor.timestampVolumeEffective = ReadDECDateTime(br);
while (true)
{ // file 1 file 2
ushort unknown1 = br.ReadUInt16(); // 48 42
if (unknown1 == 0) break;
descriptor.fileStructureVersion = br.ReadByte();
descriptor.unused4 = br.ReadByte();
descriptor.applicationSpecific = br.ReadBytes(512);
descriptor.reserved = br.ReadBytes(653);
return descriptor;
}
uint unknown2 = br.ReadDoubleEndianUInt32(); // 21 22
uint unknown3 = br.ReadDoubleEndianUInt32(); // 44 20
ulong unknown4 = br.ReadUInt64(); // ...
ushort unknown5 = br.ReadUInt16(); // 0 0
ushort unknown6 = br.ReadUInt16(); // 1 1
ushort unknown7 = br.ReadUInt16(); // 256 256
private DateTime ReadDECDateTime(IO.Reader br)
{
string szYear = br.ReadFixedLengthString(4); // Year from 1 to 9999.
string szMonth = br.ReadFixedLengthString(2); // Month from 1 to 12.
string szDay = br.ReadFixedLengthString(2); // Day from 1 to 31.
string szHour = br.ReadFixedLengthString(2); // Hour from 0 to 23.
string szMinute = br.ReadFixedLengthString(2); // Minute from 0 to 59.
string szSecond = br.ReadFixedLengthString(2); // Second from 0 to 59.
string szHundredSeconds= br.ReadFixedLengthString(2); // Hundredths of a second from 0 to 99.
string fileName = br.ReadLengthPrefixedString();
byte nulTerminator = br.ReadByte();
// Time zone offset from GMT in 15 minute intervals, starting at interval -48 (west) and running up to
// interval 52 (east). So value 0 indicates interval -48 which equals GMT-12 hours, and value 100
// indicates interval 52 which equals GMT+13 hours.
byte timeZoneOffset = br.ReadByte();
File file = fsom.AddFile(fileName);
}
}
int iYear = Int32.Parse(szYear);
int iMonth = Int32.Parse(szMonth);
int iDay = Int32.Parse(szDay);
int iHour = Int32.Parse(szHour);
int iMinute = Int32.Parse(szMinute);
int iSecond = Int32.Parse(szSecond);
int iHundredSeconds = Int32.Parse(szHundredSeconds);
private Internal.PrimaryVolumeDescriptor ReadPrimaryVolumeDescriptor(IO.Reader br)
{
Internal.PrimaryVolumeDescriptor descriptor = new Internal.PrimaryVolumeDescriptor();
descriptor.unused1 = br.ReadByte(); // Always 0x00.
descriptor.systemName = br.ReadFixedLengthString(32); // The name of the system that can act upon sectors 0x00-0x0F for the volume.
descriptor.volumeName = br.ReadFixedLengthString(32); // Identification of this volume.
descriptor.unused2 = br.ReadUInt64(); // All zeroes.
descriptor.volumeSpaceSize = br.ReadDoubleEndianUInt32();
descriptor.unused3 = br.ReadBytes(32);
descriptor.volumeSetSize = br.ReadDoubleEndianUInt16();
descriptor.volumeSequenceNumber = br.ReadDoubleEndianUInt16();
descriptor.logicalBlockSize = br.ReadDoubleEndianUInt16();
descriptor.pathTableSize = br.ReadDoubleEndianUInt32();
DateTime dt = new DateTime(iYear, iMonth, iDay, iHour, iMinute, iSecond, iHundredSeconds);
return dt;
}
private void WriteDECDateTime(IO.Writer bw, DateTime dt)
{
bw.WriteFixedLengthString(dt.Year.ToString(), 4, ' ');
bw.WriteFixedLengthString(dt.Month.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Day.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Hour.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Minute.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Second.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Millisecond.ToString(), 2, ' ');
descriptor.pathTableLocationTypeL = br.ReadUInt32();
descriptor.optionalPathTableLocationTypeL = br.ReadUInt32();
// Time zone offset from GMT in 15 minute intervals, starting at interval -48 (west) and running up to
// interval 52 (east). So value 0 indicates interval -48 which equals GMT-12 hours, and value 100
// indicates interval 52 which equals GMT+13 hours.
byte timeZoneOffset = 0;
bw.WriteByte(timeZoneOffset);
}
br.Endianness = IO.Endianness.BigEndian;
descriptor.pathTableLocationTypeM = br.ReadUInt32();
descriptor.optionalPathTableLocationTypeM = br.ReadUInt32();
br.Endianness = IO.Endianness.LittleEndian;
protected override void SaveInternal(ObjectModel objectModel)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
IO.Writer bw = base.Accessor.Writer;
descriptor.rootDirectoryEntry = br.ReadBytes(34);
br.Accessor.Position -= 34;
// skip system area
bw.Accessor.Seek(32768, SeekOrigin.Current);
#region Root Directory
ushort rootDirectoryEntrySize = br.ReadUInt16();
uint unknown1 = br.ReadDoubleEndianUInt32();
uint unknown2 = br.ReadDoubleEndianUInt32();
byte[] unknown3 = br.ReadBytes(16);
#endregion
Internal.PrimaryVolumeDescriptor descriptor = new Internal.PrimaryVolumeDescriptor();
descriptor.systemName = mvarSystemName; // The name of the system that can act upon sectors 0x00-0x0F for the volume.
descriptor.volumeName = mvarVolumeName; // Identification of this volume.
descriptor.volumeSetSize = mvarVolumeSetSize;
descriptor.volumeSequenceNumber = mvarVolumeSequenceNumber;
descriptor.logicalBlockSize = mvarLogicalBlockSize;
WritePrimaryVolumeDescriptor(bw, descriptor);
descriptor.volumeSet = br.ReadFixedLengthString(128);
descriptor.publisher = br.ReadFixedLengthString(128);
descriptor.dataPreparer = br.ReadFixedLengthString(128);
descriptor.application = br.ReadFixedLengthString(128);
descriptor.copyrightFile = br.ReadFixedLengthString(37);
descriptor.abstractFile = br.ReadFixedLengthString(37);
descriptor.bibliographicFile = br.ReadFixedLengthString(37);
bw.Flush();
}
descriptor.timestampVolumeCreation = ReadDECDateTime(br);
descriptor.timestampVolumeModification = ReadDECDateTime(br);
descriptor.timestampVolumeExpiration = ReadDECDateTime(br);
descriptor.timestampVolumeEffective = ReadDECDateTime(br);
private void WritePrimaryVolumeDescriptor(IO.Writer bw, Internal.PrimaryVolumeDescriptor descriptor)
{
bw.WriteByte(descriptor.unused1);
bw.WriteFixedLengthString(descriptor.systemName, 32, ' ');
bw.WriteFixedLengthString(descriptor.volumeName, 32, ' ');
bw.WriteUInt64(descriptor.unused2);
bw.WriteDoubleEndianUInt32(descriptor.volumeSpaceSize);
bw.WriteFixedLengthBytes(descriptor.unused3, 32);
bw.WriteDoubleEndianUInt16(descriptor.volumeSetSize);
bw.WriteDoubleEndianUInt16(descriptor.volumeSequenceNumber);
bw.WriteDoubleEndianUInt16(descriptor.logicalBlockSize);
bw.WriteDoubleEndianUInt32(descriptor.pathTableSize);
descriptor.fileStructureVersion = br.ReadByte();
descriptor.unused4 = br.ReadByte();
descriptor.applicationSpecific = br.ReadBytes(512);
descriptor.reserved = br.ReadBytes(653);
return descriptor;
}
bw.WriteUInt32(descriptor.pathTableLocationTypeL);
bw.WriteUInt32(descriptor.optionalPathTableLocationTypeL);
private DateTime ReadDECDateTime(IO.Reader br)
{
string szYear = br.ReadFixedLengthString(4); // Year from 1 to 9999.
string szMonth = br.ReadFixedLengthString(2); // Month from 1 to 12.
string szDay = br.ReadFixedLengthString(2); // Day from 1 to 31.
string szHour = br.ReadFixedLengthString(2); // Hour from 0 to 23.
string szMinute = br.ReadFixedLengthString(2); // Minute from 0 to 59.
string szSecond = br.ReadFixedLengthString(2); // Second from 0 to 59.
string szHundredSeconds= br.ReadFixedLengthString(2); // Hundredths of a second from 0 to 99.
bw.Endianness = IO.Endianness.BigEndian;
bw.WriteUInt32(descriptor.pathTableLocationTypeM);
bw.WriteUInt32(descriptor.optionalPathTableLocationTypeM);
bw.Endianness = IO.Endianness.LittleEndian;
// Time zone offset from GMT in 15 minute intervals, starting at interval -48 (west) and running up to
// interval 52 (east). So value 0 indicates interval -48 which equals GMT-12 hours, and value 100
// indicates interval 52 which equals GMT+13 hours.
byte timeZoneOffset = br.ReadByte();
bw.WriteFixedLengthBytes(descriptor.rootDirectoryEntry, 34);
int iYear = Int32.Parse(szYear);
int iMonth = Int32.Parse(szMonth);
int iDay = Int32.Parse(szDay);
int iHour = Int32.Parse(szHour);
int iMinute = Int32.Parse(szMinute);
int iSecond = Int32.Parse(szSecond);
int iHundredSeconds = Int32.Parse(szHundredSeconds);
bw.WriteFixedLengthString(descriptor.volumeSet, 128, ' ');
bw.WriteFixedLengthString(descriptor.publisher, 128, ' ');
bw.WriteFixedLengthString(descriptor.dataPreparer, 128, ' ');
bw.WriteFixedLengthString(descriptor.application, 128, ' ');
bw.WriteFixedLengthString(descriptor.copyrightFile, 38, ' ');
bw.WriteFixedLengthString(descriptor.abstractFile, 36, ' ');
bw.WriteFixedLengthString(descriptor.bibliographicFile, 37, ' ');
try
{
DateTime dt = new DateTime(iYear, iMonth, iDay, iHour, iMinute, iSecond, iHundredSeconds);
return dt;
}
catch (Exception ex)
{
return DateTime.Now;
}
}
private void WriteDECDateTime(IO.Writer bw, DateTime dt)
{
bw.WriteFixedLengthString(dt.Year.ToString(), 4, ' ');
bw.WriteFixedLengthString(dt.Month.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Day.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Hour.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Minute.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Second.ToString(), 2, ' ');
bw.WriteFixedLengthString(dt.Millisecond.ToString(), 2, ' ');
WriteDECDateTime(bw, descriptor.timestampVolumeCreation);
WriteDECDateTime(bw, descriptor.timestampVolumeModification);
WriteDECDateTime(bw, descriptor.timestampVolumeExpiration);
WriteDECDateTime(bw, descriptor.timestampVolumeEffective);
bw.WriteByte(descriptor.fileStructureVersion);
bw.WriteBytes(descriptor.unused3);
bw.WriteFixedLengthBytes(descriptor.applicationSpecific, 512);
bw.WriteFixedLengthBytes(descriptor.reserved, 653);
}
}
// Time zone offset from GMT in 15 minute intervals, starting at interval -48 (west) and running up to
// interval 52 (east). So value 0 indicates interval -48 which equals GMT-12 hours, and value 100
// indicates interval 52 which equals GMT+13 hours.
byte timeZoneOffset = 0;
bw.WriteByte(timeZoneOffset);
}
protected override void SaveInternal(ObjectModel objectModel)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
IO.Writer bw = base.Accessor.Writer;
// skip system area
bw.Accessor.Seek(32768, SeekOrigin.Current);
Internal.PrimaryVolumeDescriptor descriptor = new Internal.PrimaryVolumeDescriptor();
descriptor.systemName = mvarSystemName; // The name of the system that can act upon sectors 0x00-0x0F for the volume.
descriptor.volumeName = mvarVolumeName; // Identification of this volume.
descriptor.volumeSetSize = mvarVolumeSetSize;
descriptor.volumeSequenceNumber = mvarVolumeSequenceNumber;
descriptor.logicalBlockSize = mvarLogicalBlockSize;
WritePrimaryVolumeDescriptor(bw, descriptor);
bw.Flush();
}
private void WritePrimaryVolumeDescriptor(IO.Writer bw, Internal.PrimaryVolumeDescriptor descriptor)
{
bw.WriteByte(descriptor.unused1);
bw.WriteFixedLengthString(descriptor.systemName, 32, ' ');
bw.WriteFixedLengthString(descriptor.volumeName, 32, ' ');
bw.WriteUInt64(descriptor.unused2);
bw.WriteDoubleEndianUInt32(descriptor.volumeSpaceSize);
bw.WriteFixedLengthBytes(descriptor.unused3, 32);
bw.WriteDoubleEndianUInt16(descriptor.volumeSetSize);
bw.WriteDoubleEndianUInt16(descriptor.volumeSequenceNumber);
bw.WriteDoubleEndianUInt16(descriptor.logicalBlockSize);
bw.WriteDoubleEndianUInt32(descriptor.pathTableSize);
bw.WriteUInt32(descriptor.pathTableLocationTypeL);
bw.WriteUInt32(descriptor.optionalPathTableLocationTypeL);
bw.Endianness = IO.Endianness.BigEndian;
bw.WriteUInt32(descriptor.pathTableLocationTypeM);
bw.WriteUInt32(descriptor.optionalPathTableLocationTypeM);
bw.Endianness = IO.Endianness.LittleEndian;
bw.WriteFixedLengthBytes(descriptor.rootDirectoryEntry, 34);
bw.WriteFixedLengthString(descriptor.volumeSet, 128, ' ');
bw.WriteFixedLengthString(descriptor.publisher, 128, ' ');
bw.WriteFixedLengthString(descriptor.dataPreparer, 128, ' ');
bw.WriteFixedLengthString(descriptor.application, 128, ' ');
bw.WriteFixedLengthString(descriptor.copyrightFile, 38, ' ');
bw.WriteFixedLengthString(descriptor.abstractFile, 36, ' ');
bw.WriteFixedLengthString(descriptor.bibliographicFile, 37, ' ');
WriteDECDateTime(bw, descriptor.timestampVolumeCreation);
WriteDECDateTime(bw, descriptor.timestampVolumeModification);
WriteDECDateTime(bw, descriptor.timestampVolumeExpiration);
WriteDECDateTime(bw, descriptor.timestampVolumeEffective);
bw.WriteByte(descriptor.fileStructureVersion);
bw.WriteBytes(descriptor.unused3);
bw.WriteFixedLengthBytes(descriptor.applicationSpecific, 512);
bw.WriteFixedLengthBytes(descriptor.reserved, 653);
}
}
}