mirror of
https://github.com/MobileTooling/Ffu2Vhdx.git
synced 2026-07-27 12:48:20 -07:00
Initial Content
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// 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.ApplePartitionMap
|
||||
{
|
||||
public sealed class BlockZero : IByteArraySerializable
|
||||
{
|
||||
public uint BlockCount;
|
||||
public ushort BlockSize;
|
||||
public ushort DeviceId;
|
||||
public ushort DeviceType;
|
||||
public ushort DriverCount;
|
||||
public uint DriverData;
|
||||
public ushort Signature;
|
||||
|
||||
public int Size
|
||||
{
|
||||
get { return 512; }
|
||||
}
|
||||
|
||||
public int ReadFrom(byte[] buffer, int offset)
|
||||
{
|
||||
Signature = EndianUtilities.ToUInt16BigEndian(buffer, offset + 0);
|
||||
BlockSize = EndianUtilities.ToUInt16BigEndian(buffer, offset + 2);
|
||||
BlockCount = EndianUtilities.ToUInt32BigEndian(buffer, offset + 4);
|
||||
DeviceType = EndianUtilities.ToUInt16BigEndian(buffer, offset + 8);
|
||||
DeviceId = EndianUtilities.ToUInt16BigEndian(buffer, offset + 10);
|
||||
DriverData = EndianUtilities.ToUInt32BigEndian(buffer, offset + 12);
|
||||
DriverCount = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 16);
|
||||
|
||||
return 512;
|
||||
}
|
||||
|
||||
public void WriteTo(byte[] buffer, int offset)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// 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.ObjectModel;
|
||||
using System.IO;
|
||||
using DiscUtils.Partitions;
|
||||
using DiscUtils.Streams;
|
||||
|
||||
namespace DiscUtils.ApplePartitionMap
|
||||
{
|
||||
/// <summary>
|
||||
/// Interprets Apple Partition Map structures that partition a disk.
|
||||
/// </summary>
|
||||
public sealed class PartitionMap : PartitionTable
|
||||
{
|
||||
private readonly PartitionMapEntry[] _partitions;
|
||||
private readonly Stream _stream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PartitionMap class.
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream containing the contents of a disk.</param>
|
||||
public PartitionMap(Stream stream)
|
||||
{
|
||||
_stream = stream;
|
||||
|
||||
stream.Position = 0;
|
||||
byte[] initialBytes = StreamUtilities.ReadExact(stream, 1024);
|
||||
|
||||
BlockZero b0 = new BlockZero();
|
||||
b0.ReadFrom(initialBytes, 0);
|
||||
|
||||
PartitionMapEntry initialPart = new PartitionMapEntry(_stream);
|
||||
initialPart.ReadFrom(initialBytes, 512);
|
||||
|
||||
byte[] partTableData = StreamUtilities.ReadExact(stream, (int)(initialPart.MapEntries - 1) * 512);
|
||||
|
||||
_partitions = new PartitionMapEntry[initialPart.MapEntries - 1];
|
||||
for (uint i = 0; i < initialPart.MapEntries - 1; ++i)
|
||||
{
|
||||
_partitions[i] = new PartitionMapEntry(_stream);
|
||||
_partitions[i].ReadFrom(partTableData, (int)(512 * i));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GUID of the disk, always returns Guid.Empty.
|
||||
/// </summary>
|
||||
public override Guid DiskGuid
|
||||
{
|
||||
get { return Guid.Empty; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the partitions present on the disk.
|
||||
/// </summary>
|
||||
public override ReadOnlyCollection<PartitionInfo> Partitions
|
||||
{
|
||||
get { return new ReadOnlyCollection<PartitionInfo>(_partitions); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new partition that encompasses the entire disk.
|
||||
/// </summary>
|
||||
/// <param name="type">The partition type.</param>
|
||||
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||
/// <returns>The index of the partition.</returns>
|
||||
/// <remarks>The partition table must be empty before this method is called,
|
||||
/// otherwise IOException is thrown.</remarks>
|
||||
public override int Create(WellKnownPartitionType type, bool active)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new partition with a target size.
|
||||
/// </summary>
|
||||
/// <param name="size">The target size (in bytes).</param>
|
||||
/// <param name="type">The partition type.</param>
|
||||
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||
/// <returns>The index of the new partition.</returns>
|
||||
public override int Create(long size, WellKnownPartitionType type, bool active)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new aligned partition that encompasses the entire disk.
|
||||
/// </summary>
|
||||
/// <param name="type">The partition type.</param>
|
||||
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||
/// <param name="alignment">The alignment (in byte).</param>
|
||||
/// <returns>The index of the partition.</returns>
|
||||
/// <remarks>The partition table must be empty before this method is called,
|
||||
/// otherwise IOException is thrown.</remarks>
|
||||
/// <remarks>
|
||||
/// Traditionally partitions were aligned to the physical structure of the underlying disk,
|
||||
/// however with modern storage greater efficiency is acheived by aligning partitions on
|
||||
/// large values that are a power of two.
|
||||
/// </remarks>
|
||||
public override int CreateAligned(WellKnownPartitionType type, bool active, int alignment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new aligned partition with a target size.
|
||||
/// </summary>
|
||||
/// <param name="size">The target size (in bytes).</param>
|
||||
/// <param name="type">The partition type.</param>
|
||||
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||
/// <param name="alignment">The alignment (in byte).</param>
|
||||
/// <returns>The index of the new partition.</returns>
|
||||
/// <remarks>
|
||||
/// Traditionally partitions were aligned to the physical structure of the underlying disk,
|
||||
/// however with modern storage greater efficiency is achieved by aligning partitions on
|
||||
/// large values that are a power of two.
|
||||
/// </remarks>
|
||||
public override int CreateAligned(long size, WellKnownPartitionType type, bool active, int alignment)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a partition at a given index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the partition.</param>
|
||||
public override void Delete(int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// 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.Partitions;
|
||||
using DiscUtils.Streams;
|
||||
|
||||
namespace DiscUtils.ApplePartitionMap
|
||||
{
|
||||
public sealed class PartitionMapEntry : PartitionInfo, IByteArraySerializable
|
||||
{
|
||||
private readonly Stream _diskStream;
|
||||
public uint BootBlock;
|
||||
public uint BootBytes;
|
||||
public uint Flags;
|
||||
public uint LogicalBlocks;
|
||||
public uint LogicalBlockStart;
|
||||
public uint MapEntries;
|
||||
public string Name;
|
||||
public uint PhysicalBlocks;
|
||||
public uint PhysicalBlockStart;
|
||||
public ushort Signature;
|
||||
public string Type;
|
||||
|
||||
public PartitionMapEntry(Stream diskStream)
|
||||
{
|
||||
_diskStream = diskStream;
|
||||
}
|
||||
|
||||
public override byte BiosType
|
||||
{
|
||||
get { return 0xAF; }
|
||||
}
|
||||
|
||||
public override long FirstSector
|
||||
{
|
||||
get { return PhysicalBlockStart; }
|
||||
}
|
||||
|
||||
public override Guid GuidType
|
||||
{
|
||||
get { return Guid.Empty; }
|
||||
}
|
||||
|
||||
public override long LastSector
|
||||
{
|
||||
get { return PhysicalBlockStart + PhysicalBlocks - 1; }
|
||||
}
|
||||
|
||||
public override string TypeAsString
|
||||
{
|
||||
get { return Type; }
|
||||
}
|
||||
|
||||
public override PhysicalVolumeType VolumeType
|
||||
{
|
||||
get { return PhysicalVolumeType.ApplePartition; }
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get { return 512; }
|
||||
}
|
||||
|
||||
public int ReadFrom(byte[] buffer, int offset)
|
||||
{
|
||||
Signature = EndianUtilities.ToUInt16BigEndian(buffer, offset + 0);
|
||||
MapEntries = EndianUtilities.ToUInt32BigEndian(buffer, offset + 4);
|
||||
PhysicalBlockStart = EndianUtilities.ToUInt32BigEndian(buffer, offset + 8);
|
||||
PhysicalBlocks = EndianUtilities.ToUInt32BigEndian(buffer, offset + 12);
|
||||
Name = EndianUtilities.BytesToString(buffer, offset + 16, 32).TrimEnd('\0');
|
||||
Type = EndianUtilities.BytesToString(buffer, offset + 48, 32).TrimEnd('\0');
|
||||
LogicalBlockStart = EndianUtilities.ToUInt32BigEndian(buffer, offset + 80);
|
||||
LogicalBlocks = EndianUtilities.ToUInt32BigEndian(buffer, offset + 84);
|
||||
Flags = EndianUtilities.ToUInt32BigEndian(buffer, offset + 88);
|
||||
BootBlock = EndianUtilities.ToUInt32BigEndian(buffer, offset + 92);
|
||||
BootBytes = EndianUtilities.ToUInt32BigEndian(buffer, offset + 96);
|
||||
|
||||
return 512;
|
||||
}
|
||||
|
||||
public void WriteTo(byte[] buffer, int offset)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override SparseStream Open()
|
||||
{
|
||||
return new SubStream(_diskStream, PhysicalBlockStart * 512, PhysicalBlocks * 512);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// 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.Partitions;
|
||||
using DiscUtils.Streams;
|
||||
|
||||
namespace DiscUtils.ApplePartitionMap
|
||||
{
|
||||
[PartitionTableFactory]
|
||||
public sealed class PartitionMapFactory : PartitionTableFactory
|
||||
{
|
||||
public override bool DetectIsPartitioned(Stream s)
|
||||
{
|
||||
if (s.Length < 1024)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
s.Position = 0;
|
||||
|
||||
byte[] initialBytes = StreamUtilities.ReadExact(s, 1024);
|
||||
|
||||
BlockZero b0 = new BlockZero();
|
||||
b0.ReadFrom(initialBytes, 0);
|
||||
if (b0.Signature != 0x4552)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PartitionMapEntry initialPart = new PartitionMapEntry(s);
|
||||
initialPart.ReadFrom(initialBytes, 512);
|
||||
|
||||
return initialPart.Signature == 0x504d;
|
||||
}
|
||||
|
||||
public override PartitionTable DetectPartitionTable(VirtualDisk disk)
|
||||
{
|
||||
if (!DetectIsPartitioned(disk.Content))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PartitionMap(disk.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// 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.Archives
|
||||
{
|
||||
public sealed class FileRecord
|
||||
{
|
||||
public long Length;
|
||||
public string Name;
|
||||
public long Start;
|
||||
|
||||
public FileRecord(string name, long start, long length)
|
||||
{
|
||||
Name = name;
|
||||
Start = start;
|
||||
Length = length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// 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;
|
||||
|
||||
namespace DiscUtils.Archives
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimal tar file format implementation.
|
||||
/// </summary>
|
||||
public sealed class TarFile
|
||||
{
|
||||
private readonly Dictionary<string, FileRecord> _files;
|
||||
private readonly Stream _fileStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the TarFile class.
|
||||
/// </summary>
|
||||
/// <param name="fileStream">The Tar file.</param>
|
||||
public TarFile(Stream fileStream)
|
||||
{
|
||||
_fileStream = fileStream;
|
||||
_files = new Dictionary<string, FileRecord>();
|
||||
|
||||
TarHeader hdr = new TarHeader();
|
||||
byte[] hdrBuf = StreamUtilities.ReadExact(_fileStream, TarHeader.Length);
|
||||
hdr.ReadFrom(hdrBuf, 0);
|
||||
while (hdr.FileLength != 0 || !string.IsNullOrEmpty(hdr.FileName))
|
||||
{
|
||||
FileRecord record = new FileRecord(hdr.FileName, _fileStream.Position, hdr.FileLength);
|
||||
_files.Add(record.Name, record);
|
||||
_fileStream.Position += (hdr.FileLength + 511) / 512 * 512;
|
||||
|
||||
hdrBuf = StreamUtilities.ReadExact(_fileStream, TarHeader.Length);
|
||||
hdr.ReadFrom(hdrBuf, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to open a file contained in the archive, if it exists.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the file within the archive.</param>
|
||||
/// <param name="stream">A stream containing the file contents, or null.</param>
|
||||
/// <returns><c>true</c> if the file could be opened, else <c>false</c>.</returns>
|
||||
public bool TryOpenFile(string path, out Stream stream)
|
||||
{
|
||||
if (_files.ContainsKey(path))
|
||||
{
|
||||
FileRecord file = _files[path];
|
||||
stream = new SubStream(_fileStream, file.Start, file.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open a file contained in the archive.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the file within the archive.</param>
|
||||
/// <returns>A stream containing the file contents.</returns>
|
||||
/// <exception cref="FileNotFoundException">Thrown if the file is not found.</exception>
|
||||
public Stream OpenFile(string path)
|
||||
{
|
||||
if (_files.ContainsKey(path))
|
||||
{
|
||||
FileRecord file = _files[path];
|
||||
return new SubStream(_fileStream, file.Start, file.Length);
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("File is not in archive", path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a given file exists in the archive.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to test.</param>
|
||||
/// <returns><c>true</c> if the file is present, else <c>false</c>.</returns>
|
||||
public bool FileExists(string path)
|
||||
{
|
||||
return _files.ContainsKey(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a given directory exists in the archive.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to test.</param>
|
||||
/// <returns><c>true</c> if the directory is present, else <c>false</c>.</returns>
|
||||
public bool DirExists(string path)
|
||||
{
|
||||
string searchStr = path;
|
||||
searchStr = searchStr.Replace(@"\", "/");
|
||||
searchStr = searchStr.EndsWith(@"/", StringComparison.Ordinal) ? searchStr : searchStr + @"/";
|
||||
|
||||
foreach (string filePath in _files.Keys)
|
||||
{
|
||||
if (filePath.StartsWith(searchStr, StringComparison.Ordinal))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<FileRecord> GetFiles(string dir)
|
||||
{
|
||||
string searchStr = dir;
|
||||
searchStr = searchStr.Replace(@"\", "/");
|
||||
searchStr = searchStr.EndsWith(@"/", StringComparison.Ordinal) ? searchStr : searchStr + @"/";
|
||||
|
||||
foreach (string filePath in _files.Keys)
|
||||
{
|
||||
if (filePath.StartsWith(searchStr, StringComparison.Ordinal))
|
||||
{
|
||||
yield return _files[filePath];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// 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;
|
||||
|
||||
namespace DiscUtils.Archives
|
||||
{
|
||||
/// <summary>
|
||||
/// Builder to create UNIX Tar archive files.
|
||||
/// </summary>
|
||||
public sealed class TarFileBuilder : StreamBuilder
|
||||
{
|
||||
private readonly List<UnixBuildFileRecord> _files;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TarFileBuilder"/> class.
|
||||
/// </summary>
|
||||
public TarFileBuilder()
|
||||
{
|
||||
_files = new List<UnixBuildFileRecord>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a file to the tar archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the file.</param>
|
||||
/// <param name="buffer">The file data.</param>
|
||||
public void AddFile(string name, byte[] buffer)
|
||||
{
|
||||
_files.Add(new UnixBuildFileRecord(name, buffer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a file to the tar archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the file.</param>
|
||||
/// <param name="buffer">The file data.</param>
|
||||
/// <param name="fileMode">The access mode of the file.</param>
|
||||
/// <param name="ownerId">The uid of the owner.</param>
|
||||
/// <param name="groupId">The gid of the owner.</param>
|
||||
/// <param name="modificationTime">The modification time for the file.</param>
|
||||
public void AddFile(
|
||||
string name, byte[] buffer, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||
DateTime modificationTime)
|
||||
{
|
||||
_files.Add(new UnixBuildFileRecord(name, buffer, fileMode, ownerId, groupId, modificationTime));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a file to the tar archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the file.</param>
|
||||
/// <param name="stream">The file data.</param>
|
||||
public void AddFile(string name, Stream stream)
|
||||
{
|
||||
_files.Add(new UnixBuildFileRecord(name, stream));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a file to the tar archive.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the file.</param>
|
||||
/// <param name="stream">The file data.</param>
|
||||
/// <param name="fileMode">The access mode of the file.</param>
|
||||
/// <param name="ownerId">The uid of the owner.</param>
|
||||
/// <param name="groupId">The gid of the owner.</param>
|
||||
/// <param name="modificationTime">The modification time for the file.</param>
|
||||
public void AddFile(
|
||||
string name, Stream stream, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||
DateTime modificationTime)
|
||||
{
|
||||
_files.Add(new UnixBuildFileRecord(name, stream, fileMode, ownerId, groupId, modificationTime));
|
||||
}
|
||||
|
||||
protected override List<BuilderExtent> FixExtents(out long totalLength)
|
||||
{
|
||||
List<BuilderExtent> result = new List<BuilderExtent>(_files.Count * 2 + 2);
|
||||
long pos = 0;
|
||||
|
||||
foreach (UnixBuildFileRecord file in _files)
|
||||
{
|
||||
BuilderExtent fileContentExtent = file.Fix(pos + TarHeader.Length);
|
||||
|
||||
result.Add(new TarHeaderExtent(
|
||||
pos, file.Name, fileContentExtent.Length, file.FileMode, file.OwnerId, file.GroupId,
|
||||
file.ModificationTime));
|
||||
pos += TarHeader.Length;
|
||||
|
||||
result.Add(fileContentExtent);
|
||||
pos += MathUtilities.RoundUp(fileContentExtent.Length, 512);
|
||||
}
|
||||
|
||||
// Two empty 512-byte blocks at end of tar file.
|
||||
result.Add(new BuilderBufferExtent(pos, new byte[1024]));
|
||||
|
||||
totalLength = pos + 1024;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// 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.Archives
|
||||
{
|
||||
public sealed class TarHeader
|
||||
{
|
||||
public const int Length = 512;
|
||||
public long FileLength;
|
||||
public UnixFilePermissions FileMode;
|
||||
|
||||
public string FileName;
|
||||
public int GroupId;
|
||||
public DateTime ModificationTime;
|
||||
public int OwnerId;
|
||||
|
||||
public void ReadFrom(byte[] buffer, int offset)
|
||||
{
|
||||
FileName = ReadNullTerminatedString(buffer, offset + 0, 100);
|
||||
FileMode = (UnixFilePermissions)OctalToLong(ReadNullTerminatedString(buffer, offset + 100, 8));
|
||||
OwnerId = (int)OctalToLong(ReadNullTerminatedString(buffer, offset + 108, 8));
|
||||
GroupId = (int)OctalToLong(ReadNullTerminatedString(buffer, offset + 116, 8));
|
||||
FileLength = OctalToLong(ReadNullTerminatedString(buffer, offset + 124, 12));
|
||||
ModificationTime = OctalToLong(ReadNullTerminatedString(buffer, offset + 136, 12)).FromUnixTimeSeconds().DateTime;
|
||||
}
|
||||
|
||||
public void WriteTo(byte[] buffer, int offset)
|
||||
{
|
||||
Array.Clear(buffer, offset, Length);
|
||||
|
||||
EndianUtilities.StringToBytes(FileName, buffer, offset, 99);
|
||||
EndianUtilities.StringToBytes(LongToOctal((long)FileMode, 7), buffer, offset + 100, 7);
|
||||
EndianUtilities.StringToBytes(LongToOctal(OwnerId, 7), buffer, offset + 108, 7);
|
||||
EndianUtilities.StringToBytes(LongToOctal(GroupId, 7), buffer, offset + 116, 7);
|
||||
EndianUtilities.StringToBytes(LongToOctal(FileLength, 11), buffer, offset + 124, 11);
|
||||
EndianUtilities.StringToBytes(LongToOctal(Convert.ToUInt32((new DateTimeOffset(ModificationTime)).ToUnixTimeSeconds()), 11), buffer, offset + 136, 11);
|
||||
|
||||
// Checksum
|
||||
EndianUtilities.StringToBytes(new string(' ', 8), buffer, offset + 148, 8);
|
||||
long checkSum = 0;
|
||||
for (int i = 0; i < 512; ++i)
|
||||
{
|
||||
checkSum += buffer[offset + i];
|
||||
}
|
||||
|
||||
EndianUtilities.StringToBytes(LongToOctal(checkSum, 7), buffer, offset + 148, 7);
|
||||
buffer[155] = 0;
|
||||
}
|
||||
|
||||
private static string ReadNullTerminatedString(byte[] buffer, int offset, int length)
|
||||
{
|
||||
return EndianUtilities.BytesToString(buffer, offset, length).TrimEnd('\0');
|
||||
}
|
||||
|
||||
private static long OctalToLong(string value)
|
||||
{
|
||||
long result = 0;
|
||||
|
||||
for (int i = 0; i < value.Length; ++i)
|
||||
{
|
||||
result = result * 8 + (value[i] - '0');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string LongToOctal(long value, int length)
|
||||
{
|
||||
string result = string.Empty;
|
||||
|
||||
while (value > 0)
|
||||
{
|
||||
result = (char)('0' + value % 8) + result;
|
||||
value = value / 8;
|
||||
}
|
||||
|
||||
return new string('0', length - result.Length) + result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// 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.Archives
|
||||
{
|
||||
public sealed class TarHeaderExtent : BuilderBufferExtent
|
||||
{
|
||||
private readonly long _fileLength;
|
||||
private readonly string _fileName;
|
||||
private readonly int _groupId;
|
||||
private readonly UnixFilePermissions _mode;
|
||||
private readonly DateTime _modificationTime;
|
||||
private readonly int _ownerId;
|
||||
|
||||
public TarHeaderExtent(long start, string fileName, long fileLength, UnixFilePermissions mode, int ownerId,
|
||||
int groupId, DateTime modificationTime)
|
||||
: base(start, 512)
|
||||
{
|
||||
_fileName = fileName;
|
||||
_fileLength = fileLength;
|
||||
_mode = mode;
|
||||
_ownerId = ownerId;
|
||||
_groupId = groupId;
|
||||
_modificationTime = modificationTime;
|
||||
}
|
||||
|
||||
public TarHeaderExtent(long start, string fileName, long fileLength)
|
||||
: this(start, fileName, fileLength, 0, 0, 0, DateTimeOffsetExtensions.UnixEpoch) {}
|
||||
|
||||
protected override byte[] GetBuffer()
|
||||
{
|
||||
byte[] buffer = new byte[TarHeader.Length];
|
||||
|
||||
TarHeader header = new TarHeader();
|
||||
header.FileName = _fileName;
|
||||
header.FileLength = _fileLength;
|
||||
header.FileMode = _mode;
|
||||
header.OwnerId = _ownerId;
|
||||
header.GroupId = _groupId;
|
||||
header.ModificationTime = _modificationTime;
|
||||
header.WriteTo(buffer, 0);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// 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.Streams;
|
||||
|
||||
namespace DiscUtils.Archives
|
||||
{
|
||||
public sealed class UnixBuildFileRecord
|
||||
{
|
||||
private readonly BuilderExtentSource _source;
|
||||
|
||||
public UnixBuildFileRecord(string name, byte[] buffer)
|
||||
: this(name, new BuilderBufferExtentSource(buffer), 0, 0, 0, DateTimeOffsetExtensions.UnixEpoch) {}
|
||||
|
||||
public UnixBuildFileRecord(string name, Stream stream)
|
||||
: this(name, new BuilderStreamExtentSource(stream), 0, 0, 0, DateTimeOffsetExtensions.UnixEpoch) {}
|
||||
|
||||
public UnixBuildFileRecord(
|
||||
string name, byte[] buffer, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||
DateTime modificationTime)
|
||||
: this(name, new BuilderBufferExtentSource(buffer), fileMode, ownerId, groupId, modificationTime) {}
|
||||
|
||||
public UnixBuildFileRecord(
|
||||
string name, Stream stream, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||
DateTime modificationTime)
|
||||
: this(name, new BuilderStreamExtentSource(stream), fileMode, ownerId, groupId, modificationTime) {}
|
||||
|
||||
public UnixBuildFileRecord(string name, BuilderExtentSource fileSource, UnixFilePermissions fileMode,
|
||||
int ownerId, int groupId, DateTime modificationTime)
|
||||
{
|
||||
Name = name;
|
||||
_source = fileSource;
|
||||
FileMode = fileMode;
|
||||
OwnerId = ownerId;
|
||||
GroupId = groupId;
|
||||
ModificationTime = modificationTime;
|
||||
}
|
||||
|
||||
public UnixFilePermissions FileMode { get; }
|
||||
|
||||
public int GroupId { get; }
|
||||
|
||||
public DateTime ModificationTime { get; }
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public int OwnerId { get; }
|
||||
|
||||
public BuilderExtent Fix(long pos)
|
||||
{
|
||||
return _source.Fix(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Class whose instances represent a CHS (Cylinder, Head, Sector) address on a disk.
|
||||
/// </summary>
|
||||
/// <remarks>Instances of this class are immutable.</remarks>
|
||||
public sealed class ChsAddress
|
||||
{
|
||||
/// <summary>
|
||||
/// The address of the first sector on any disk.
|
||||
/// </summary>
|
||||
public static readonly ChsAddress First = new ChsAddress(0, 0, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ChsAddress class.
|
||||
/// </summary>
|
||||
/// <param name="cylinder">The number of cylinders of the disk.</param>
|
||||
/// <param name="head">The number of heads (aka platters) of the disk.</param>
|
||||
/// <param name="sector">The number of sectors per track/cylinder of the disk.</param>
|
||||
public ChsAddress(int cylinder, int head, int sector)
|
||||
{
|
||||
Cylinder = cylinder;
|
||||
Head = head;
|
||||
Sector = sector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cylinder number (zero-based).
|
||||
/// </summary>
|
||||
public int Cylinder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the head (zero-based).
|
||||
/// </summary>
|
||||
public int Head { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sector number (one-based).
|
||||
/// </summary>
|
||||
public int Sector { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this object is equivalent to another.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test against.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="obj"/> is equivalent, else <c>false</c>.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ChsAddress other = (ChsAddress)obj;
|
||||
|
||||
return Cylinder == other.Cylinder && Head == other.Head && Sector == other.Sector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the hash code for this object.
|
||||
/// </summary>
|
||||
/// <returns>The hash code.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Cylinder.GetHashCode() ^ Head.GetHashCode() ^ Sector.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of this object, in the form (C/H/S).
|
||||
/// </summary>
|
||||
/// <returns>The string representation.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + Cylinder + "/" + Head + "/" + Sector + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// 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;
|
||||
|
||||
namespace DiscUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that identifies the role of each cluster in a file system.
|
||||
/// </summary>
|
||||
public sealed class ClusterMap
|
||||
{
|
||||
private readonly object[] _clusterToFileId;
|
||||
private readonly ClusterRoles[] _clusterToRole;
|
||||
private readonly Dictionary<object, string[]> _fileIdToPaths;
|
||||
|
||||
public ClusterMap(ClusterRoles[] clusterToRole, object[] clusterToFileId,
|
||||
Dictionary<object, string[]> fileIdToPaths)
|
||||
{
|
||||
_clusterToRole = clusterToRole;
|
||||
_clusterToFileId = clusterToFileId;
|
||||
_fileIdToPaths = fileIdToPaths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role of a cluster within the file system.
|
||||
/// </summary>
|
||||
/// <param name="cluster">The cluster to inspect.</param>
|
||||
/// <returns>The clusters role (or roles).</returns>
|
||||
public ClusterRoles GetRole(long cluster)
|
||||
{
|
||||
if (_clusterToRole == null || _clusterToRole.Length < cluster)
|
||||
{
|
||||
return ClusterRoles.None;
|
||||
}
|
||||
return _clusterToRole[cluster];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a cluster to a list of file names.
|
||||
/// </summary>
|
||||
/// <param name="cluster">The cluster to inspect.</param>
|
||||
/// <returns>A list of paths that map to the cluster.</returns>
|
||||
/// <remarks>A list is returned because on file systems with the notion of
|
||||
/// hard links, a cluster may correspond to multiple directory entries.</remarks>
|
||||
public string[] ClusterToPaths(long cluster)
|
||||
{
|
||||
if ((GetRole(cluster) & (ClusterRoles.DataFile | ClusterRoles.SystemFile)) != 0)
|
||||
{
|
||||
object fileId = _clusterToFileId[cluster];
|
||||
return _fileIdToPaths[fileId];
|
||||
}
|
||||
return new string[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace DiscUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of possible cluster roles.
|
||||
/// </summary>
|
||||
/// <remarks>A cluster may be in more than one role.</remarks>
|
||||
[Flags]
|
||||
public enum ClusterRoles
|
||||
{
|
||||
/// <summary>
|
||||
/// Unknown, or unspecified role.
|
||||
/// </summary>
|
||||
None = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Cluster is free.
|
||||
/// </summary>
|
||||
Free = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Cluster is in use by a normal file.
|
||||
/// </summary>
|
||||
DataFile = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Cluster is in use by a system file.
|
||||
/// </summary>
|
||||
/// <remarks>This isn't a file marked with the 'system' attribute,
|
||||
/// rather files that form part of the file system namespace but also
|
||||
/// form part of the file system meta-data.</remarks>
|
||||
SystemFile = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Cluster is in use for meta-data.
|
||||
/// </summary>
|
||||
Metadata = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// Cluster contains the boot region.
|
||||
/// </summary>
|
||||
BootArea = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// Cluster is marked bad.
|
||||
/// </summary>
|
||||
Bad = 0x20
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// 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.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the Adler-32 checksum algorithm.
|
||||
/// </summary>
|
||||
public class Adler32
|
||||
{
|
||||
private uint _a;
|
||||
private uint _b;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Adler32 class.
|
||||
/// </summary>
|
||||
public Adler32()
|
||||
{
|
||||
_a = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the checksum of all data processed so far.
|
||||
/// </summary>
|
||||
public int Value
|
||||
{
|
||||
get { return (int)(_b << 16 | _a); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides data that should be checksummed.
|
||||
/// </summary>
|
||||
/// <param name="buffer">Buffer containing the data to checksum.</param>
|
||||
/// <param name="offset">Offset of the first byte to checksum.</param>
|
||||
/// <param name="count">The number of bytes to checksum.</param>
|
||||
/// <remarks>
|
||||
/// Call this method repeatedly until all checksummed
|
||||
/// data has been processed.
|
||||
/// </remarks>
|
||||
public void Process(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
}
|
||||
|
||||
if (offset < 0 || offset > buffer.Length)
|
||||
{
|
||||
throw new ArgumentException("Offset outside of array bounds", nameof(offset));
|
||||
}
|
||||
|
||||
if (count < 0 || offset + count > buffer.Length)
|
||||
{
|
||||
throw new ArgumentException("Array index out of bounds", nameof(count));
|
||||
}
|
||||
|
||||
int processed = 0;
|
||||
while (processed < count)
|
||||
{
|
||||
int innerEnd = Math.Min(count, processed + 2000);
|
||||
while (processed < innerEnd)
|
||||
{
|
||||
_a += buffer[processed++];
|
||||
_b += _a;
|
||||
}
|
||||
|
||||
_a %= 65521;
|
||||
_b %= 65521;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
public class BZip2BlockDecoder
|
||||
{
|
||||
private readonly InverseBurrowsWheeler _inverseBurrowsWheeler;
|
||||
|
||||
public BZip2BlockDecoder(int blockSize)
|
||||
{
|
||||
_inverseBurrowsWheeler = new InverseBurrowsWheeler(blockSize);
|
||||
}
|
||||
|
||||
public uint Crc { get; private set; }
|
||||
|
||||
public int Process(BitStream bitstream, byte[] outputBuffer, int outputBufferOffset)
|
||||
{
|
||||
Crc = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
Crc = (Crc << 8) | bitstream.Read(8);
|
||||
}
|
||||
|
||||
bool rand = bitstream.Read(1) != 0;
|
||||
int origPtr = (int)bitstream.Read(24);
|
||||
|
||||
int thisBlockSize = ReadBuffer(bitstream, outputBuffer, outputBufferOffset);
|
||||
|
||||
_inverseBurrowsWheeler.OriginalIndex = origPtr;
|
||||
_inverseBurrowsWheeler.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer,
|
||||
outputBufferOffset);
|
||||
|
||||
if (rand)
|
||||
{
|
||||
BZip2Randomizer randomizer = new BZip2Randomizer();
|
||||
randomizer.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer, outputBufferOffset);
|
||||
}
|
||||
|
||||
return thisBlockSize;
|
||||
}
|
||||
|
||||
private static int ReadBuffer(BitStream bitstream, byte[] buffer, int offset)
|
||||
{
|
||||
// The MTF state
|
||||
int numInUse = 0;
|
||||
MoveToFront moveFrontTransform = new MoveToFront();
|
||||
bool[] inUseGroups = new bool[16];
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
inUseGroups[i] = bitstream.Read(1) != 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
if (inUseGroups[i / 16])
|
||||
{
|
||||
if (bitstream.Read(1) != 0)
|
||||
{
|
||||
moveFrontTransform.Set(numInUse, (byte)i);
|
||||
numInUse++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize 'virtual' Huffman tree from bitstream
|
||||
BZip2CombinedHuffmanTrees huffmanTree = new BZip2CombinedHuffmanTrees(bitstream, numInUse + 2);
|
||||
|
||||
// Main loop reading data
|
||||
int readBytes = 0;
|
||||
while (true)
|
||||
{
|
||||
uint symbol = huffmanTree.NextSymbol();
|
||||
|
||||
if (symbol < 2)
|
||||
{
|
||||
// RLE, with length stored in a binary-style format
|
||||
uint runLength = 0;
|
||||
int bitShift = 0;
|
||||
while (symbol < 2)
|
||||
{
|
||||
runLength += (symbol + 1) << bitShift;
|
||||
bitShift++;
|
||||
|
||||
symbol = huffmanTree.NextSymbol();
|
||||
}
|
||||
|
||||
byte b = moveFrontTransform.Head;
|
||||
while (runLength > 0)
|
||||
{
|
||||
buffer[offset + readBytes] = b;
|
||||
++readBytes;
|
||||
--runLength;
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol <= numInUse)
|
||||
{
|
||||
// Single byte
|
||||
byte b = moveFrontTransform.GetAndMove((int)symbol - 1);
|
||||
buffer[offset + readBytes] = b;
|
||||
++readBytes;
|
||||
}
|
||||
else if (symbol == numInUse + 1)
|
||||
{
|
||||
// End of block marker
|
||||
return readBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidDataException("Invalid symbol from Huffman table");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents scheme used by BZip2 where multiple Huffman trees are used as a
|
||||
/// virtual Huffman tree, with a logical selector every 50 bits in the bit stream.
|
||||
/// </summary>
|
||||
public class BZip2CombinedHuffmanTrees
|
||||
{
|
||||
private HuffmanTree _activeTree;
|
||||
private readonly BitStream _bitstream;
|
||||
private int _nextSelector;
|
||||
private byte[] _selectors;
|
||||
private int _symbolsToNextSelector;
|
||||
private HuffmanTree[] _trees;
|
||||
|
||||
public BZip2CombinedHuffmanTrees(BitStream bitstream, int maxSymbols)
|
||||
{
|
||||
_bitstream = bitstream;
|
||||
|
||||
Initialize(maxSymbols);
|
||||
}
|
||||
|
||||
public uint NextSymbol()
|
||||
{
|
||||
if (_symbolsToNextSelector == 0)
|
||||
{
|
||||
_symbolsToNextSelector = 50;
|
||||
_activeTree = _trees[_selectors[_nextSelector]];
|
||||
_nextSelector++;
|
||||
}
|
||||
|
||||
_symbolsToNextSelector--;
|
||||
|
||||
return _activeTree.NextSymbol(_bitstream);
|
||||
}
|
||||
|
||||
private void Initialize(int maxSymbols)
|
||||
{
|
||||
int numTrees = (int)_bitstream.Read(3);
|
||||
if (numTrees < 2 || numTrees > 6)
|
||||
{
|
||||
throw new InvalidDataException("Invalid number of tables");
|
||||
}
|
||||
|
||||
int numSelectors = (int)_bitstream.Read(15);
|
||||
if (numSelectors < 1)
|
||||
{
|
||||
throw new InvalidDataException("Invalid number of selectors");
|
||||
}
|
||||
|
||||
_selectors = new byte[numSelectors];
|
||||
MoveToFront mtf = new MoveToFront(numTrees, true);
|
||||
for (int i = 0; i < numSelectors; ++i)
|
||||
{
|
||||
_selectors[i] = mtf.GetAndMove(CountSetBits(numTrees));
|
||||
}
|
||||
|
||||
_trees = new HuffmanTree[numTrees];
|
||||
for (int t = 0; t < numTrees; ++t)
|
||||
{
|
||||
uint[] lengths = new uint[maxSymbols];
|
||||
|
||||
uint len = _bitstream.Read(5);
|
||||
for (int i = 0; i < maxSymbols; ++i)
|
||||
{
|
||||
if (len < 1 || len > 20)
|
||||
{
|
||||
throw new InvalidDataException("Invalid length constructing Huffman tree");
|
||||
}
|
||||
|
||||
while (_bitstream.Read(1) != 0)
|
||||
{
|
||||
len = _bitstream.Read(1) == 0 ? len + 1 : len - 1;
|
||||
|
||||
if (len < 1 || len > 20)
|
||||
{
|
||||
throw new InvalidDataException("Invalid length constructing Huffman tree");
|
||||
}
|
||||
}
|
||||
|
||||
lengths[i] = len;
|
||||
}
|
||||
|
||||
_trees[t] = new HuffmanTree(lengths);
|
||||
}
|
||||
|
||||
_symbolsToNextSelector = 0;
|
||||
_nextSelector = 0;
|
||||
}
|
||||
|
||||
private byte CountSetBits(int max)
|
||||
{
|
||||
byte val = 0;
|
||||
while (_bitstream.Read(1) != 0)
|
||||
{
|
||||
val++;
|
||||
if (val >= max)
|
||||
{
|
||||
throw new InvalidDataException("Exceeded max number of consecutive bits");
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using DiscUtils.Internal;
|
||||
using DiscUtils.Streams;
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of a BZip2 decoder.
|
||||
/// </summary>
|
||||
public sealed class BZip2DecoderStream : Stream
|
||||
{
|
||||
private readonly BitStream _bitstream;
|
||||
|
||||
private readonly byte[] _blockBuffer;
|
||||
private uint _blockCrc;
|
||||
private readonly BZip2BlockDecoder _blockDecoder;
|
||||
private Crc32 _calcBlockCrc;
|
||||
private uint _calcCompoundCrc;
|
||||
private uint _compoundCrc;
|
||||
private Stream _compressedStream;
|
||||
|
||||
private bool _eof;
|
||||
private readonly Ownership _ownsCompressed;
|
||||
private long _position;
|
||||
private BZip2RleStream _rleStream;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BZip2DecoderStream class.
|
||||
/// </summary>
|
||||
/// <param name="stream">The compressed input stream.</param>
|
||||
/// <param name="ownsStream">Whether ownership of stream passes to the new instance.</param>
|
||||
public BZip2DecoderStream(Stream stream, Ownership ownsStream)
|
||||
{
|
||||
_compressedStream = stream;
|
||||
_ownsCompressed = ownsStream;
|
||||
|
||||
_bitstream = new BigEndianBitStream(new BufferedStream(stream));
|
||||
|
||||
// The Magic BZh
|
||||
byte[] magic = new byte[3];
|
||||
magic[0] = (byte)_bitstream.Read(8);
|
||||
magic[1] = (byte)_bitstream.Read(8);
|
||||
magic[2] = (byte)_bitstream.Read(8);
|
||||
if (magic[0] != 0x42 || magic[1] != 0x5A || magic[2] != 0x68)
|
||||
{
|
||||
throw new InvalidDataException("Bad magic at start of stream");
|
||||
}
|
||||
|
||||
// The size of the decompression blocks in multiples of 100,000
|
||||
int blockSize = (int)_bitstream.Read(8) - 0x30;
|
||||
if (blockSize < 1 || blockSize > 9)
|
||||
{
|
||||
throw new InvalidDataException("Unexpected block size in header: " + blockSize);
|
||||
}
|
||||
|
||||
blockSize *= 100000;
|
||||
|
||||
_rleStream = new BZip2RleStream();
|
||||
_blockDecoder = new BZip2BlockDecoder(blockSize);
|
||||
_blockBuffer = new byte[blockSize];
|
||||
|
||||
if (ReadBlock() == 0)
|
||||
{
|
||||
_eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication of whether read access is permitted.
|
||||
/// </summary>
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication of whether seeking is permitted.
|
||||
/// </summary>
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an indication of whether write access is permitted.
|
||||
/// </summary>
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the stream (the capacity of the underlying buffer).
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets and sets the current position within the stream.
|
||||
/// </summary>
|
||||
public override long Position
|
||||
{
|
||||
get { return _position; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes all data to the underlying storage.
|
||||
/// </summary>
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a number of bytes from the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The destination buffer.</param>
|
||||
/// <param name="offset">The start offset within the destination buffer.</param>
|
||||
/// <param name="count">The number of bytes to read.</param>
|
||||
/// <returns>The number of bytes read.</returns>
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
}
|
||||
|
||||
if (buffer.Length < offset + count)
|
||||
{
|
||||
throw new ArgumentException("Buffer smaller than declared");
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
throw new ArgumentException("Offset less than zero", nameof(offset));
|
||||
}
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
throw new ArgumentException("Count less than zero", nameof(count));
|
||||
}
|
||||
|
||||
if (_eof)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numRead = _rleStream.Read(buffer, offset, count);
|
||||
if (numRead == 0)
|
||||
{
|
||||
// If there was an existing block, check it's crc.
|
||||
if (_calcBlockCrc != null)
|
||||
{
|
||||
if (_blockCrc != _calcBlockCrc.Value)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - block CRC mismatch");
|
||||
}
|
||||
|
||||
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
|
||||
}
|
||||
|
||||
// Read a new block (if any), if none - check the overall CRC before returning
|
||||
if (ReadBlock() == 0)
|
||||
{
|
||||
_eof = true;
|
||||
if (_calcCompoundCrc != _compoundCrc)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - compound CRC");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
numRead = _rleStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
_calcBlockCrc.Process(buffer, offset, numRead);
|
||||
|
||||
// Pre-read next block, so a client that knows the decompressed length will still
|
||||
// have the overall CRC calculated.
|
||||
if (_rleStream.AtEof)
|
||||
{
|
||||
// If there was an existing block, check it's crc.
|
||||
if (_calcBlockCrc != null)
|
||||
{
|
||||
if (_blockCrc != _calcBlockCrc.Value)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - block CRC mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
|
||||
if (ReadBlock() == 0)
|
||||
{
|
||||
_eof = true;
|
||||
if (_calcCompoundCrc != _compoundCrc)
|
||||
{
|
||||
throw new InvalidDataException("Decompression failed - compound CRC mismatch");
|
||||
}
|
||||
|
||||
return numRead;
|
||||
}
|
||||
}
|
||||
|
||||
_position += numRead;
|
||||
return numRead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current stream position.
|
||||
/// </summary>
|
||||
/// <param name="offset">The origin-relative stream position.</param>
|
||||
/// <param name="origin">The origin for the stream position.</param>
|
||||
/// <returns>The new stream position.</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the length of the stream (the underlying buffer's capacity).
|
||||
/// </summary>
|
||||
/// <param name="value">The new length of the stream.</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a buffer to the stream.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer to write.</param>
|
||||
/// <param name="offset">The starting offset within buffer.</param>
|
||||
/// <param name="count">The number of bytes to write.</param>
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases underlying resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Whether this method is called from Dispose.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_compressedStream != null && _ownsCompressed == Ownership.Dispose)
|
||||
{
|
||||
_compressedStream.Dispose();
|
||||
}
|
||||
|
||||
_compressedStream = null;
|
||||
|
||||
if (_rleStream != null)
|
||||
{
|
||||
_rleStream.Dispose();
|
||||
_rleStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadBlock()
|
||||
{
|
||||
ulong marker = ReadMarker();
|
||||
if (marker == 0x314159265359)
|
||||
{
|
||||
int blockSize = _blockDecoder.Process(_bitstream, _blockBuffer, 0);
|
||||
_rleStream.Reset(_blockBuffer, 0, blockSize);
|
||||
_blockCrc = _blockDecoder.Crc;
|
||||
_calcBlockCrc = new Crc32BigEndian(Crc32Algorithm.Common);
|
||||
return blockSize;
|
||||
}
|
||||
if (marker == 0x177245385090)
|
||||
{
|
||||
_compoundCrc = ReadUint();
|
||||
return 0;
|
||||
}
|
||||
throw new InvalidDataException("Found invalid marker in stream");
|
||||
}
|
||||
|
||||
private uint ReadUint()
|
||||
{
|
||||
uint val = 0;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
val = (val << 8) | _bitstream.Read(8);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private ulong ReadMarker()
|
||||
{
|
||||
ulong marker = 0;
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
marker = (marker << 8) | _bitstream.Read(8);
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
public class BZip2Randomizer : DataBlockTransform
|
||||
{
|
||||
private static readonly int[] RandomVals =
|
||||
{
|
||||
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||
936, 638
|
||||
};
|
||||
|
||||
protected override bool BuffersMustNotOverlap
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||
{
|
||||
if (input != output || inputOffset != outputOffset)
|
||||
{
|
||||
Array.Copy(input, inputOffset, output, outputOffset, inputCount);
|
||||
}
|
||||
|
||||
int randIndex = 1;
|
||||
int nextByte = RandomVals[0] - 2;
|
||||
|
||||
while (nextByte < inputCount)
|
||||
{
|
||||
output[nextByte] ^= 1;
|
||||
nextByte += RandomVals[randIndex++];
|
||||
randIndex &= 0x1FF;
|
||||
}
|
||||
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
protected override int MaxOutputCount(int inputCount)
|
||||
{
|
||||
return inputCount;
|
||||
}
|
||||
|
||||
protected override int MinOutputCount(int inputCount)
|
||||
{
|
||||
return inputCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
//
|
||||
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
public class BZip2RleStream : Stream
|
||||
{
|
||||
private byte[] _blockBuffer;
|
||||
private int _blockOffset;
|
||||
private int _blockRemaining;
|
||||
private byte _lastByte;
|
||||
|
||||
private int _numSame;
|
||||
private long _position;
|
||||
private int _runBytesOutstanding;
|
||||
|
||||
public bool AtEof
|
||||
{
|
||||
get { return _runBytesOutstanding == 0 && _blockRemaining == 0; }
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { return _position; }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public void Reset(byte[] buffer, int offset, int count)
|
||||
{
|
||||
_position = 0;
|
||||
_blockBuffer = buffer;
|
||||
_blockOffset = offset;
|
||||
_blockRemaining = count;
|
||||
_numSame = -1;
|
||||
_lastByte = 0;
|
||||
_runBytesOutstanding = 0;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int numRead = 0;
|
||||
|
||||
while (numRead < count && _runBytesOutstanding > 0)
|
||||
{
|
||||
int runCount = Math.Min(_runBytesOutstanding, count);
|
||||
for (int i = 0; i < runCount; ++i)
|
||||
{
|
||||
buffer[offset + numRead] = _lastByte;
|
||||
}
|
||||
|
||||
_runBytesOutstanding -= runCount;
|
||||
numRead += runCount;
|
||||
}
|
||||
|
||||
while (numRead < count && _blockRemaining > 0)
|
||||
{
|
||||
byte b = _blockBuffer[_blockOffset];
|
||||
++_blockOffset;
|
||||
--_blockRemaining;
|
||||
|
||||
if (_numSame == 4)
|
||||
{
|
||||
int runCount = Math.Min(b, count - numRead);
|
||||
for (int i = 0; i < runCount; ++i)
|
||||
{
|
||||
buffer[offset + numRead] = _lastByte;
|
||||
numRead++;
|
||||
}
|
||||
|
||||
_runBytesOutstanding = b - runCount;
|
||||
_numSame = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b != _lastByte || _numSame <= 0)
|
||||
{
|
||||
_lastByte = b;
|
||||
_numSame = 0;
|
||||
}
|
||||
|
||||
buffer[offset + numRead] = b;
|
||||
numRead++;
|
||||
_numSame++;
|
||||
}
|
||||
}
|
||||
|
||||
_position += numRead;
|
||||
return numRead;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.IO;
|
||||
|
||||
namespace DiscUtils.Compression
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a byte stream into a bit stream.
|
||||
/// </summary>
|
||||
public class BigEndianBitStream : BitStream
|
||||
{
|
||||
private uint _buffer;
|
||||
private int _bufferAvailable;
|
||||
private readonly Stream _byteStream;
|
||||
|
||||
private readonly byte[] _readBuffer = new byte[2];
|
||||
|
||||
public BigEndianBitStream(Stream byteStream)
|
||||
{
|
||||
_byteStream = byteStream;
|
||||
}
|
||||
|
||||
public override int MaxReadAhead
|
||||
{
|
||||
get { return 16; }
|
||||
}
|
||||
|
||||
public override uint Read(int count)
|
||||
{
|
||||
if (count > 16)
|
||||
{
|
||||
uint result = Read(16) << (count - 16);
|
||||
return result | Read(count - 16);
|
||||
}
|
||||
|
||||
EnsureBufferFilled();
|
||||
|
||||
_bufferAvailable -= count;
|
||||
|
||||
uint mask = (uint)((1 << count) - 1);
|
||||
|
||||
return (_buffer >> _bufferAvailable) & mask;
|
||||
}
|
||||
|
||||
public override uint Peek(int count)
|
||||
{
|
||||
EnsureBufferFilled();
|
||||
|
||||
uint mask = (uint)((1 << count) - 1);
|
||||
|
||||
return (_buffer >> (_bufferAvailable - count)) & mask;
|
||||
}
|
||||
|
||||
public override void Consume(int count)
|
||||
{
|
||||
EnsureBufferFilled();
|
||||
|
||||
_bufferAvailable -= count;
|
||||
}
|
||||
|
||||
private void EnsureBufferFilled()
|
||||
{
|
||||
if (_bufferAvailable < 16)
|
||||
{
|
||||
_readBuffer[0] = 0;
|
||||
_readBuffer[1] = 0;
|
||||
_byteStream.Read(_readBuffer, 0, 2);
|
||||
|
||||
_buffer = _buffer << 16 | (uint)(_readBuffer[0] << 8) | _readBuffer[1];
|
||||
_bufferAvailable += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user