.nes file format: PHP parsing library

File extension

nes

KS implementation details

License: WTFPL

This page hosts a formal specification of .nes file format using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

PHP source code to parse .nes file format

Ines.php

<?php
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

namespace {
    class Ines extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Kaitai\Struct\Struct $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m__raw_header = $this->_io->readBytes(16);
            $_io__raw_header = new \Kaitai\Struct\Stream($this->_m__raw_header);
            $this->_m_header = new \Ines\Header($_io__raw_header, $this, $this->_root);
            if ($this->header()->f6()->trainer()) {
                $this->_m_trainer = $this->_io->readBytes(512);
            }
            $this->_m_prgRom = $this->_io->readBytes(($this->header()->lenPrgRom() * 16384));
            $this->_m_chrRom = $this->_io->readBytes(($this->header()->lenChrRom() * 8192));
            if ($this->header()->f7()->playchoice10()) {
                $this->_m_playchoice10 = new \Ines\Playchoice10($this->_io, $this, $this->_root);
            }
            if (!($this->_io()->isEof())) {
                $this->_m_title = \Kaitai\Struct\Stream::bytesToStr($this->_io->readBytesFull(), "ASCII");
            }
        }
        protected $_m_header;
        protected $_m_trainer;
        protected $_m_prgRom;
        protected $_m_chrRom;
        protected $_m_playchoice10;
        protected $_m_title;
        protected $_m__raw_header;
        public function header() { return $this->_m_header; }
        public function trainer() { return $this->_m_trainer; }
        public function prgRom() { return $this->_m_prgRom; }
        public function chrRom() { return $this->_m_chrRom; }
        public function playchoice10() { return $this->_m_playchoice10; }
        public function title() { return $this->_m_title; }
        public function _raw_header() { return $this->_m__raw_header; }
    }
}

namespace Ines {
    class Header extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_magic = $this->_io->readBytes(4);
            if (!($this->magic() == "\x4E\x45\x53\x1A")) {
                throw new \Kaitai\Struct\Error\ValidationNotEqualError("\x4E\x45\x53\x1A", $this->magic(), $this->_io(), "/types/header/seq/0");
            }
            $this->_m_lenPrgRom = $this->_io->readU1();
            $this->_m_lenChrRom = $this->_io->readU1();
            $this->_m__raw_f6 = $this->_io->readBytes(1);
            $_io__raw_f6 = new \Kaitai\Struct\Stream($this->_m__raw_f6);
            $this->_m_f6 = new \Ines\Header\F6($_io__raw_f6, $this, $this->_root);
            $this->_m__raw_f7 = $this->_io->readBytes(1);
            $_io__raw_f7 = new \Kaitai\Struct\Stream($this->_m__raw_f7);
            $this->_m_f7 = new \Ines\Header\F7($_io__raw_f7, $this, $this->_root);
            $this->_m_lenPrgRam = $this->_io->readU1();
            $this->_m__raw_f9 = $this->_io->readBytes(1);
            $_io__raw_f9 = new \Kaitai\Struct\Stream($this->_m__raw_f9);
            $this->_m_f9 = new \Ines\Header\F9($_io__raw_f9, $this, $this->_root);
            $this->_m__raw_f10 = $this->_io->readBytes(1);
            $_io__raw_f10 = new \Kaitai\Struct\Stream($this->_m__raw_f10);
            $this->_m_f10 = new \Ines\Header\F10($_io__raw_f10, $this, $this->_root);
            $this->_m_reserved = $this->_io->readBytes(5);
            if (!($this->reserved() == "\x00\x00\x00\x00\x00")) {
                throw new \Kaitai\Struct\Error\ValidationNotEqualError("\x00\x00\x00\x00\x00", $this->reserved(), $this->_io(), "/types/header/seq/8");
            }
        }
        protected $_m_mapper;
        public function mapper() {
            if ($this->_m_mapper !== null)
                return $this->_m_mapper;
            $this->_m_mapper = ($this->f6()->lowerMapper() | ($this->f7()->upperMapper() << 4));
            return $this->_m_mapper;
        }
        protected $_m_magic;
        protected $_m_lenPrgRom;
        protected $_m_lenChrRom;
        protected $_m_f6;
        protected $_m_f7;
        protected $_m_lenPrgRam;
        protected $_m_f9;
        protected $_m_f10;
        protected $_m_reserved;
        protected $_m__raw_f6;
        protected $_m__raw_f7;
        protected $_m__raw_f9;
        protected $_m__raw_f10;
        public function magic() { return $this->_m_magic; }

        /**
         * Size of PRG ROM in 16 KB units
         */
        public function lenPrgRom() { return $this->_m_lenPrgRom; }

        /**
         * Size of CHR ROM in 8 KB units (Value 0 means the board uses CHR RAM)
         */
        public function lenChrRom() { return $this->_m_lenChrRom; }
        public function f6() { return $this->_m_f6; }
        public function f7() { return $this->_m_f7; }

        /**
         * Size of PRG RAM in 8 KB units (Value 0 infers 8 KB for compatibility; see PRG RAM circuit on nesdev.com)
         */
        public function lenPrgRam() { return $this->_m_lenPrgRam; }
        public function f9() { return $this->_m_f9; }

        /**
         * this one is unofficial
         */
        public function f10() { return $this->_m_f10; }
        public function reserved() { return $this->_m_reserved; }
        public function _raw_f6() { return $this->_m__raw_f6; }
        public function _raw_f7() { return $this->_m__raw_f7; }
        public function _raw_f9() { return $this->_m__raw_f9; }
        public function _raw_f10() { return $this->_m__raw_f10; }
    }
}

namespace Ines\Header {
    class F6 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines\Header $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_lowerMapper = $this->_io->readBitsIntBe(4);
            $this->_m_fourScreen = $this->_io->readBitsIntBe(1) != 0;
            $this->_m_trainer = $this->_io->readBitsIntBe(1) != 0;
            $this->_m_hasBatteryRam = $this->_io->readBitsIntBe(1) != 0;
            $this->_m_mirroring = $this->_io->readBitsIntBe(1);
        }
        protected $_m_lowerMapper;
        protected $_m_fourScreen;
        protected $_m_trainer;
        protected $_m_hasBatteryRam;
        protected $_m_mirroring;

        /**
         * Lower nibble of mapper number
         */
        public function lowerMapper() { return $this->_m_lowerMapper; }

        /**
         * Ignore mirroring control or above mirroring bit; instead provide four-screen VRAM
         */
        public function fourScreen() { return $this->_m_fourScreen; }

        /**
         * 512-byte trainer at $7000-$71FF (stored before PRG data)
         */
        public function trainer() { return $this->_m_trainer; }

        /**
         * If on the cartridge contains battery-backed PRG RAM ($6000-7FFF) or other persistent memory
         */
        public function hasBatteryRam() { return $this->_m_hasBatteryRam; }

        /**
         * if 0, horizontal arrangement. if 1, vertical arrangement
         */
        public function mirroring() { return $this->_m_mirroring; }
    }
}

namespace Ines\Header\F6 {
    class Mirroring {
        const HORIZONTAL = 0;
        const VERTICAL = 1;
    }
}

namespace Ines\Header {
    class F7 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines\Header $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_upperMapper = $this->_io->readBitsIntBe(4);
            $this->_m_format = $this->_io->readBitsIntBe(2);
            $this->_m_playchoice10 = $this->_io->readBitsIntBe(1) != 0;
            $this->_m_vsUnisystem = $this->_io->readBitsIntBe(1) != 0;
        }
        protected $_m_upperMapper;
        protected $_m_format;
        protected $_m_playchoice10;
        protected $_m_vsUnisystem;

        /**
         * Upper nibble of mapper number
         */
        public function upperMapper() { return $this->_m_upperMapper; }

        /**
         * If equal to 2, flags 8-15 are in NES 2.0 format
         */
        public function format() { return $this->_m_format; }

        /**
         * Determines if it made for a Nintendo PlayChoice-10 or not
         */
        public function playchoice10() { return $this->_m_playchoice10; }

        /**
         * Determines if it is made for a Nintendo VS Unisystem or not
         */
        public function vsUnisystem() { return $this->_m_vsUnisystem; }
    }
}

namespace Ines\Header {
    class F9 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines\Header $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_reserved = $this->_io->readBitsIntBe(7);
            $this->_m_tvSystem = $this->_io->readBitsIntBe(1);
        }
        protected $_m_reserved;
        protected $_m_tvSystem;
        public function reserved() { return $this->_m_reserved; }

        /**
         * if 0, NTSC. If 1, PAL.
         */
        public function tvSystem() { return $this->_m_tvSystem; }
    }
}

namespace Ines\Header\F9 {
    class TvSystem {
        const NTSC = 0;
        const PAL = 1;
    }
}

namespace Ines\Header {
    class F10 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines\Header $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_reserved1 = $this->_io->readBitsIntBe(2);
            $this->_m_busConflict = $this->_io->readBitsIntBe(1) != 0;
            $this->_m_prgRam = $this->_io->readBitsIntBe(1) != 0;
            $this->_m_reserved2 = $this->_io->readBitsIntBe(2);
            $this->_m_tvSystem = $this->_io->readBitsIntBe(2);
        }
        protected $_m_reserved1;
        protected $_m_busConflict;
        protected $_m_prgRam;
        protected $_m_reserved2;
        protected $_m_tvSystem;
        public function reserved1() { return $this->_m_reserved1; }

        /**
         * If 0, no bus conflicts. If 1, bus conflicts.
         */
        public function busConflict() { return $this->_m_busConflict; }

        /**
         * If 0, PRG ram is present. If 1, not present.
         */
        public function prgRam() { return $this->_m_prgRam; }
        public function reserved2() { return $this->_m_reserved2; }

        /**
         * if 0, NTSC. If 2, PAL. If 1 or 3, dual compatible.
         */
        public function tvSystem() { return $this->_m_tvSystem; }
    }
}

namespace Ines\Header\F10 {
    class TvSystem {
        const NTSC = 0;
        const DUAL1 = 1;
        const PAL = 2;
        const DUAL2 = 3;
    }
}

namespace Ines {
    class Playchoice10 extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_instRom = $this->_io->readBytes(8192);
            $this->_m_prom = new \Ines\Playchoice10\Prom($this->_io, $this, $this->_root);
        }
        protected $_m_instRom;
        protected $_m_prom;
        public function instRom() { return $this->_m_instRom; }
        public function prom() { return $this->_m_prom; }
    }
}

namespace Ines\Playchoice10 {
    class Prom extends \Kaitai\Struct\Struct {
        public function __construct(\Kaitai\Struct\Stream $_io, \Ines\Playchoice10 $_parent = null, \Ines $_root = null) {
            parent::__construct($_io, $_parent, $_root);
            $this->_read();
        }

        private function _read() {
            $this->_m_data = $this->_io->readBytes(16);
            $this->_m_counterOut = $this->_io->readBytes(16);
        }
        protected $_m_data;
        protected $_m_counterOut;
        public function data() { return $this->_m_data; }
        public function counterOut() { return $this->_m_counterOut; }
    }
}