Ejemplo n.º 1
0
        public Z64Rom(Rom rom)
        {
            _rom = rom;

            var identity   = (UInt64)_rom.Header.Crc[0] << 32 | _rom.Header.Crc[1];
            var useOffsets = true;

            if (!_tableOffsets.ContainsKey(identity))
            {
                useOffsets = false;
            }

            TableOffsets offsets;

            if (useOffsets)
            {
                offsets = _tableOffsets[identity];
            }
            else
            {
                offsets = new TableOffsets
                {
                    FileTable = FindFileTable(rom.Data)
                };

                if (offsets.FileTable == 0)
                {
                    throw new ArgumentException("File table not found. Is this a valid Zelda 64 ROM?");
                }
            }

            var fileTablePointers = _rom.GetSegment(offsets.FileTable)
                                    .ToWordGroups(4)
                                    .TakeWhile(g => !g.All(w => w == 0))
                                    .ToList();


            var nameTable =
                useOffsets
                ? _rom.GetSegment(offsets.NameTable)
                .ExtractStrings(fileTablePointers.Count)
                .ToList()
                : new List <string>();

            Files = fileTablePointers
                    .Where(f => f[3] != 0xFFFFFFFF && f[2] != 0xFFFFFFFF)
                    .Select((f, i) => new File(
                                f[0], f[1], f[2], f[3],
                                nameTable.Count > i ? nameTable[i] : null,
                                string.Format("{0:0000}-{1:X8}", i + 1, f[0]),
                                null,
                                _rom
                                ))
                    .ToList();

            CodeFile = Files.Cast <File>().FirstOrDefault(f => f.ContainsString("Yoshitaka Yasumoto"));

            IEnumerable <uint[]> overlaySource;

            if (useOffsets)
            {
                overlaySource = offsets.OverlayTables
                                .SelectMany(o => _rom.GetSegment(o.StartAddress, o.RecordCount * o.RecordSize)
                                            .ToWordGroups(o.RecordSize / sizeof(UInt32))
                                            );
            }
            else
            {
                var ovls = Files.Where(f => f.Type == FileType.Overlay)
                           .Select(o => (UInt64)o.VirtualStart << 32 | o.VirtualEnd)
                           .ToList();

                overlaySource = CodeFile.FindTuples(ovls)
                                .SelectMany(t => Utilities.ReadU32(CodeFile.Contents, t.Value + 12) >= 0x80800000
                    ?
                                            CodeFile.Contents.GetSegment(t.Value, 32)
                                            .ToWordGroups(7)
                    :
                                            // Some overlays in Majora's Mask have the vma start and end addreses
                                            // before the virtual file address pair. Here, we compensate for this
                                            // by checking if the vma end is < 0x80800000 (overlay address space).
                                            // If it is, we prepend the preceding 8 bytes with the rest of the record.
                                            CodeFile.Contents.GetSegment(t.Value - 8, 8)
                                            .Concat(CodeFile.Contents.GetSegment(t.Value, 24))
                                            .ToWordGroups(7));
            }

            Overlays = overlaySource
                       //_rom.GetSegment(offsets.EffectOverlayTable, (int)offsets.EffectOverlayCount * (int)OverlayEntry.EffectRecordSize)
                       .Select(r => OverlayEntry.FromWords(r, Files.FirstOrDefault(f => f.VirtualStart == r[0])))
                       .Where(r => r.VmaStart >= 0x80800000 && r.VmaEnd != 0)
                       .OrderBy(o => o.VmaStart)
                       .ToList();
        }