initial commit of media shit

This commit is contained in:
louis 2020-02-18 18:44:58 -05:00
commit 8c0a5e3aa7
38 changed files with 9195 additions and 0 deletions

View file

@ -0,0 +1,222 @@
using System;
using System.Collections.Generic;
using System.IO;
using VGMToolbox.util;
namespace vgm_usm.extract
{
public class CriUsmStream : MpegStream
{
public const string DefaultAudioExtension = ".adx";
public const string DefaultVideoExtension = ".m2v";
public const string HcaAudioExtension = ".hca";
static readonly byte[] HCA_SIG_BYTES = new byte[] { 0x48, 0x43, 0x41, 0x00 };
protected static readonly byte[] ALP_BYTES = new byte[] { 0x40, 0x41, 0x4C, 0x50 };
protected static readonly byte[] CRID_BYTES = new byte[] { 0x43, 0x52, 0x49, 0x44 };
protected static readonly byte[] SFV_BYTES = new byte[] { 0x40, 0x53, 0x46, 0x56 };
protected static readonly byte[] SFA_BYTES = new byte[] { 0x40, 0x53, 0x46, 0x41 };
protected static readonly byte[] SBT_BYTES = new byte[] { 0x40, 0x53, 0x42, 0x54 };
protected static readonly byte[] CUE_BYTES = new byte[] { 0x40, 0x43, 0x55, 0x45 };
protected static readonly byte[] UTF_BYTES = new byte[] { 0x40, 0x55, 0x54, 0x46 };
protected static readonly byte[] HEADER_END_BYTES =
new byte[] { 0x23, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20,
0x45, 0x4E, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x00 };
protected static readonly byte[] METADATA_END_BYTES =
new byte[] { 0x23, 0x4D, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54,
0x41, 0x20, 0x45, 0x4E, 0x44, 0x20, 0x20, 0x20,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x00 };
protected static readonly byte[] CONTENTS_END_BYTES =
new byte[] { 0x23, 0x43, 0x4F, 0x4E, 0x54, 0x45, 0x4E, 0x54,
0x53, 0x20, 0x45, 0x4E, 0x44, 0x20, 0x20, 0x20,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x00 };
public CriUsmStream(string path)
: base(path)
{
this.UsesSameIdForMultipleAudioTracks = true;
this.FileExtensionAudio = DefaultAudioExtension;
this.FileExtensionVideo = DefaultVideoExtension;
base.BlockIdDictionary.Clear();
base.BlockIdDictionary[BitConverter.ToUInt32(ALP_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @ALP
base.BlockIdDictionary[BitConverter.ToUInt32(CRID_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // CRID
base.BlockIdDictionary[BitConverter.ToUInt32(SFV_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SFV
base.BlockIdDictionary[BitConverter.ToUInt32(SFA_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SFA
base.BlockIdDictionary[BitConverter.ToUInt32(SBT_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @SBT
base.BlockIdDictionary[BitConverter.ToUInt32(CUE_BYTES, 0)] = new BlockSizeStruct(PacketSizeType.SizeBytes, 4); // @CUE
}
protected override byte[] GetPacketStartBytes() { return CRID_BYTES; }
protected override int GetAudioPacketHeaderSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "8";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override int GetVideoPacketHeaderSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "8";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override bool IsThisAnAudioBlock(byte[] blockToCheck)
{
return ParseFile.CompareSegment(blockToCheck, 0, SFA_BYTES);
}
protected override bool IsThisAVideoBlock(byte[] blockToCheck)
{
return ParseFile.CompareSegment(blockToCheck, 0, SFV_BYTES);
}
protected override byte GetStreamId(Stream readStream, long currentOffset)
{
byte streamId;
streamId = ParseFile.ParseSimpleOffset(readStream, currentOffset + 0xC, 1)[0];
return streamId;
}
protected override int GetAudioPacketFooterSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "0xA";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override int GetVideoPacketFooterSize(Stream readStream, long currentOffset)
{
UInt16 checkBytes;
OffsetDescription od = new OffsetDescription();
od.OffsetByteOrder = Constants.BigEndianByteOrder;
od.OffsetSize = "2";
od.OffsetValue = "0xA";
checkBytes = (UInt16)ParseFile.GetVaryingByteValueAtRelativeOffset(readStream, od, currentOffset);
return checkBytes;
}
protected override void DoFinalTasks(FileStream sourceFileStream, Dictionary<uint, FileStream> outputFiles, bool addHeader)
{
long headerEndOffset;
long metadataEndOffset;
long headerSize;
long footerOffset;
long footerSize;
string sourceFileName;
string workingFile;
string fileExtension;
string destinationFileName;
foreach (uint streamId in outputFiles.Keys)
{
sourceFileName = outputFiles[streamId].Name;
//--------------------------
// get header size
//--------------------------
headerEndOffset = ParseFile.GetNextOffset(outputFiles[streamId], 0, HEADER_END_BYTES);
metadataEndOffset = ParseFile.GetNextOffset(outputFiles[streamId], 0, METADATA_END_BYTES);
if (metadataEndOffset > headerEndOffset)
{
headerSize = metadataEndOffset + METADATA_END_BYTES.Length;
}
else
{
headerSize = headerEndOffset + METADATA_END_BYTES.Length;
}
//-----------------
// get footer size
//-----------------
footerOffset = ParseFile.GetNextOffset(outputFiles[streamId], 0, CONTENTS_END_BYTES) - headerSize;
footerSize = outputFiles[streamId].Length - footerOffset;
//------------------------------------------
// check data to adjust extension if needed
//------------------------------------------
if (this.IsThisAnAudioBlock(BitConverter.GetBytes(streamId & 0xFFFFFFF0))) // may need to change mask if more than 0xF streams
{
byte[] checkBytes = ParseFile.ParseSimpleOffset(outputFiles[streamId], headerSize, 4);
if (ParseFile.CompareSegment(checkBytes, 0, SofdecStream.AixSignatureBytes))
{
fileExtension = SofdecStream.AixAudioExtension;
}
else if (checkBytes[0] == 0x80)
{
fileExtension = SofdecStream.AdxAudioExtension;
}
else if (ParseFile.CompareSegment(checkBytes, 0, HCA_SIG_BYTES))
{
fileExtension = HcaAudioExtension;
}
else
{
fileExtension = ".bin";
}
}
else
{
fileExtension = Path.GetExtension(sourceFileName);
}
outputFiles[streamId].Close();
outputFiles[streamId].Dispose();
workingFile = FileUtil.RemoveChunkFromFile(sourceFileName, 0, headerSize);
File.Copy(workingFile, sourceFileName, true);
File.Delete(workingFile);
workingFile = FileUtil.RemoveChunkFromFile(sourceFileName, footerOffset, footerSize);
destinationFileName = Path.ChangeExtension(sourceFileName, fileExtension);
File.Copy(workingFile, destinationFileName, true);
File.Delete(workingFile);
if ((sourceFileName != destinationFileName) && (File.Exists(sourceFileName)))
{
File.Delete(sourceFileName);
}
}
}
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.IO;
namespace vgm_usm.extract
{
public class Mpeg1Stream : MpegStream
{
public const string DefaultAudioExtension = ".mp2";
public const string DefaultVideoExtension = ".m1v";
public Mpeg1Stream(string path)
: base(path)
{
this.FileExtensionAudio = DefaultAudioExtension;
this.FileExtensionVideo = DefaultVideoExtension;
base.BlockIdDictionary[BitConverter.ToUInt32(MpegStream.PacketStartBytes, 0)] = new BlockSizeStruct(PacketSizeType.Static, 0xC); // Pack Header
}
protected override int GetAudioPacketHeaderSize(Stream readStream, long currentOffset)
{
int paddingByteCount = 0;
readStream.Position = currentOffset + 6;
// skip stuffing bytes
while (readStream.ReadByte() == 0xFF)
{
paddingByteCount++;
}
return paddingByteCount + 7;
}
protected override int GetVideoPacketHeaderSize(Stream readStream, long currentOffset)
{
return 0xC;
}
}
}

View file

@ -0,0 +1,503 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using VGMToolbox.util;
namespace vgm_usm.extract
{
public abstract class MpegStream
{
protected static readonly byte[] PacketStartBytes = new byte[] { 0x00, 0x00, 0x01, 0xBA };
protected static readonly byte[] PacketEndBytes = new byte[] { 0x00, 0x00, 0x01, 0xB9 };
public MpegStream(string path)
{
this.FilePath = path;
this.UsesSameIdForMultipleAudioTracks = false;
this.SubTitleExtractionSupported = false;
this.BlockSizeIsLittleEndian = false;
//********************
// Add Slice Packets
//********************
byte[] sliceBytes;
uint sliceBytesValue;
BlockSizeStruct blockSize = new BlockSizeStruct(PacketSizeType.Static, 0xE);
for (byte i = 0; i <= 0xAF; i++)
{
sliceBytes = new byte[] { 0x00, 0x00, 0x01, i };
sliceBytesValue = BitConverter.ToUInt32(sliceBytes, 0);
this.BlockIdDictionary.Add(sliceBytesValue, blockSize);
}
}
public enum PacketSizeType
{
Static,
SizeBytes,
Eof
}
public struct MpegDemuxOptions
{
public bool AddHeader { set; get; }
}
public struct BlockSizeStruct
{
public PacketSizeType SizeType;
public int Size;
public BlockSizeStruct(PacketSizeType sizeTypeValue, int sizeValue)
{
this.SizeType = sizeTypeValue;
this.Size = sizeValue;
}
}
public struct DemuxOptionsStruct
{
public bool ExtractVideo { set; get; }
public bool ExtractAudio { set; get; }
public bool AddHeader { set; get; }
public bool SplitAudioStreams { set; get; }
public bool AddPlaybackHacks { set; get; }
}
#region Dictionary Initialization
protected Dictionary<uint, BlockSizeStruct> BlockIdDictionary =
new Dictionary<uint, BlockSizeStruct>
{
//********************
// System Packets
//********************
{BitConverter.ToUInt32(MpegStream.PacketEndBytes, 0), new BlockSizeStruct(PacketSizeType.Eof, -1)}, // Program End
{BitConverter.ToUInt32(MpegStream.PacketStartBytes, 0), new BlockSizeStruct(PacketSizeType.Static, 0xE)}, // Pack Header
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xBB }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // System Header, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xBD }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Private Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xBE }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Padding Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xBF }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Private Stream, two bytes following equal length (Big Endian)
//****************************
// Audio Streams
//****************************
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC0 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC1 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC2 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC3 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC4 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC5 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC6 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC7 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC8 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xC9 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xCA }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xCB }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xCC }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xCD }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xCE }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xCF }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD0 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD1 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD2 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD3 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD4 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD5 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD6 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD7 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD8 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xD9 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xDA }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xDB }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xDC }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xDD }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xDE }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xDF }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Audio Stream, two bytes following equal length (Big Endian)
//****************************
// Video Streams
//****************************
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE0 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE1 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE2 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE3 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE4 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE5 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE6 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE7 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE8 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xE9 }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xEA }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xEB }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xEC }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xED }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xEE }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
{BitConverter.ToUInt32(new byte[] { 0x00, 0x00, 0x01, 0xEF }, 0), new BlockSizeStruct(PacketSizeType.SizeBytes, 2)}, // Video Stream, two bytes following equal length (Big Endian)
};
#endregion
public string FilePath { get; set; }
public string FileExtensionAudio { get; set; }
public string FileExtensionVideo { get; set; }
protected Dictionary<byte, string> StreamIdFileType = new Dictionary<byte, string>();
public bool UsesSameIdForMultipleAudioTracks { set; get; } // for PMF/PAM/DVD, who use 000001BD for all audio tracks
public bool SubTitleExtractionSupported { set; get; } // assume not supported.
public bool BlockSizeIsLittleEndian { set; get; }
protected virtual byte[] GetPacketStartBytes() { return MpegStream.PacketStartBytes; }
protected virtual byte[] GetPacketEndBytes() { return MpegStream.PacketEndBytes; }
protected abstract int GetAudioPacketHeaderSize(Stream readStream, long currentOffset);
protected virtual int GetAudioPacketSubHeaderSize(Stream readStream, long currentOffset, byte streamId) { return 0; }
protected abstract int GetVideoPacketHeaderSize(Stream readStream, long currentOffset);
protected virtual int GetAudioPacketFooterSize(Stream readStream, long currentOffset) { return 0; }
protected virtual int GetVideoPacketFooterSize(Stream readStream, long currentOffset) { return 0; }
protected virtual bool IsThisAnAudioBlock(byte[] blockToCheck)
{
return ((blockToCheck[3] >= 0xC0) &&
(blockToCheck[3] <= 0xDF));
}
protected virtual bool IsThisAVideoBlock(byte[] blockToCheck)
{
return ((blockToCheck[3] >= 0xE0) && (blockToCheck[3] <= 0xEF));
}
protected virtual bool IsThisASubPictureBlock(byte[] blockToCheck)
{
return ((blockToCheck[3] >= 0xE0) && (blockToCheck[3] <= 0xEF));
}
protected virtual string GetAudioFileExtension(Stream readStream, long currentOffset)
{
return this.FileExtensionAudio;
}
protected virtual string GetVideoFileExtension(Stream readStream, long currentOffset)
{
return this.FileExtensionVideo;
}
protected virtual byte GetStreamId(Stream readStream, long currentOffset) { return 0; }
protected virtual long GetStartOffset(Stream readStream, long currentOffset) { return 0; }
protected virtual void DoFinalTasks(FileStream sourceFileStream, Dictionary<uint, FileStream> outputFiles, bool addHeader)
{
}
public virtual void DemultiplexStreams(DemuxOptionsStruct demuxOptions)
{
using (FileStream fs = File.OpenRead(this.FilePath))
{
long fileSize = fs.Length;
long currentOffset = 0;
byte[] currentBlockId;
uint currentBlockIdVal;
byte[] currentBlockIdNaming;
BlockSizeStruct blockStruct = new BlockSizeStruct();
byte[] blockSizeArray;
uint blockSize;
int audioBlockSkipSize;
int videoBlockSkipSize;
int audioBlockFooterSize;
int videoBlockFooterSize;
int cutSize;
bool eofFlagFound = false;
Dictionary<uint, FileStream> streamOutputWriters = new Dictionary<uint, FileStream>();
string outputFileName;
byte streamId = 0; // for types that have multiple streams in the same block ID
uint currentStreamKey; // hash key for each file
bool isAudioBlock;
string audioFileExtension;
// look for first packet
currentOffset = this.GetStartOffset(fs, currentOffset);
currentOffset = ParseFile.GetNextOffset(fs, currentOffset, this.GetPacketStartBytes());
if (currentOffset != -1)
{
while (currentOffset < fileSize)
{
#if DEBUG
//if (currentOffset == 0x414080e)
//{
// int gggg = 1;
//}
// hack for bad data (ni no kuni s09.pam)
//if ((currentOffset & 1) == 1)
//{
// currentOffset = MathUtil.RoundUpToByteAlignment(currentOffset, 0x800);
//}
#endif
try
{
// get the current block
currentBlockId = ParseFile.ParseSimpleOffset(fs, currentOffset, 4);
// get value to use as key to hash table
currentBlockIdVal = BitConverter.ToUInt32(currentBlockId, 0);
if (BlockIdDictionary.ContainsKey(currentBlockIdVal))
{
// get info about this block type
blockStruct = BlockIdDictionary[currentBlockIdVal];
switch (blockStruct.SizeType)
{
/////////////////////
// Static Block Size
/////////////////////
case PacketSizeType.Static:
currentOffset += blockStruct.Size; // skip this block
break;
//////////////////
// End of Stream
//////////////////
case PacketSizeType.Eof:
eofFlagFound = true; // set EOF block found so we can exit the loop
break;
//////////////////////
// Varying Block Size
//////////////////////
case PacketSizeType.SizeBytes:
// Get the block size
blockSizeArray = ParseFile.ParseSimpleOffset(fs, currentOffset + currentBlockId.Length, blockStruct.Size);
if (!this.BlockSizeIsLittleEndian)
{
Array.Reverse(blockSizeArray);
}
switch (blockStruct.Size)
{
case 4:
blockSize = (uint)BitConverter.ToUInt32(blockSizeArray, 0);
break;
case 2:
blockSize = (uint)BitConverter.ToUInt16(blockSizeArray, 0);
break;
case 1:
blockSize = (uint)blockSizeArray[0];
break;
default:
throw new ArgumentOutOfRangeException(String.Format("Unhandled size block size.{0}", Environment.NewLine));
}
// if block type is audio or video, extract it
isAudioBlock = this.IsThisAnAudioBlock(currentBlockId);
if ((demuxOptions.ExtractAudio && isAudioBlock) ||
(demuxOptions.ExtractVideo && this.IsThisAVideoBlock(currentBlockId)))
{
// reset stream id
streamId = 0;
// if audio block, get the stream number from the queue
if (isAudioBlock && this.UsesSameIdForMultipleAudioTracks)
{
streamId = this.GetStreamId(fs, currentOffset);
currentStreamKey = (streamId | currentBlockIdVal);
}
else
{
currentStreamKey = currentBlockIdVal;
}
// check if we've already started parsing this stream
if (!streamOutputWriters.ContainsKey(currentStreamKey))
{
// convert block id to little endian for naming
currentBlockIdNaming = BitConverter.GetBytes(currentStreamKey);
Array.Reverse(currentBlockIdNaming);
// build output file name
outputFileName = Path.GetFileNameWithoutExtension(this.FilePath);
//outputFileName = outputFileName + "_" + BitConverter.ToUInt32(currentBlockIdNaming, 0).ToString("X8");
// add proper extension
if (this.IsThisAnAudioBlock(currentBlockId))
{
audioFileExtension = this.GetAudioFileExtension(fs, currentOffset);
outputFileName += audioFileExtension;
if (!this.StreamIdFileType.ContainsKey(streamId))
{
this.StreamIdFileType.Add(streamId, audioFileExtension);
}
}
else
{
this.FileExtensionVideo = this.GetVideoFileExtension(fs, currentOffset);
outputFileName += this.FileExtensionVideo;
}
// add output directory
outputFileName = Path.Combine(Path.GetDirectoryName(this.FilePath), outputFileName);
// add an output stream for writing
streamOutputWriters[currentStreamKey] = new FileStream(outputFileName, FileMode.Create, FileAccess.ReadWrite);
}
// write the block
if (this.IsThisAnAudioBlock(currentBlockId))
{
// write audio
audioBlockSkipSize = this.GetAudioPacketHeaderSize(fs, currentOffset) + GetAudioPacketSubHeaderSize(fs, currentOffset, streamId);
audioBlockFooterSize = this.GetAudioPacketFooterSize(fs, currentOffset);
cutSize = (int)(blockSize - audioBlockSkipSize - audioBlockFooterSize);
if (cutSize > 0)
{
streamOutputWriters[currentStreamKey].Write(ParseFile.ParseSimpleOffset(fs, currentOffset + currentBlockId.Length + blockSizeArray.Length + audioBlockSkipSize, (int)(blockSize - audioBlockSkipSize)), 0, cutSize);
}
#if DEBUG
//else
//{
// int aaa = 1;
//}
#endif
}
else
{
// write video
videoBlockSkipSize = this.GetVideoPacketHeaderSize(fs, currentOffset);
videoBlockFooterSize = this.GetVideoPacketFooterSize(fs, currentOffset);
cutSize = (int)(blockSize - videoBlockSkipSize - videoBlockFooterSize);
if (cutSize > 0)
{
streamOutputWriters[currentStreamKey].Write(ParseFile.ParseSimpleOffset(fs, currentOffset + currentBlockId.Length + blockSizeArray.Length + videoBlockSkipSize, (int)(blockSize - videoBlockSkipSize)), 0, cutSize);
}
#if DEBUG
//else
//{
// int vvv = 1;
//}
#endif
}
}
// move to next block
currentOffset += currentBlockId.Length + blockSizeArray.Length + blockSize;
blockSizeArray = new byte[] { };
break;
default:
break;
}
}
else // this is an undexpected block type
{
this.closeAllWriters(streamOutputWriters);
Array.Reverse(currentBlockId);
throw new FormatException(String.Format("Block ID at 0x{0} not found in table: 0x{1}", currentOffset.ToString("X8"), BitConverter.ToUInt32(currentBlockId, 0).ToString("X8")));
}
// exit loop if EOF block found
if (eofFlagFound)
{
break;
}
}
catch (Exception _ex)
{
this.closeAllWriters(streamOutputWriters);
throw new Exception(String.Format("Error parsing file at offset {0), '{1}'", currentOffset.ToString("X8"), _ex.Message), _ex);
}
} // while (currentOffset < fileSize)
}
else
{
this.closeAllWriters(streamOutputWriters);
throw new FormatException(String.Format("Cannot find Pack Header for file: {0}{1}", Path.GetFileName(this.FilePath), Environment.NewLine));
}
///////////////////////////////////
// Perform any final tasks needed
///////////////////////////////////
this.DoFinalTasks(fs, streamOutputWriters, demuxOptions.AddHeader);
//////////////////////////
// close all open writers
//////////////////////////
this.closeAllWriters(streamOutputWriters);
} // using (FileStream fs = File.OpenRead(path))
}
private void closeAllWriters(Dictionary<uint, FileStream> writers)
{
//////////////////////////
// close all open writers
//////////////////////////
foreach (uint b in writers.Keys)
{
if (writers[b].CanRead)
{
writers[b].Close();
writers[b].Dispose();
}
}
}
public static int GetMpegStreamType(string path)
{
int mpegType = -1;
using (FileStream fs = File.OpenRead(path))
{
// look for first packet
long currentOffset = ParseFile.GetNextOffset(fs, 0, MpegStream.PacketStartBytes);
if (currentOffset != -1)
{
currentOffset += 4;
fs.Position = currentOffset;
byte idByte = (byte)fs.ReadByte();
if ((int)ByteConversion.GetHighNibble(idByte) == 2)
{
mpegType = 1;
}
else if ((int)ByteConversion.GetHighNibble(idByte) == 4)
{
mpegType = 2;
}
}
else
{
throw new FormatException(String.Format("Cannot find Pack Header for file: {0}{1}", Path.GetFileName(path), Environment.NewLine));
}
}
return mpegType;
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.IO;
namespace vgm_usm.extract
{
static class extract
{
static void Main(string[] args) {
MpegStream.DemuxOptionsStruct demuxOptions = new MpegStream.DemuxOptionsStruct();
demuxOptions.ExtractVideo = true;
demuxOptions.ExtractAudio = true;
demuxOptions.AddHeader = true;
demuxOptions.SplitAudioStreams = true;
demuxOptions.AddPlaybackHacks = true;
foreach (string s in args) {
CriUsmStream usm = new CriUsmStream(s);
usm.DemultiplexStreams(demuxOptions);
}
}
}
}

View file

@ -0,0 +1,58 @@
using System;
using System.IO;
using VGMToolbox.util;
namespace vgm_usm.extract
{
public class SofdecStream : Mpeg1Stream
{
new public const string DefaultVideoExtension = ".m2v";
public const string AdxAudioExtension = ".adx";
public const string AixAudioExtension = ".aix";
public const string Ac3AudioExtension = ".ac3";
public static readonly byte[] AixSignatureBytes = new byte[] { 0x41, 0x49, 0x58, 0x46 };
public static readonly byte[] Ac3SignatureBytes = new byte[] { 0x0B, 0x77 };
public SofdecStream(string path): base(path)
{
this.FileExtensionAudio = AdxAudioExtension;
this.FileExtensionVideo = DefaultVideoExtension;
}
protected override string GetAudioFileExtension(Stream readStream, long currentOffset)
{
string fileExtension;
byte[] checkBytes, checkBytesAc3;
int headerSize = this.GetAudioPacketHeaderSize(readStream, currentOffset);
checkBytes = ParseFile.ParseSimpleOffset(readStream, (currentOffset + 6 + headerSize), 4);
if (ParseFile.CompareSegment(checkBytes, 0, AixSignatureBytes))
{
fileExtension = AixAudioExtension;
}
else if (checkBytes[0] == 0x80)
{
fileExtension = AdxAudioExtension;
}
else
{
checkBytesAc3 = ParseFile.ParseSimpleOffset(readStream, (currentOffset + 6 + headerSize), 2);
if (ParseFile.CompareSegment(checkBytesAc3, 0, Ac3SignatureBytes))
{
fileExtension = Ac3AudioExtension;
}
else
{
fileExtension = ".bin";
}
}
return fileExtension;
}
}
}

View file

@ -0,0 +1,266 @@
using System;
using System.Globalization;
using System.Text;
namespace VGMToolbox.util
{
/// <summary>
/// Class containing static text conversion functions.
/// </summary>
public sealed class ByteConversion
{
/// <summary>
/// Codepage value for Shift JIS (Jp)
/// </summary>
public const int CodePageJapan = 932;
/// <summary>
/// Codepage value for Cyrillic (US)
/// </summary>
public const int CodePageUnitedStates = 1251;
/// <summary>
/// Codepage value for OEM DOS
/// </summary>
public const int CodePageOEM = 437;
private ByteConversion() { }
/// <summary>
/// Get string from bytes.
/// </summary>
/// <param name="pBytes">Bytes to convert to a string.</param>
/// <param name="codePage">Codepage to use in converting bytes.</param>
/// <returns>String encoding using the input Codepage.</returns>
public static string GetEncodedText(byte[] value, int codePage)
{
//return Encoding.Unicode.GetString(value);
return System.Text.Encoding.GetEncoding(codePage).GetString(value);
}
/// <summary>
/// Get text encoded in Shift JIS
/// </summary>
/// <param name="pBytes">Bytes to decode.</param>
/// <returns>String encoded using the Shift JIS codepage.</returns>
public static string GetJapaneseEncodedText(byte[] value)
{
return GetEncodedText(value, CodePageJapan);
}
/// <summary>
/// Get text encoded in Cyrillic
/// </summary>
/// <param name="pBytes">Bytes to decode.</param>
/// <returns>String encoded using the Cyrillic codepage.</returns>
public static string GetUnitedStatesEncodedText(byte[] value)
{
return GetEncodedText(value, CodePageUnitedStates);
}
/// <summary>
/// Get text encoded in ASCII
/// </summary>
/// <param name="pBytes">Bytes to decode.</param>
/// <returns>String encoded using ASCII.</returns>
public static string GetAsciiText(byte[] value)
{
System.Text.Encoding ascii = System.Text.Encoding.ASCII;
return ascii.GetString(value);
}
/// <summary>
/// Get text encoded in ASCII, stops at null.
/// </summary>
/// <param name="pBytes">Bytes to decode.</param>
/// <param name="offset">Offet within byte array of string.</param>
/// <returns>String encoded using ASCII.</returns>
public static string GetAsciiText(byte[] value, long offset)
{
StringBuilder sb = new StringBuilder();
System.Text.Encoding ascii = System.Text.Encoding.ASCII;
for (long i = offset; i < value.Length; i++)
{
if (value[i] == 0)
{
break;
}
else
{
sb.Append((char)value[i]);
}
}
return sb.ToString();
}
public static string GetUtf16LeText(byte[] value)
{
System.Text.Encoding encoding = System.Text.Encoding.Unicode;
return encoding.GetString(value);
}
/// <summary>
/// Convert input string to a long. Works for Decimal and Hexidecimal (use 0x prefix).
/// </summary>
/// <param name="pStringNumber">String containing a Decimal and Hexidecimal number.</param>
/// <returns>Long representing the input string.</returns>
public static long GetLongValueFromString(string value)
{
long ret;
bool isNegative = false;
string parseValue;
if (value.StartsWith("-"))
{
parseValue = value.Substring(1);
isNegative = true;
}
else
{
parseValue = value;
}
if (parseValue.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
{
parseValue = parseValue.Substring(2);
ret = long.Parse(parseValue, System.Globalization.NumberStyles.HexNumber, null);
}
else
{
ret = long.Parse(parseValue, System.Globalization.NumberStyles.Integer, null);
}
if (isNegative)
{
ret *= -1;
}
return ret;
}
/// <summary>
/// Get the UInt32 Value of the Incoming Byte Array, which is in Big Endian order.
/// </summary>
/// <param name="pBytes">Bytes to convert.</param>
/// <returns>The UInt32 Value of the Incoming Byte Array.</returns>
public static UInt32 GetUInt32BigEndian(byte[] value)
{
byte[] workingArray = new byte[value.Length];
Array.Copy(value, 0, workingArray, 0, value.Length);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(workingArray);
}
return BitConverter.ToUInt32(workingArray, 0);
}
/// <summary>
/// Get the UInt16 Value of the Incoming Byte Array, which is in Big Endian order.
/// </summary>
/// <param name="pBytes">Bytes to convert.</param>
/// <returns>The UInt16 Value of the Incoming Byte Array.</returns>
public static UInt16 GetUInt16BigEndian(byte[] value)
{
byte[] workingArray = new byte[value.Length];
Array.Copy(value, 0, workingArray, 0, value.Length);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(workingArray);
}
return BitConverter.ToUInt16(workingArray, 0);
}
/// <summary>
/// Predicts Code Page between Cyrillic and Shift-JIS based on whether high ASCII is included or not.
/// </summary>
/// <param name="tagBytes">Bytes containing the tags in an unknown language.</param>
/// <returns>Integer representing the predicted code page.</returns>
public static int GetPredictedCodePageForTags(byte[] tagBytes)
{
int predictedCodePage = CodePageUnitedStates;
foreach (byte b in tagBytes)
{
if ((int)b > 0x7F)
{
predictedCodePage = CodePageJapan;
break;
}
}
return predictedCodePage;
}
public static byte GetHighNibble(byte value)
{
return (byte)(((value) >> 4) & 0x0F);
}
public static byte GetLowNibble(byte value)
{
return (byte)((value) & 0x0F); ;
}
public static byte[] GetBytesFromHexString(string hexValue)
{
int j = 0;
byte[] bytes = new byte[hexValue.Length / 2];
// convert the string to bytes
for (int i = 0; i < hexValue.Length; i += 2)
{
bytes[j] = BitConverter.GetBytes(Int16.Parse(hexValue.Substring(i, 2), System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture))[0];
j++;
}
return bytes;
}
public static byte[] GetBytesBigEndian(uint value)
{
byte[] ret = BitConverter.GetBytes(value);
Array.Reverse(ret);
return ret;
}
public static DateTime GetDateTimeFromFAT32Date(int value)
{
short xDate = (short)(value >> 0x10);
short xTime = (short)(value & 0xFFFF);
if (xDate == 0 && xTime == 0)
{
return DateTime.Now;
}
else
{
return new DateTime(
(((xDate & 0xFE00) >> 9) + 0x7BC),
((xDate & 0x1E0) >> 5),
(xDate & 0x1F),
((xTime & 0xF800) >> 0xB),
((xTime & 0x7E0) >> 5),
((xTime & 0x1F) * 2));
}
}
public static bool IsZeroFilledByteArray(byte[] value)
{
bool ret = true;
for (int i = 0; i < value.Length; i++)
{
if (value[i] != 0)
{
ret = false;
break;
}
}
return ret;
}
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VGMToolbox.util
{
public class ByteSearchCalculatingOffsetDescription : CalculatingOffsetDescription
{
public const string START_OF_STRING = "start of";
public const string END_OF_STRING = "end of";
public string RelativeLocationToByteString { set; get; }
public string ByteString { set; get; }
public bool TreatByteStringAsHex { set; get; }
}
}

View file

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VGMToolbox.util
{
public class CalculatingOffsetDescription : OffsetDescription
{
public const string OFFSET_VARIABLE_STRING = "$V";
public string CalculationString { set; get; }
}
}

View file

@ -0,0 +1,196 @@
// <copyright file="ChecksumUtil.cs" company="N/A">
// Copyright (c) 2008 All Rights Reserved
// </copyright>
// <author></author>
// <email></email>
// <date></date>
// <summary>Contains the ChecksumUtil class.</summary>
using System;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using ICSharpCode.SharpZipLib.Checksums;
using Ionic.Zlib;
namespace VGMToolbox.util
{
/// <summary>
/// Class containing static functions related to checksum generation.
/// </summary>
public sealed class ChecksumUtil
{
/// <summary>
/// Prevents a default instance of the ChecksumUtil class from being created.
/// </summary>
private ChecksumUtil()
{
}
/// <summary>
/// Get the CRC32 checksum of the input stream.
/// </summary>
/// <param name="stream">File Stream for which to generate the checksum.</param>
/// <returns>String containing the hexidecimal representation of the CRC32 of the input stream.</returns>
public static string GetCrc32OfFullFile(FileStream stream)
{
// get incoming stream position
long initialStreamPosition = stream.Position;
// move to zero position
stream.Seek(0, SeekOrigin.Begin);
// calculate CRC32
CRC32 crc32 = new CRC32();
int ret = crc32.GetCrc32(stream);
// return stream to incoming position
stream.Position = initialStreamPosition;
return ret.ToString("X8", CultureInfo.InvariantCulture);
}
/// <summary>
/// Get the MD5 checksum of the input stream.
/// </summary>
/// <param name="stream">File Stream for which to generate the checksum.</param>
/// <returns>String containing the hexidecimal representation of the MD5 of the input stream.</returns>
public static string GetMd5OfFullFile(FileStream stream)
{
MD5CryptoServiceProvider hashMd5 = new MD5CryptoServiceProvider();
stream.Seek(0, SeekOrigin.Begin);
hashMd5.ComputeHash(stream);
return ParseFile.ByteArrayToString(hashMd5.Hash);
}
public static byte[] GetSha1(byte[] dataBlock)
{
SHA1CryptoServiceProvider sha1Hash = new SHA1CryptoServiceProvider();
sha1Hash.ComputeHash(dataBlock);
return sha1Hash.Hash;
}
/// <summary>
/// Get the SHA1 checksum of the input stream.
/// </summary>
/// <param name="stream">File Stream for which to generate the checksum.</param>
/// <returns>String containing the hexidecimal representation of the SHA1 of the input stream.</returns>
public static string GetSha1OfFullFile(FileStream stream)
{
SHA1CryptoServiceProvider sha1Hash = new SHA1CryptoServiceProvider();
stream.Seek(0, SeekOrigin.Begin);
sha1Hash.ComputeHash(stream);
return ParseFile.ByteArrayToString(sha1Hash.Hash);
}
/// <summary>
/// Get the SHA-512 checksum of the input stream.
/// </summary>
/// <param name="stream">File Stream for which to generate the checksum.</param>
/// <returns>String containing the hexidecimal representation of the SHA-512 of the input stream.</returns>
public static string GetSha512OfFullFile(FileStream stream)
{
SHA512CryptoServiceProvider sha512 = new SHA512CryptoServiceProvider();
stream.Seek(0, SeekOrigin.Begin);
sha512.ComputeHash(stream);
return ParseFile.ByteArrayToString(sha512.Hash);
}
/// <summary>
/// Adds a chunk of data to the input CRC32 generator.
/// </summary>
/// <param name="stream">Stream to read data from.</param>
/// <param name="startingOffset">Offset to begin reading from.</param>
/// <param name="length">Number of bytes to read.</param>
/// <param name="checksumGenerator">CRC32 generator.</param>
public static void AddChunkToChecksum(Stream stream, int startingOffset, int length, ref Crc32 checksumGenerator)
{
int remaining = length;
byte[] data = new byte[4096];
int read;
int offset = startingOffset;
stream.Seek((long)startingOffset, SeekOrigin.Begin);
while (remaining > 0)
{
if (remaining < 4096)
{
read = stream.Read(data, 0, remaining);
}
else
{
read = stream.Read(data, 0, 4096);
}
if (read <= 0)
{
throw new EndOfStreamException(
String.Format(
CultureInfo.CurrentCulture,
"End of stream reached with {0} bytes left to read",
remaining));
}
checksumGenerator.Update(data, 0, read);
remaining -= read;
offset += read;
}
}
/// <summary>
/// Adds a chunk of data to the input CRC32/MD5/SHA1 generator.
/// </summary>
/// <param name="sourceStream">Stream to read data from.</param>
/// <param name="startingOffset">Offset to begin reading from.</param>
/// <param name="length">Number of bytes to read.</param>
/// <param name="checksumGeneratorCrc32">CRC32 generator.</param>
/// <param name="checksumStreamMd5">MD5 generator.</param>
/// <param name="checksumStreamSha1">SHA1 generator.</param>
public static void AddChunkToChecksum(
Stream sourceStream,
int startingOffset,
int length,
ref Crc32 checksumGeneratorCrc32,
ref CryptoStream checksumStreamMd5,
ref CryptoStream checksumStreamSha1)
{
int remaining = length;
byte[] data = new byte[4096];
int read;
int offset = startingOffset;
sourceStream.Seek((long)startingOffset, SeekOrigin.Begin);
while (remaining > 0)
{
if (remaining < 4096)
{
read = sourceStream.Read(data, 0, remaining);
}
else
{
read = sourceStream.Read(data, 0, 4096);
}
if (read <= 0)
{
throw new EndOfStreamException(
String.Format(
CultureInfo.CurrentCulture,
"End of stream reached with {0} bytes left to read",
remaining));
}
checksumGeneratorCrc32.Update(data, 0, read);
checksumStreamMd5.Write(data, 0, read);
checksumStreamSha1.Write(data, 0, read);
remaining -= read;
offset += read;
}
}
}
}

View file

@ -0,0 +1,496 @@
using System;
using System.IO;
using System.Reflection;
using Ionic.Zip;
using Ionic.Zlib;
using SevenZip;
namespace VGMToolbox.util
{
/// <summary>
/// Class containing static functions for compresson related tasks
/// </summary>
public sealed class CompressionUtil
{
/// <summary>
/// File extension used to output decompressed zlib data.
/// </summary>
public const string ZlibDecompressOutputExtension = ".zlibx";
/// <summary>
/// File extension used to output compressed zlib data.
/// </summary>
public const string ZlibCompressOutputExtension = ".zlib";
/// <summary>
/// File extension used to output decompressed gzip data.
/// </summary>
public const string GzipDecompressOutputExtension = ".gzipx";
/// <summary>
/// File extension used to output compressed gzip data.
/// </summary>
public const string GzipCompressOutputExtension = ".gz";
/// <summary>
/// Path to the included 7z.dll file.
/// </summary>
public static readonly string SevenZipDll =
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll");
/// <summary>
/// Prevents a default instance of the CompressionUtil class from being created
/// </summary>
private CompressionUtil()
{
}
/// <summary>
/// Get a list of files inside an archive file.
/// </summary>
/// <param name="path">Path to the archive file.</param>
/// <returns>An array of strings containing a list of files inside the archive.</returns>
/// <remarks>Must be an archive supported by 7z.dll.</remarks>
public static string[] GetFileList(string path)
{
string archivePath = Path.GetFullPath(path);
string[] filenames = null;
SevenZipExtractor sevenZipExtractor = null;
if (File.Exists(archivePath))
{
SevenZipExtractor.SetLibraryPath(SevenZipDll);
try
{
sevenZipExtractor = new SevenZipExtractor(archivePath);
filenames = new string[sevenZipExtractor.ArchiveFileNames.Count];
int i = 0;
foreach (string f in sevenZipExtractor.ArchiveFileNames)
{
filenames[i++] = f;
}
}
catch (System.ArgumentException)
{
// ignore unsupported formats
}
finally
{
if (sevenZipExtractor != null)
{
sevenZipExtractor.Dispose();
}
}
}
return filenames;
}
/// <summary>
/// Get an uppercase list of files inside an archive file. Must be an archive supported by 7z.dll.
/// </summary>
/// <param name="path">Path to the archive file.</param>
/// <returns>An array of strings containing an uppercase list of files inside the archive.</returns>
/// <remarks>Must be an archive supported by 7z.dll.</remarks>
public static string[] GetUpperCaseFileList(string path)
{
string archivePath = Path.GetFullPath(path);
string[] filenames = null;
SevenZipExtractor sevenZipExtractor = null;
if (File.Exists(archivePath))
{
SevenZipExtractor.SetLibraryPath(SevenZipDll);
try
{
sevenZipExtractor = new SevenZipExtractor(archivePath);
filenames = new string[sevenZipExtractor.ArchiveFileNames.Count];
int i = 0;
foreach (string f in sevenZipExtractor.ArchiveFileNames)
{
filenames[i++] = f.ToUpper();
}
}
catch (System.ArgumentException)
{
// ignore unsupported formats
}
finally
{
if (sevenZipExtractor != null)
{
sevenZipExtractor.Dispose();
}
}
}
return filenames;
}
public static bool Is7zSupportedArchive(string pArchivePath)
{
string archivePath = Path.GetFullPath(pArchivePath);
SevenZipExtractor sevenZipExtractor = null;
bool ret = false;
if (File.Exists(archivePath))
{
try
{
SevenZipExtractor.SetLibraryPath(SevenZipDll);
sevenZipExtractor = new SevenZipExtractor(archivePath);
sevenZipExtractor.Check();
ret = true;
}
catch (Exception)
{
ret = false;
}
finally
{
if (sevenZipExtractor != null)
{
sevenZipExtractor.Dispose();
}
}
}
return ret;
}
/// <summary>
/// Extracts a file from an archive. The file will be output to a subfolder in the archive's directory;
/// named with the original archive name.
/// </summary>
/// <param name="archivePath">Path to the archive file.</param>
/// <param name="fileName">Name of file to extract.</param>
/// <remarks>Must be an archive supported by 7z.dll.</remarks>
public static void ExtractFileFromArchive(string archivePath, string fileName)
{
ExtractFileFromArchive(archivePath, fileName, String.Empty);
}
/// <summary>
/// Extracts a file from an archive.
/// </summary>
/// <param name="pArchivePath">Path to the archive file.</param>
/// <param name="pFileName">Name of file to extract.</param>
/// <param name="pOutputPath">Folder to output the file to. If empty or null,
/// the file will be output to a subfolder in the archive's directory;
/// named with the original archive name.</param>
/// <remarks>Must be an archive supported by 7z.dll.</remarks>
public static void ExtractFileFromArchive(string pArchivePath, string pFileName, string pOutputPath)
{
string archivePath = Path.GetFullPath(pArchivePath);
SevenZipExtractor sevenZipExtractor = null;
string outputDir;
if (File.Exists(archivePath))
{
try
{
if (!String.IsNullOrEmpty(pOutputPath))
{
outputDir = pOutputPath;
}
else
{
outputDir = Path.Combine(Path.GetDirectoryName(archivePath), Path.GetFileNameWithoutExtension(archivePath));
}
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
SevenZipExtractor.SetLibraryPath(SevenZipDll);
sevenZipExtractor = new SevenZipExtractor(archivePath);
sevenZipExtractor.ExtractFile(pFileName, outputDir, true);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
if (sevenZipExtractor != null)
{
sevenZipExtractor.Dispose();
}
}
}
}
public static void ExtractAllFilesFromArchive(string pArchivePath, string pOutputPath)
{
string archivePath = Path.GetFullPath(pArchivePath);
SevenZipExtractor sevenZipExtractor = null;
string outputDir;
if (File.Exists(archivePath))
{
try
{
if (!String.IsNullOrEmpty(pOutputPath))
{
outputDir = pOutputPath;
}
else
{
outputDir = Path.Combine(Path.GetDirectoryName(archivePath), Path.GetFileNameWithoutExtension(archivePath));
}
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
SevenZipExtractor.SetLibraryPath(SevenZipDll);
sevenZipExtractor = new SevenZipExtractor(archivePath);
sevenZipExtractor.ExtractArchive(outputDir);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
if (sevenZipExtractor != null)
{
sevenZipExtractor.Dispose();
}
}
}
}
/// <summary>
/// Compress input folder (recursively) with 7zip Ultra compression.
/// </summary>
/// <param name="pSourcePath">Source directory to compress.</param>
/// <param name="pArchiveName">Fully rooted output archive name.</param>
public static void CompressFolderWith7zip(string pSourcePath, string pArchiveName)
{
SevenZipCompressor.SetLibraryPath(SevenZipDll);
SevenZipCompressor compressor = new SevenZipCompressor();
compressor.CompressionLevel = SevenZip.CompressionLevel.Ultra;
compressor.CompressDirectory(pSourcePath, pArchiveName, true);
}
/// <summary>
/// Extract all files from the input .zip compressed file.
/// </summary>
/// <param name="pZipFilePath">Fully rooted path to the .zip file.</param>
/// <param name="pOutputFolder">Fully rooted path to the output folder to place the deompressed files.</param>
public static void ExtractAllFilesFromZipFile(string pZipFilePath, string pOutputFolder)
{
using (ZipFile zip = ZipFile.Read(pZipFilePath))
{
zip.ExtractAll(pOutputFolder);
}
}
/// <summary>
/// Add a file to the input .zip file.
/// </summary>
/// <param name="pZipFileName">Fully rooted path to the .zip file to add files to.</param>
/// <param name="pNewEntrySourceFileName">Fully rooted path to the file to insert.</param>
/// <param name="pNewEntryDestinationName">Path within the .zip file to insert the new file as.</param>
public static void AddFileToZipFile(string pZipFileName, string pNewEntrySourceFileName, string pNewEntryDestinationName)
{
ZipFile zf;
// create or open zip file
if (File.Exists(pZipFileName))
{
zf = ZipFile.Read(pZipFileName);
}
else
{
zf = new ZipFile(pZipFileName);
}
zf.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
using (FileStream fs = File.OpenRead(pNewEntrySourceFileName))
{
zf.AddEntry(Path.GetFileName(pNewEntryDestinationName), Path.GetDirectoryName(pNewEntryDestinationName), fs);
zf.Save();
}
}
/// <summary>
/// Decompress a zlib compressed section of a stream to file. Data must begin at offset 0.
/// </summary>
/// <param name="pStream">Stream containing zlib compressed bytes.</param>
/// <param name="pOutputFilePath">Fully rooted output file name to output the decompressed data to.</param>
public static void DecompressZlibStreamToFile(Stream pStream, string pOutputFilePath)
{
DecompressZlibStreamToFile(pStream, pOutputFilePath, 0);
}
/// <summary>
/// Decompress a zlib compressed section of a stream to file.
/// </summary>
/// <param name="pStream">Stream containing zlib compressed bytes.</param>
/// <param name="pOutputFilePath">Fully rooted output file name to output the decompressed data to.</param>
/// <param name="pStartingOffset">Offset to begin reading data from.</param>
public static void DecompressZlibStreamToFile(Stream pStream, string pOutputFilePath, long pStartingOffset)
{
using (FileStream outFs = new FileStream(pOutputFilePath, FileMode.Create, FileAccess.Write))
{
using (BinaryWriter bw = new BinaryWriter(outFs))
{
pStream.Position = pStartingOffset;
using (ZlibStream zs = new ZlibStream(pStream, CompressionMode.Decompress, true))
{
int read;
byte[] data = new byte[Constants.FileReadChunkSize];
while ((read = zs.Read(data, 0, data.Length)) > 0)
{
bw.Write(data, 0, read);
}
}
}
}
}
/// <summary>
/// Compress the incoming stream to a file using zlib compression.
/// </summary>
/// <param name="pStream">Stream to compress.</param>
/// <param name="pOutputFilePath">Path to the file to output.</param>
public static void CompressStreamToZlibFile(Stream pStream, string pOutputFilePath)
{
CompressStreamToZlibFile(pStream, pOutputFilePath, 0);
}
/// <summary>
/// Compress the incoming stream to a file using zlib compression starting at the incoming offset.
/// </summary>
/// <param name="pStream">Stream to compress.</param>
/// <param name="pOutputFilePath">Path to the file to output.</param>
/// <param name="pStartingOffset">Offset within the stream to start compressing.</param>
public static void CompressStreamToZlibFile(Stream pStream, string pOutputFilePath, long pStartingOffset)
{
using (FileStream outFs = new FileStream(pOutputFilePath, FileMode.Create, FileAccess.Write))
{
using (BinaryReader br = new BinaryReader(pStream))
{
pStream.Position = pStartingOffset;
using (ZlibStream zs = new ZlibStream(outFs, CompressionMode.Compress, Ionic.Zlib.CompressionLevel.BestCompression, true))
{
int read;
byte[] data = new byte[Constants.FileReadChunkSize];
while ((read = br.Read(data, 0, data.Length)) > 0)
{
zs.Write(data, 0, read);
}
zs.Flush();
}
}
}
}
/// <summary>
/// Compress an entire file using gzip compression.
/// </summary>
/// <param name="pFileName">Fully rooted file name of file to compress.</param>
public static void GzipEntireFile(string pFileName)
{
string tempFileName;
if (File.Exists(pFileName))
{
using (FileStream fs = File.OpenRead(pFileName))
{
tempFileName = Path.GetTempFileName();
using (FileStream outFs = File.OpenWrite(tempFileName))
{
using (GZipStream gs = new GZipStream(outFs, CompressionMode.Compress, Ionic.Zlib.CompressionLevel.BestCompression))
{
int read;
byte[] data = new byte[Constants.FileReadChunkSize];
while ((read = fs.Read(data, 0, data.Length)) > 0)
{
gs.Write(data, 0, read);
}
}
}
}
File.Delete(pFileName);
File.Move(tempFileName, pFileName);
}
}
/// <summary>
/// Decompress a gzip compressed section of a stream to file.
/// </summary>
/// <param name="pStream">Stream containing gzip compressed bytes.</param>
/// <param name="pOutputFilePath">Fully rooted output file name to output the decompressed data to.</param>
/// <param name="pStartingOffset">Offset to begin reading data from.</param>
public static void DecompressGzipStreamToFile(Stream pStream, string pOutputFilePath, long pStartingOffset)
{
using (FileStream outFs = new FileStream(pOutputFilePath, FileMode.Create, FileAccess.Write))
{
using (BinaryWriter bw = new BinaryWriter(outFs))
{
pStream.Position = pStartingOffset;
using (GZipStream gs = new GZipStream(pStream, CompressionMode.Decompress, true))
{
int read;
byte[] data = new byte[Constants.FileReadChunkSize];
while ((read = gs.Read(data, 0, data.Length)) > 0)
{
bw.Write(data, 0, read);
}
}
}
}
}
/// <summary>
/// Compress the incoming stream to a file using gzip compression starting at the incoming offset.
/// </summary>
/// <param name="pStream">Stream to compress.</param>
/// <param name="pOutputFilePath">Path to the file to output.</param>
/// <param name="pStartingOffset">Offset within the stream to start compressing.</param>
public static void CompressStreamToGzipFile(Stream pStream, string pOutputFilePath, long pStartingOffset)
{
using (FileStream outFs = new FileStream(pOutputFilePath, FileMode.Create, FileAccess.Write))
{
using (BinaryReader br = new BinaryReader(pStream))
{
pStream.Position = pStartingOffset;
using (GZipStream gs = new GZipStream(outFs, CompressionMode.Compress, Ionic.Zlib.CompressionLevel.BestCompression, true))
{
int read;
byte[] data = new byte[Constants.FileReadChunkSize];
while ((read = br.Read(data, 0, data.Length)) > 0)
{
gs.Write(data, 0, read);
}
gs.Flush();
}
}
}
}
}
}

View file

@ -0,0 +1,453 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace VGMToolbox.util
{
/// <summary>
/// Struct containing criteria used to find offsets.
/// </summary>
public struct FindOffsetStruct
{
private string searchString;
private string startingOffset;
private bool treatSearchStringAsHex;
private bool cutFile;
private string searchStringOffset;
private string cutSize;
private string cutSizeOffsetSize;
private bool isCutSizeAnOffset;
private string outputFileExtension;
private bool isLittleEndian;
private bool useTerminatorForCutSize;
private string terminatorString;
private bool treatTerminatorStringAsHex;
private bool includeTerminatorLength;
private string extraCutSizeBytes;
public bool DoSearchStringModulo
{
set;
get;
}
public string SearchStringModuloDivisor
{
set;
get;
}
public string SearchStringModuloResult
{
set;
get;
}
public bool DoTerminatorModulo
{
set;
get;
}
public string TerminatorStringModuloDivisor
{
set;
get;
}
public string TerminatorStringModuloResult
{
set;
get;
}
public string MinimumSize
{
set;
get;
}
public string SearchString
{
get { return searchString; }
set { searchString = value; }
}
/// <summary>
/// Gets or sets offset to being searching at
/// </summary>
public string StartingOffset
{
set { startingOffset = value; }
get { return startingOffset; }
}
/// <summary>
/// Gets or sets flag to indicate search string is a hex value.
/// </summary>
public bool TreatSearchStringAsHex
{
get { return treatSearchStringAsHex; }
set { treatSearchStringAsHex = value; }
}
/// <summary>
/// Gets or sets flag to cut the file when the offset is found.
/// </summary>
public bool CutFile
{
get { return cutFile; }
set { cutFile = value; }
}
/// <summary>
/// Gets or sets offset within destination file Search String would reside.
/// </summary>
public string SearchStringOffset
{
get { return searchStringOffset; }
set { searchStringOffset = value; }
}
/// <summary>
/// Gets or sets size to cut from file
/// </summary>
public string CutSize
{
get { return cutSize; }
set { cutSize = value; }
}
/// <summary>
/// Gets or sets size of offset holding cut size
/// </summary>
public string CutSizeOffsetSize
{
get { return cutSizeOffsetSize; }
set { cutSizeOffsetSize = value; }
}
/// <summary>
/// Gets or sets flag indicating that cut size is an offset.
/// </summary>
public bool IsCutSizeAnOffset
{
get { return isCutSizeAnOffset; }
set { isCutSizeAnOffset = value; }
}
/// <summary>
/// Gets or sets file extension to use for cut files.
/// </summary>
public string OutputFileExtension
{
get { return outputFileExtension; }
set { outputFileExtension = value; }
}
/// <summary>
/// Gets or sets flag indicating that offset based cut size is stored in Little Endian byte order.
/// </summary>
public bool IsLittleEndian
{
get { return isLittleEndian; }
set { isLittleEndian = value; }
}
/// <summary>
/// Gets or sets flag indicating that a terminator should be used to determine the cut size.
/// </summary>
public bool UseLengthMultiplier { set; get; }
public string LengthMultiplier { set; get; }
public bool UseTerminatorForCutSize
{
get { return useTerminatorForCutSize; }
set { useTerminatorForCutSize = value; }
}
/// <summary>
/// Gets or sets terminator string to search for.
/// </summary>
public string TerminatorString
{
get { return terminatorString; }
set { terminatorString = value; }
}
/// <summary>
/// Gets or sets flag indicating that Terminator String is hex.
/// </summary>
public bool TreatTerminatorStringAsHex
{
get { return treatTerminatorStringAsHex; }
set { treatTerminatorStringAsHex = value; }
}
/// <summary>
/// Gets or sets flag indicating that the length of the terminator should be included in the cut size.
/// </summary>
public bool IncludeTerminatorLength
{
get { return includeTerminatorLength; }
set { includeTerminatorLength = value; }
}
public bool CutToEofIfTerminatorNotFound { set; get; }
/// <summary>
/// Gets or sets additional bytes to include in the cut size.
/// </summary>
public string ExtraCutSizeBytes
{
get { return extraCutSizeBytes; }
set { extraCutSizeBytes = value; }
}
public string OutputFolder { get; set; }
}
/// <summary>
/// Struct used to send messages conveying progress.
/// </summary>
public struct ProgressStruct
{
/// <summary>
/// File name to display in progress bar.
/// </summary>
private string fileName;
/// <summary>
/// Error message to display in output window.
/// </summary>
private string errorMessage;
/// <summary>
/// Generic message to display in output window.
/// </summary>
private string genericMessage;
/// <summary>
/// New tree node to add to a TreeView.
/// </summary>
private TreeNode newNode;
/// <summary>
/// Gets or sets fileName.
/// </summary>
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
/// <summary>
/// Gets or sets errorMessage.
/// </summary>
public string ErrorMessage
{
get { return errorMessage; }
set { errorMessage = value; }
}
/// <summary>
/// Gets or sets genericMessage.
/// </summary>
public string GenericMessage
{
get { return genericMessage; }
set { genericMessage = value; }
}
/// <summary>
/// Gets or sets newNode.
/// </summary>
public TreeNode NewNode
{
get { return newNode; }
set { newNode = value; }
}
/// <summary>
/// Reset this node's values
/// </summary>
public void Clear()
{
fileName = String.Empty;
errorMessage = String.Empty;
genericMessage = String.Empty;
newNode = null;
}
}
/// <summary>
/// Struct used to allow TreeView to select a specific form and modify the originating node upon completion of a task.
/// </summary>
public struct NodeTagStruct
{
/// <summary>
/// Class name of the Form this node will bring to focus.
/// </summary>
private string formClass;
/// <summary>
/// Object type this node represents.
/// </summary>
private string objectType;
/// <summary>
/// File path of the file this node represents.
/// </summary>
private string filePath;
/// <summary>
/// Gets or sets formClass
/// </summary>
public string FormClass
{
get { return formClass; }
set { formClass = value; }
}
/// <summary>
/// Gets or sets objectType
/// </summary>
public string ObjectType
{
get { return objectType; }
set { objectType = value; }
}
/// <summary>
/// Gets or sets filePath
/// </summary>
public string FilePath
{
get { return filePath; }
set { filePath = value; }
}
}
public enum VfsFileRecordRelativeOffsetLocationType
{
FileRecordStart,
FileRecordEnd
}
public struct VfsExtractionStruct
{
// header size
public bool UseStaticHeaderSize { set; get; }
public string StaticHeaderSize { set; get; }
public bool UseHeaderSizeOffset { set; get; }
public OffsetDescription HeaderSizeOffsetDescription { set; get; }
public bool ReadHeaderToEof { set; get; }
// file count
public bool UseStaticFileCount { set; get; }
public string StaticFileCount { set; get; }
public bool UseFileCountOffset { set; get; }
public OffsetDescription FileCountOffsetDescription { set; get; }
// file record basic information
public string FileRecordsStartOffset { set; get; }
public string FileRecordSize { set; get; }
// file offset
public bool UseFileOffsetOffset { set; get; }
public CalculatingOffsetDescription FileOffsetOffsetDescription { set; get; }
public bool UsePreviousFilesSizeToDetermineOffset { set; get; }
public string BeginCuttingFilesAtOffset { set; get; }
public bool UseByteAlignmentValue { set; get; }
public string ByteAlignmentValue { set; get; }
// file length/size
public bool UseFileLengthOffset { set; get; }
public CalculatingOffsetDescription FileLengthOffsetDescription { set; get; }
public bool UseLocationOfNextFileToDetermineLength { set; get; }
// file name
public bool FileNameIsPresent { set; get; }
public bool UseStaticFileNameOffsetWithinRecord { set; get; }
public string StaticFileNameOffsetWithinRecord { set; get; }
public bool UseAbsoluteFileNameOffset { set; get; }
public OffsetDescription AbsoluteFileNameOffsetDescription { set; get; }
public bool UseRelativeFileNameOffset { set; get; }
public OffsetDescription RelativeFileNameOffsetDescription { set; get; }
public VfsFileRecordRelativeOffsetLocationType FileRecordNameRelativeOffsetLocation { set; get; }
// name size
public bool UseStaticFileNameLength { set; get; }
public string StaticFileNameLength { set; get; }
public bool UseFileNameTerminatorString { set; get; }
public string FileNameTerminatorString { set; get; }
}
public struct SimpleFileExtractionStruct
{
public string FilePath { set; get; }
public long FileOffset { set; get; }
public long FileLength { set; get; }
public long FileNameLength { set; get; }
public void Clear()
{
this.FilePath = String.Empty;
this.FileOffset = -1;
this.FileLength = -1;
this.FileNameLength = -1;
}
}
/// <summary>
/// Class containing universal constants.
/// </summary>
public sealed class Constants
{
/// <summary>
/// Chunk size to use when reading from files. Used to grab maximum buffer
/// size without using the large object heap which has poor collection.
/// </summary>
public const int FileReadChunkSize = 71680;
/// <summary>
/// Constant used to send an ignore the value message to the progress bar.
/// </summary>
public const int IgnoreProgress = -1;
/// <summary>
/// Constant used to send a generic message to the progress bar.
/// </summary>
public const int ProgressMessageOnly = -2;
/// <summary>
/// Text description to use when describing a Big Endian option
/// </summary>
public const string BigEndianByteOrder = "Big Endian";
/// <summary>
/// Text description to use when describing a Little Endian option
/// </summary>
public const string LittleEndianByteOrder = "Little Endian";
public static readonly byte[] RiffHeaderBytes = new byte[] { 0x52, 0x49, 0x46, 0x46 };
public static readonly byte[] RiffDataBytes = new byte[] { 0x64, 0x61, 0x74, 0x61 };
public static readonly byte[] RiffWaveBytes = new byte[] { 0x57, 0x41, 0x56, 0x45 };
public static readonly byte[] RiffFmtBytes = new byte[] { 0x66, 0x6D, 0x74, 0x20 };
public static readonly byte[] NullByteArray = new byte[] { 0x00 };
public const string StringNullTerminator = "\0";
// empty constructor
private Constants() { }
}
}

View file

@ -0,0 +1,706 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace VGMToolbox.util
{
public sealed class FileUtil
{
private FileUtil() { }
/// <summary>
/// Reads data into a complete array, throwing an EndOfStreamException
/// if the stream runs out of data first, or if an IOException
/// naturally occurs.
/// </summary>
/// <param name="stream">The stream to read data from</param>
/// <param name="data">The array to read bytes into. The array
/// will be completely filled from the stream, so an appropriate
/// size must be given.</param>
public static void ReadWholeArray(Stream stream, byte[] data)
{
ReadWholeArray(stream, data, data.Length);
}
public static void ReadWholeArray(Stream stream, byte[] data, int pLength)
{
int offset = 0;
int remaining = pLength;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
{
throw new EndOfStreamException(
String.Format(CultureInfo.CurrentCulture, "End of stream reached with {0} bytes left to read", remaining));
}
remaining -= read;
offset += read;
}
}
/// <summary>
/// Replaces 0x00 with 0x20 in an array of bytes.
/// </summary>
/// <param name="value">Array of bytes to alter.</param>
/// <returns>Original array with 0x00 replaced by 0x20.</returns>
public static byte[] ReplaceNullByteWithSpace(byte[] value)
{
for (int i = 0; i < value.Length; i++)
{
if (value[i] == 0x00)
{
value[i] = 0x20;
}
}
return value;
}
/// <summary>
/// Returns the count of files contained in the input directories and their subdirectories.
/// </summary>
/// <param name="paths">Paths to count files within.</param>
/// <returns>Number of files in the incoming directories and their subdirectories.</returns>
public static int GetFileCount(string[] paths)
{
return GetFileCount(paths, true);
}
public static int GetFileCount(string[] paths, bool includeSubdirs)
{
int totalFileCount = 0;
foreach (string path in paths)
{
if (File.Exists(path))
{
totalFileCount++;
}
else if (Directory.Exists(path))
{
if (includeSubdirs)
{
totalFileCount += Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Length;
}
else
{
totalFileCount += Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly).Length;
}
}
}
return totalFileCount;
}
public static string CleanFileName(string pDirtyFileName)
{
foreach (char c in Path.GetInvalidFileNameChars())
{
pDirtyFileName = pDirtyFileName.Replace(c, '_');
}
return pDirtyFileName;
}
public static void UpdateTextField(
string pFilePath,
string pFieldValue,
int pOffset,
int pMaxLength)
{
System.Text.Encoding enc = System.Text.Encoding.ASCII;
using (BinaryWriter bw =
new BinaryWriter(File.Open(pFilePath, FileMode.Open, FileAccess.ReadWrite)))
{
byte[] newBytes = new byte[pMaxLength];
byte[] convertedBytes = enc.GetBytes(pFieldValue);
int numBytesToCopy =
convertedBytes.Length <= pMaxLength ? convertedBytes.Length : pMaxLength;
Array.ConstrainedCopy(convertedBytes, 0, newBytes, 0, numBytesToCopy);
bw.Seek(pOffset, SeekOrigin.Begin);
bw.Write(newBytes);
}
}
public static void UpdateChunk(
string pFilePath,
int pOffset,
byte[] value)
{
using (BinaryWriter bw =
new BinaryWriter(File.Open(pFilePath, FileMode.Open, FileAccess.ReadWrite)))
{
bw.Seek(pOffset, SeekOrigin.Begin);
bw.Write(value);
}
}
public static void ReplaceFileChunk(
string pSourceFilePath,
long pSourceOffset,
long pLength,
string pDestinationFilePath,
long pDestinationOffset)
{
int read = 0;
long maxread;
int totalBytes = 0;
byte[] bytes = new byte[Constants.FileReadChunkSize];
using (BinaryWriter bw =
new BinaryWriter(File.Open(pDestinationFilePath, FileMode.Open, FileAccess.ReadWrite)))
{
using (BinaryReader br =
new BinaryReader(File.Open(pSourceFilePath, FileMode.Open, FileAccess.Read)))
{
br.BaseStream.Position = pSourceOffset;
bw.BaseStream.Position = pDestinationOffset;
maxread = pLength > bytes.Length ? bytes.Length : pLength;
while ((read = br.Read(bytes, 0, (int)maxread)) > 0)
{
bw.Write(bytes, 0, read);
totalBytes += read;
maxread = (pLength - totalBytes) > bytes.Length ? bytes.Length : (pLength - totalBytes);
}
}
}
}
public static void ZeroOutFileChunk(string pPath, long pOffset, int pLength)
{
int bytesToWrite = pLength;
byte[] bytes;
int maxWrite = bytesToWrite > Constants.FileReadChunkSize ? Constants.FileReadChunkSize : bytesToWrite;
using (BinaryWriter bw =
new BinaryWriter(File.Open(pPath, FileMode.Open, FileAccess.Write)))
{
bw.BaseStream.Position = pOffset;
while (bytesToWrite > 0)
{
bytes = new byte[maxWrite];
bw.Write(bytes);
bytesToWrite -= maxWrite;
maxWrite = bytesToWrite > bytes.Length ? bytes.Length : bytesToWrite;
}
}
}
public static void TrimFileToLength(string path, long totalLength)
{
string fullPath = Path.GetFullPath(path);
if (File.Exists(fullPath))
{
string destinationPath = Path.ChangeExtension(fullPath, ".trimmed");
using (FileStream fs = File.OpenRead(path))
{
ParseFile.ExtractChunkToFile(fs, 0, totalLength, destinationPath);
}
File.Copy(destinationPath, path, true);
File.Delete(destinationPath);
}
}
public static string RemoveChunkFromFile(string path, long startingOffset, long length)
{
string fullPath = Path.GetFullPath(path);
int bytesRead;
byte[] bytes = new byte[1024];
string ret = String.Empty;
if (File.Exists(fullPath))
{
string destinationPath = Path.ChangeExtension(fullPath, ".cut");
using (FileStream sourceFs = File.OpenRead(fullPath))
{
// extract initial chunk
ParseFile.ExtractChunkToFile(sourceFs, 0, startingOffset, destinationPath);
// append remainder
using (FileStream outFs = File.Open(destinationPath, FileMode.Append, FileAccess.Write))
{
sourceFs.Position = startingOffset + length;
bytesRead = sourceFs.Read(bytes, 0, bytes.Length);
while (bytesRead > 0)
{
outFs.Write(bytes, 0, bytesRead);
bytesRead = sourceFs.Read(bytes, 0, bytes.Length);
}
}
ret = destinationPath;
}
}
return ret;
}
public static string RemoveAllChunksFromFile(FileStream fs, byte[] chunkToRemove)
{
int bytesRead;
long currentReadOffset = 0;
long totalBytesRead = 0;
int maxReadSize = 0;
long currentChunkSize;
byte[] bytes = new byte[Constants.FileReadChunkSize];
long[] offsets = ParseFile.GetAllOffsets(fs, 0, chunkToRemove, false, -1, -1, true);
string destinationPath = Path.ChangeExtension(fs.Name, ".cut");
using (FileStream destinationFs = File.OpenWrite(destinationPath))
{
for (int i = 0; i < offsets.Length; i++)
{
// move position
fs.Position = currentReadOffset;
// get length of current size to write
currentChunkSize = offsets[i] - currentReadOffset;
// calculcate max cut size for this loop iteration
maxReadSize = (currentChunkSize - totalBytesRead) > (long)bytes.Length ? bytes.Length : (int)(currentChunkSize - totalBytesRead);
while ((bytesRead = fs.Read(bytes, 0, maxReadSize)) > 0)
{
destinationFs.Write(bytes, 0, bytesRead);
totalBytesRead += (long)bytesRead;
maxReadSize = (currentChunkSize - totalBytesRead) > (long)bytes.Length ? bytes.Length : (int)(currentChunkSize - totalBytesRead);
}
totalBytesRead = 0;
currentReadOffset = offsets[i] + chunkToRemove.Length;
}
////////////////////////////
// write remainder of file
////////////////////////////
// move position
fs.Position = currentReadOffset;
// get length of current size to write
currentChunkSize = fs.Length - currentReadOffset;
// calculcate max cut size
maxReadSize = (currentChunkSize - totalBytesRead) > (long)bytes.Length ? bytes.Length : (int)(currentChunkSize - totalBytesRead);
while ((bytesRead = fs.Read(bytes, 0, maxReadSize)) > 0)
{
destinationFs.Write(bytes, 0, bytesRead);
totalBytesRead += (long)bytesRead;
maxReadSize = (currentChunkSize - totalBytesRead) > (long)bytes.Length ? bytes.Length : (int)(currentChunkSize - totalBytesRead);
}
}
return destinationPath;
}
public static string RemoveAllChunksFromFile(string path, byte[] chunkToRemove)
{
string destinationPath;
using (FileStream fs = File.OpenRead(path))
{
destinationPath = RemoveAllChunksFromFile(fs, chunkToRemove);
}
return destinationPath;
}
public static bool ExecuteExternalProgram(
string pathToExecuatable,
string arguments,
string workingDirectory,
out string standardOut,
out string standardError)
{
Process externalExecutable;
bool isSuccess = false;
standardOut = String.Empty;
standardError = String.Empty;
using (externalExecutable = new Process())
{
externalExecutable.StartInfo = new ProcessStartInfo(pathToExecuatable, arguments);
externalExecutable.StartInfo.WorkingDirectory = workingDirectory;
externalExecutable.StartInfo.UseShellExecute = false;
externalExecutable.StartInfo.CreateNoWindow = true;
externalExecutable.StartInfo.RedirectStandardOutput = true;
externalExecutable.StartInfo.RedirectStandardError = true;
isSuccess = externalExecutable.Start();
standardOut = externalExecutable.StandardOutput.ReadToEnd();
standardError = externalExecutable.StandardError.ReadToEnd();
externalExecutable.WaitForExit();
}
return isSuccess;
}
public static void AddHeaderToFile(byte[] headerBytes, string sourceFile, string destinationFile)
{
int bytesRead;
byte[] readBuffer = new byte[Constants.FileReadChunkSize];
using (FileStream destinationStream = File.Open(destinationFile, FileMode.CreateNew, FileAccess.Write))
{
// write header
destinationStream.Write(headerBytes, 0, headerBytes.Length);
// write the source file
using (FileStream sourceStream = File.Open(sourceFile, FileMode.Open, FileAccess.Read))
{
while ((bytesRead = sourceStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
destinationStream.Write(readBuffer, 0, bytesRead);
}
}
}
}
public static void RenameFileUsingInternalName(string path,
long offset, int length, byte[] terminatorBytes, bool maintainFileExtension)
{
string destinationDirectory = Path.GetDirectoryName(path);
string destinationFile;
string originalExtension;
int nameLength;
byte[] nameByteArray;
using (FileStream fs = File.OpenRead(path))
{
if (terminatorBytes != null)
{
nameLength = ParseFile.GetSegmentLength(fs, (int)offset, terminatorBytes);
}
else
{
nameLength = length;
}
if (nameLength < 1)
{
throw new ArgumentOutOfRangeException("Name Length", "Name Length is less than 1.");
}
if (maintainFileExtension)
{
originalExtension = Path.GetExtension(path);
}
nameByteArray = ParseFile.ParseSimpleOffset(fs, offset, nameLength);
destinationFile = ByteConversion.GetAsciiText(FileUtil.ReplaceNullByteWithSpace(nameByteArray)).Trim();
destinationFile = Path.Combine(destinationDirectory, destinationFile);
if (maintainFileExtension)
{
originalExtension = Path.GetExtension(path);
destinationFile = Path.ChangeExtension(destinationFile, originalExtension);
}
}
// try to copy using the new name
if (!path.Equals(destinationFile))
{
try
{
if (!Directory.Exists(Path.GetDirectoryName(destinationFile)))
{
Directory.CreateDirectory(Path.GetDirectoryName(destinationFile));
}
if (File.Exists(destinationFile))
{
string[] sameNamedFiles = Directory.GetFiles(Path.GetDirectoryName(destinationFile), Path.GetFileNameWithoutExtension(destinationFile) + "*");
// rename to prevent overwrite
destinationFile = Path.Combine(Path.GetDirectoryName(destinationFile), String.Format("{0}_{1}{2}", Path.GetFileNameWithoutExtension(destinationFile), sameNamedFiles.Length.ToString("D4"), Path.GetExtension(destinationFile)));
}
File.Copy(path, destinationFile);
File.Delete(path);
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
}
}
public static void InterleaveFiles(string[] sourceFiles, uint interleaveValue,
long startOffest, byte[] paddingBytes, string destinationFile)
{
long currentOffset = 0;
long maxLength = 0;
long sizeDifference = 0;
long bytesToWrite;
long bytesRemaining;
FileStream[] inputStreams = new FileStream[sourceFiles.Length];
long[] fileLengths = new long[sourceFiles.Length];
destinationFile = Path.GetFullPath(destinationFile);
// open destination file for writing
using (FileStream destinationStream = File.OpenWrite(destinationFile))
{
try
{
// build input streams array
for (int i = 0; i < sourceFiles.Length; i++)
{
inputStreams[i] = File.OpenRead(sourceFiles[i]);
fileLengths[i] = inputStreams[i].Length;
// get max file length
if (maxLength < fileLengths[i])
{
maxLength = fileLengths[i];
}
}
// write out blocks
currentOffset = startOffest;
while (currentOffset < maxLength)
{
for (int i = 0; i < sourceFiles.Length; i++)
{
if (currentOffset + interleaveValue < fileLengths[i])
{
// write from file
destinationStream.Write(
ParseFile.ParseSimpleOffset(inputStreams[i], currentOffset, (int)interleaveValue),
0, (int)interleaveValue);
}
else if (currentOffset < fileLengths[i])
{
// write some from file, some from padding
sizeDifference = (currentOffset + interleaveValue) - fileLengths[i];
// write from file
destinationStream.Write(
ParseFile.ParseSimpleOffset(inputStreams[i], currentOffset, (int)(interleaveValue - sizeDifference)),
0, (int)(int)(interleaveValue - sizeDifference));
// write padding bytes
bytesRemaining = sizeDifference;
while (bytesRemaining > 0)
{
bytesToWrite = bytesRemaining > paddingBytes.Length ? paddingBytes.Length : bytesRemaining;
destinationStream.Write(paddingBytes, 0, (int)bytesToWrite);
bytesRemaining -= bytesToWrite;
}
}
else
{
// write padding bytes
bytesRemaining = interleaveValue;
while (bytesRemaining > 0)
{
bytesToWrite = bytesRemaining > paddingBytes.Length ? paddingBytes.Length : bytesRemaining;
destinationStream.Write(paddingBytes, 0, (int)bytesToWrite);
bytesRemaining -= bytesToWrite;
}
}
}
// increment offset
currentOffset += interleaveValue;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
finally
{
// close all readers
for (int i = 0; i < inputStreams.Length; i++)
{
if (inputStreams[i].CanRead)
{
inputStreams[i].Close();
inputStreams[i].Dispose();
}
}
}
}
}
public static string GetNonDuplicateFileName(string destinationFile)
{
if (File.Exists(destinationFile))
{
string[] sameNamedFiles = Directory.GetFiles(Path.GetDirectoryName(destinationFile), Path.GetFileNameWithoutExtension(destinationFile) + "*");
// rename to prevent overwrite
destinationFile = Path.Combine(Path.GetDirectoryName(destinationFile), String.Format("{0}_{1}{2}", Path.GetFileNameWithoutExtension(destinationFile), sameNamedFiles.Length.ToString("D4"), Path.GetExtension(destinationFile)));
}
return destinationFile;
}
public static string[] SplitFile(string sourceFile, long startingOffset, ulong chunkSizeInBytes, string outputFolder)
{
string[] outputFileList;
string outputFileName;
ArrayList outputFiles = new ArrayList();
long fileLength;
ulong currentOffset;
int chunkCount;
using (FileStream sourceStream = File.OpenRead(sourceFile))
{
// get file length
fileLength = sourceStream.Length;
// init counters
chunkCount = 1;
currentOffset = (ulong)startingOffset;
while (currentOffset < (ulong)fileLength)
{
// construct output file name
outputFileName = Path.Combine(outputFolder,
String.Format("{0}.{1}",
Path.GetFileName(sourceFile),
chunkCount.ToString("D3")));
ParseFile.ExtractChunkToFile64(sourceStream, currentOffset, chunkSizeInBytes,
outputFileName, true, true);
outputFiles.Add(outputFileName);
currentOffset += chunkSizeInBytes;
chunkCount++;
}
}
outputFileList = (string[])outputFiles.ToArray(typeof(string));
return outputFileList;
}
public static long? GetFileSize(string path)
{
long? fileSize;
try
{
FileInfo fi = new FileInfo(Path.GetFullPath(path));
fileSize = fi.Length;
}
catch (Exception)
{
fileSize = null;
}
return fileSize;
}
public static void CreateFileFromByteArray(string destinationFile, byte[] sourceBytes)
{
string destinationDirectory = Path.GetDirectoryName(destinationFile);
if (!Directory.Exists(destinationDirectory))
{
Directory.CreateDirectory(destinationDirectory);
}
using (FileStream outStream = File.Open(destinationFile, FileMode.Create, FileAccess.Write, FileShare.Read))
{
outStream.Write(sourceBytes, 0, sourceBytes.Length);
}
}
public static void CreateFileFromString(string destinationFile, string sourceText)
{
string destinationDirectory = Path.GetDirectoryName(destinationFile);
if (!Directory.Exists(destinationDirectory))
{
Directory.CreateDirectory(destinationDirectory);
}
using ( FileStream outStream = File.Open(destinationFile, FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (StreamWriter sw = new StreamWriter(outStream, Encoding.ASCII))
{
sw.Write(sourceText);
}
}
}
public static string GetStringFromFileChunk(FileStream fs, ulong offset, ulong size)
{
StringBuilder sb = new StringBuilder();
int read = 0;
ulong totalBytes = 0;
byte[] bytes = new byte[Constants.FileReadChunkSize];
// reset location
fs.Seek(0, SeekOrigin.Begin);
// move stream pointer in long size chunks
while (offset > long.MaxValue) //
{
fs.Seek(long.MaxValue, SeekOrigin.Current);
offset -= long.MaxValue;
}
// less than a long now, should be ok
fs.Seek((long)offset, SeekOrigin.Current);
int maxread = size > (ulong)bytes.Length ? bytes.Length : (int)size;
while ((read = fs.Read(bytes, 0, maxread)) > 0)
{
for (int i = 0; i < read; i++)
{
sb.Append(bytes[i].ToString("X2"));
}
totalBytes += (ulong)read;
maxread = (size - totalBytes) > (ulong)bytes.Length ? bytes.Length : (int)(size - totalBytes);
}
return sb.ToString();
}
}
}

View file

@ -0,0 +1,7 @@
namespace VGMToolbox.util
{
public interface IDeepCopy<T>
{
T DeepCopy();
}
}

View file

@ -0,0 +1,26 @@
using System;
namespace VGMToolbox.util
{
public class MathUtil
{
public static long RoundUpToByteAlignment(long valueToRound, long byteAlignment)
{
long roundedValue = -1;
roundedValue = (valueToRound + byteAlignment - 1) / byteAlignment * byteAlignment;
return roundedValue;
}
public static ulong RoundUpToByteAlignment(ulong valueToRound, ulong byteAlignment)
{
ulong roundedValue;
roundedValue = (valueToRound + byteAlignment - 1) / byteAlignment * byteAlignment;
return roundedValue;
}
}
}

View file

@ -0,0 +1,9 @@
namespace VGMToolbox.util
{
public class OffsetDescription
{
public string OffsetValue { set; get; }
public string OffsetSize { set; get; }
public string OffsetByteOrder { set; get; }
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace VGMToolbox.util
{
public class RiffCalculatingOffsetDescription : CalculatingOffsetDescription
{
public const string START_OF_STRING = "start of";
public const string END_OF_STRING = "end of";
public string RelativeLocationToRiffChunkString { set; get; }
public string RiffChunkString { set; get; }
}
}

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>usm_extract</RootNamespace>
<AssemblyName>usm_extract</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="src\Program.cs" />
<Compile Include="src\util\ParseFile.cs" />
<Compile Include="src\util\Constants.cs" />
<Compile Include="src\util\FileUtil.cs" />
<Compile Include="src\util\ByteConversion.cs" />
<Compile Include="src\util\OffsetDescription.cs" />
<Compile Include="src\util\CalculatingOffsetDescription.cs" />
<Compile Include="src\util\ByteSearchCalculatingOffsetDescription.cs" />
<Compile Include="src\util\RiffCalculatingOffsetDescription.cs" />
<Compile Include="src\util\MathUtil.cs" />
<Compile Include="src\CriUsmStream.cs" />
<Compile Include="src\MpegStream.cs" />
<Compile Include="src\Mpeg1Stream.cs" />
<Compile Include="src\SofdecStream.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -0,0 +1,23 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "usm_extract", "usm_extract.csproj", "{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Debug|x86.ActiveCfg = Debug|x86
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Debug|x86.Build.0 = Debug|x86
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Release|Any CPU.Build.0 = Release|Any CPU
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Release|x86.ActiveCfg = Release|x86
{3951D6E5-61BE-4D7C-A464-F44D98E9CE83}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal