public MixFile(string filename, PackageHashType type, int priority) { this.filename = filename; this.priority = priority; this.type = type; s = GlobalFileSystem.Open(filename); // Detect format type s.Seek(0, SeekOrigin.Begin); var isCncMix = s.ReadUInt16() != 0; // The C&C mix format doesn't contain any flags or encryption var isEncrypted = false; if (!isCncMix) { isEncrypted = (s.ReadUInt16() & 0x2) != 0; } List <PackageEntry> entries; if (isEncrypted) { long unused; entries = ParseHeader(DecryptHeader(s, 4, out dataStart), 0, out unused); } else { entries = ParseHeader(s, isCncMix ? 0 : 4, out dataStart); } index = entries.ToDictionaryWithConflictLog(x => x.Hash, "{0} ({1} format, Encrypted: {2}, DataStart: {3})".F(filename, isCncMix ? "C&C" : "RA/TS/RA2", isEncrypted, dataStart), null, x => "(offs={0}, len={1})".F(x.Offset, x.Length)); }
public MixFile(string filename, PackageHashType type, int priority) { this.filename = filename; this.priority = priority; this.type = type; s = GlobalFileSystem.Open(filename); // Detect format type s.Seek(0, SeekOrigin.Begin); var isCncMix = s.ReadUInt16() != 0; // The C&C mix format doesn't contain any flags or encryption var isEncrypted = false; if (!isCncMix) isEncrypted = (s.ReadUInt16() & 0x2) != 0; List<PackageEntry> entries; if (isEncrypted) { long unused; entries = ParseHeader(DecryptHeader(s, 4, out dataStart), 0, out unused); } else entries = ParseHeader(s, isCncMix ? 0 : 4, out dataStart); index = entries.ToDictionaryWithConflictLog(x => x.Hash, "{0} ({1} format, Encrypted: {2}, DataStart: {3})".F(filename, (isCncMix ? "C&C" : "RA/TS/RA2"), isEncrypted, dataStart), null, x => "(offs={0}, len={1})".F(x.Offset, x.Length) ); }
// Save a mix to disk with the given contents public MixFile(FileSystem context, string filename, int priority, Dictionary <string, byte[]> contents) { this.filename = filename; this.priority = priority; this.type = PackageHashType.Classic; this.context = context; if (File.Exists(filename)) { File.Delete(filename); } s = File.Create(filename); try { index = new Dictionary <uint, PackageEntry>(); contents.Add("local mix database.dat", new XccLocalDatabase(contents.Keys.Append("local mix database.dat")).Data()); Write(contents); } catch { Dispose(); throw; } }
public static uint HashFilename(string name, PackageHashType type) { var padding = name.Length % 4 != 0 ? 4 - name.Length % 4 : 0; var paddedLength = name.Length + padding; // Avoid stack overflows by only allocating small buffers on the stack, and larger ones on the heap. // 64 chars covers most real filenames. var upperPaddedName = paddedLength < 64 ? stackalloc char[paddedLength] : new char[paddedLength]; name.AsSpan().ToUpperInvariant(upperPaddedName); switch (type) { case PackageHashType.Classic: { for (var p = 0; p < padding; p++) { upperPaddedName[paddedLength - 1 - p] = '\0'; } var asciiBytes = paddedLength < 64 ? stackalloc byte[paddedLength] : new byte[paddedLength]; Encoding.ASCII.GetBytes(upperPaddedName, asciiBytes); var data = MemoryMarshal.Cast <byte, uint>(asciiBytes); var result = 0u; foreach (var next in data) { result = ((result << 1) | (result >> 31)) + next; } return(result); } case PackageHashType.CRC32: { var length = name.Length; var lengthRoundedDownToFour = length / 4 * 4; if (length != lengthRoundedDownToFour) { upperPaddedName[length] = (char)(length - lengthRoundedDownToFour); for (var p = 1; p < padding; p++) { upperPaddedName[length + p] = upperPaddedName[lengthRoundedDownToFour]; } } var asciiBytes = paddedLength < 64 ? stackalloc byte[paddedLength] : new byte[paddedLength]; Encoding.ASCII.GetBytes(upperPaddedName, asciiBytes); return(CRC32.Calculate(asciiBytes)); } default: throw new NotImplementedException($"Unknown hash type `{type}`"); } }
static Stream GetFromCache(PackageHashType type, string filename) { var index = type == PackageHashType.CRC32 ? crcHashIndex : classicHashIndex; var folder = index[PackageEntry.HashFilename(filename, type)] .Where(x => x.Exists(filename)) .MinByOrDefault(x => x.Priority); if (folder != null) { return(folder.GetContent(filename)); } return(null); }
// Save a mix to disk with the given contents public MixFile(string filename, int priority, Dictionary<string, byte[]> contents) { this.filename = filename; this.priority = priority; this.type = PackageHashType.Classic; if (File.Exists(filename)) File.Delete(filename); s = File.Create(filename); index = new Dictionary<uint, PackageEntry>(); contents.Add("local mix database.dat", new XccLocalDatabase(contents.Keys.Append("local mix database.dat")).Data()); Write(contents); }
public static uint HashFilename(string name, PackageHashType type) { switch (type) { case PackageHashType.Classic: { name = name.ToUpperInvariant(); if (name.Length % 4 != 0) { name = name.PadRight(name.Length + (4 - name.Length % 4), '\0'); } using (var ms = new MemoryStream(Encoding.ASCII.GetBytes(name))) { var len = name.Length >> 2; uint result = 0; while (len-- != 0) { result = ((result << 1) | (result >> 31)) + ms.ReadUInt32(); } return(result); } } case PackageHashType.CRC32: { name = name.ToUpperInvariant(); var l = name.Length; var a = l >> 2; if ((l & 3) != 0) { name += (char)(l - (a << 2)); var i = 3 - (l & 3); while (i-- != 0) { name += name[a << 2]; } } return(CRC32.Calculate(Encoding.ASCII.GetBytes(name))); } default: throw new NotImplementedException("Unknown hash type `{0}`".F(type)); } }
public static uint HashFilename(string name, PackageHashType type) { switch (type) { case PackageHashType.Classic: { name = name.ToUpperInvariant(); if (name.Length % 4 != 0) { name = name.PadRight(name.Length + (4 - name.Length % 4), '\0'); } var result = 0u; var data = Encoding.ASCII.GetBytes(name); var i = 0; while (i < data.Length) { var next = (uint)(data[i++] | data[i++] << 8 | data[i++] << 16 | data[i++] << 24); result = ((result << 1) | (result >> 31)) + next; } return(result); } case PackageHashType.CRC32: { name = name.ToUpperInvariant(); var l = name.Length; var a = l >> 2; if ((l & 3) != 0) { name += (char)(l - (a << 2)); var i = 3 - (l & 3); while (i-- != 0) { name += name[a << 2]; } } return(CRC32.Calculate(Encoding.ASCII.GetBytes(name))); } default: throw new NotImplementedException($"Unknown hash type `{type}`"); } }
public static uint HashFilename(string name, PackageHashType type) { switch (type) { case PackageHashType.Classic: { name = name.ToUpperInvariant(); if (name.Length % 4 != 0) name = name.PadRight(name.Length + (4 - name.Length % 4), '\0'); var ms = new MemoryStream(Encoding.ASCII.GetBytes(name)); var reader = new BinaryReader(ms); var len = name.Length >> 2; uint result = 0; while (len-- != 0) result = ((result << 1) | (result >> 31)) + reader.ReadUInt32(); return result; } case PackageHashType.CRC32: { name = name.ToUpperInvariant(); var l = name.Length; var a = l >> 2; if ((l & 3) != 0) { name += (char)(l - (a << 2)); var i = 3 - (l & 3); while (i-- != 0) name += name[a << 2]; } return CRC32.Calculate(Encoding.ASCII.GetBytes(name)); } default: throw new NotImplementedException("Unknown hash type `{0}`".F(type)); } }
static Stream GetFromCache(PackageHashType type, string filename) { var index = type == PackageHashType.CRC32 ? crcHashIndex : classicHashIndex; var folder = index[PackageEntry.HashFilename(filename, type)] .Where(x => x.Exists(filename)) .MinByOrDefault(x => x.Priority); if (folder != null) return folder.GetContent(filename); return null; }
public static uint HashFilename(string name, PackageHashType type) { return PackageEntry.HashFilename(name, type); }
public static uint HashFilename(string name, PackageHashType type) { return(PackageEntry.HashFilename(name, type)); }