예제 #1
0
        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;
            }));
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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");
        }
예제 #5
0
        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);
        }
예제 #6
0
        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();
                }
            }
        }
예제 #7
0
        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
            });
        }