public ITask CreateDecompressBemaniLz() { return(Build("Decompress Bemani LZ", task => { var files = GetInputFiles(task); if (!files.Any()) { task.Message = "No input files."; return false; } ParallelProgress(task, files, file => { using (var stream = OpenRead(task, file)) { var decoded = _bemaniLzDecoder.Decode(stream); task.Message = $"Deompressed {stream.Length} -> {decoded.Length} bytes."; using (var output = OpenWriteSingle(task, file, i => $"{i}.decoded")) { var writer = new BinaryWriter(output); writer.Write(decoded); output.Flush(); } } }); return true; })); }
public IList <DdrPs2FileDataTableEntry> Decode(DdrPs2FileDataTableChunk chunk) { var data = chunk.Data; var result = new List <DdrPs2FileDataTableEntry>(); var stream = new MemoryStream(data); var offsets = MemoryMarshal.Cast <byte, int>(data.AsSpan(0, data.Length / 4 * 4)); var offsetCount = offsets.Length; for (var i = 0; i < offsetCount; i++) { var newCount = offsets[i] / 4; if (newCount < offsetCount) { offsetCount = newCount; } } for (var i = 0; i < offsetCount; i++) { stream.Position = offsets[i] + (chunk.HasHeaders ? 0xC : 0x0); result.Add(new DdrPs2FileDataTableEntry { Index = i, Data = _bemaniLzDecoder.Decode(stream) }); } return(result); }
public IList <DdrPs2FileDataTableEntry> Decode(DdrPs2FileDataTableChunk chunk) { var data = chunk.Data; var result = new List <DdrPs2FileDataTableEntry>(); var stream = new MemoryStream(data); var offsets = MemoryMarshal.Cast <byte, int>(data.AsSpan(0, data.Length / 4 * 4)); var count = offsets[0]; for (var i = 0; i < count; i++) { var offset = offsets[i + 1]; var length = offsets[i + 1 + count]; stream.Position = offset; result.Add(new DdrPs2FileDataTableEntry { Index = i, Data = _bemaniLzDecoder.Decode(stream) }); } return(result); }
public int FindKey(ReadOnlySpan <byte> database) { var header = database.Slice(0, 16); for (var i = 0; i < 256; i++) { var test = _bemaniLzDecoder.Decode(new MemoryStream(Decrypt(header, i))); if (!test[0].IsLetter()) { continue; } if (!test[1].IsLetter()) { continue; } if (!test[2].IsLetter()) { continue; } if (!test[3].IsLetterOrDigit()) { continue; } if (!test[4].IsLetterOrDigit() && test[4] != 0) { continue; } if (test[5] != 0) { continue; } return(i); } throw new RhythmCodexException("Can't seem to find the key for this MDB"); }
public DdrPs2FileDataTableChunk Read(Stream fileDataBinStream, long length) { var position = -0x800L; var max = length / 0x800 * 0x800; var buffer = new MemoryStream(); var reader = new BinaryReader(fileDataBinStream); var skip = false; var append = false; var empty = new byte[16]; var success = false; var offsets = new List <int>(); while (position < max) { position += 0x800; // if (position == 0x433E1000) // position = position; var block = reader.ReadBytes(0x800); if (append) { buffer.Write(block, 0, block.Length); } if (skip) { skip = !block.AsSpan(0x7F0).ToArray().SequenceEqual(empty); append &= skip; if (!skip && success) { var oldPos = buffer.Position; buffer.Position = offsets[0]; try { var lzBuffer = _bemaniLzDecoder.Decode(buffer); var matches = _heuristicTester.Match(lzBuffer).Where(t => t.Heuristic is SsqHeuristic); if (!matches.Any()) { success = false; } } catch (Exception) { success = false; } finally { buffer.Position = oldPos; } if (!success) { buffer.Position = 0; buffer.SetLength(0); continue; } return(new DdrPs2FileDataTableChunk { Data = buffer.ToArray(), HasHeaders = false }); } continue; } append = true; buffer.Write(block, 0, block.Length); var maxTable = block.Length / 4; success = true; var offsetBlock = MemoryMarshal.Cast <byte, int>(block); offsets.Clear(); for (var i = 0; i < maxTable; i++) { var offset = offsetBlock[i]; if (offset >= 4 && offset < 0x1000000 && !offsets.Contains(offset)) { offsets.Add(offset); } else { success = false; break; } if (maxTable > offset / 4) { maxTable = offset / 4; } } skip = true; if (success) { continue; } buffer.Position = 0; buffer.SetLength(0); append = false; } return(null); }
private IEnumerable <Ddr573File> DecodeInternal(Ddr573Image image, string dbKey) { if (!image.Modules.Any()) { throw new RhythmCodexException("There must be at least one module in the image."); } if (!image.Modules.ContainsKey(0)) { throw new RhythmCodexException("A module with index 0 must be present in the image."); } var readers = image.Modules .ToDictionary(kv => kv.Key, kv => new BinaryReader(new ReadOnlyMemoryStream(kv.Value))); try { foreach (var entry in _ddr573ImageDirectoryDecoder.Decode(image)) { if (!readers.ContainsKey(entry.Module)) { throw new RhythmCodexException($"Module {entry.Module} was requested, but not found."); } var canDecompress = true; var moduleReader = readers[entry.Module]; moduleReader.BaseStream.Position = entry.Offset; Memory <byte> data = moduleReader.ReadBytes(entry.Length); switch (entry.EncryptionType) { case 1: { if (dbKey != null) { data = _ddr573DatabaseDecrypter.Decrypt(data.Span, _ddr573DatabaseDecrypter.ConvertKey(dbKey)); } else { canDecompress = false; } break; } } if (canDecompress) { switch (entry.CompressionType) { case 1: { using (var compressedStream = new ReadOnlyMemoryStream(data)) { try { data = _bemaniLzDecoder.Decode(compressedStream); } catch (Exception) { _logger.Warning($"Entry Id={entry.Id:X8} Module={entry.Module:X4} Offset={entry.Offset:X7} could not be decompressed. It will be extracted as-is."); } } break; } } } yield return(new Ddr573File { Data = data, Id = entry.Id, Module = entry.Module, Offset = entry.Offset, EncryptionType = entry.EncryptionType, Reserved1 = entry.Reserved1, Reserved2 = entry.Reserved2 }); } } finally { foreach (var reader in readers) { reader.Value?.Dispose(); } } }
public DdrPs2FileDataTableChunk GetUnbound(Stream stream) { var cache = new CachedStream(stream); var cacheReader = new BinaryReader(cache); using var snapshot = new SnapshotStream(cache); var snapshotReader = new BinaryReader(snapshot); var firstFile = snapshotReader.ReadInt32(); var tableSize = firstFile / 4 * 4; var table = Enumerable.Range(0, firstFile / 4).Select(_ => snapshotReader.ReadInt32()).ToArray(); var skip = firstFile - tableSize; int index; if (skip > 0) { snapshotReader.ReadBytes(skip); } for (index = 1; index < table.Length; index++) { if (table[index] < table[index - 1]) { break; } } // Warning: big heckin' hack. // We're looking for a TCB table, which puts headers on all the file entries. // There's no way to tell easily outside of this function, so... var prevPosition = cache.Position; cache.Position = table[0]; var headTest0 = cacheReader.ReadInt32(); var headTest1 = cacheReader.ReadInt32(); var headTest2 = cacheReader.ReadInt32(); var hasHeaders = headTest0 > 0 && headTest1 > 0 && headTest2 > 0 && headTest2 > headTest1 && headTest1 > headTest0 && (headTest0 & 0x3) == 0 && ((headTest0 | headTest1 | headTest2) >> 24) == 0; cache.Position = prevPosition; var desiredPosition = table[index - 1]; snapshotReader.ReadBytes((int)(desiredPosition - prevPosition)); if (hasHeaders) { snapshotReader.ReadBytes(0xC); } try { _bemaniLzDecoder.Decode(snapshot); } catch (Exception) { return(null); } return(new DdrPs2FileDataTableChunk { Data = snapshot.ToArray(), HasHeaders = hasHeaders }); }