iNES 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +1 -0
- data/lib/ines.rb +135 -0
- metadata +46 -0
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# iNES ROM format for Ruby #
|
data/lib/ines.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
|
2
|
+
class INES
|
3
|
+
# Header size (16 bytes)
|
4
|
+
INES_HEADER_SIZE = 0x10
|
5
|
+
|
6
|
+
# Trainer size (512 bytes)
|
7
|
+
INES_TRAINER_SIZE = 0x200
|
8
|
+
|
9
|
+
# Program (PRG) ROM size (16384 bytes)
|
10
|
+
INES_PRG_PAGE_SIZE = 0x4000
|
11
|
+
|
12
|
+
# Character (CHR) ROM size (8192 bytes)
|
13
|
+
INES_CHR_PAGE_SIZE = 0x2000
|
14
|
+
|
15
|
+
# The ROM, stored as an array of bytes
|
16
|
+
bytes = []
|
17
|
+
|
18
|
+
# Create an INES instance with an optional file to load
|
19
|
+
def initialize(filename = nil)
|
20
|
+
unless filename.nil?
|
21
|
+
load(filename)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Load a file, replacing all data previously loaded
|
26
|
+
def load(filename)
|
27
|
+
unless File.file? filename
|
28
|
+
raise "file not found: #{filename}"
|
29
|
+
end
|
30
|
+
|
31
|
+
file = File.new(filename, 'r')
|
32
|
+
@bytes = file.read.unpack 'C*'
|
33
|
+
file.close
|
34
|
+
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Save the current data to file
|
39
|
+
def save(filename, overwrite = false)
|
40
|
+
if File.file?(filename) && !overwrite
|
41
|
+
raise "file exists: #{filename}"
|
42
|
+
end
|
43
|
+
|
44
|
+
file = File.new(filename, 'wb')
|
45
|
+
file.write @bytes.pack('C*')
|
46
|
+
file.close
|
47
|
+
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# Write data to the ROM at the defined offset
|
52
|
+
def write(offset, data, enlarge = false)
|
53
|
+
if (offset + data.length) > @bytes.length && !enlarge
|
54
|
+
raise 'writing past the end of the rom'
|
55
|
+
end
|
56
|
+
|
57
|
+
data.length.times { @bytes.delete_at offset }
|
58
|
+
|
59
|
+
for i in 0 ... data.length
|
60
|
+
@bytes.insert(offset + i, data[i])
|
61
|
+
end
|
62
|
+
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# Calculate the data offset, excluding header and trainer (if applicable)
|
67
|
+
def offset
|
68
|
+
return INES_HEADER_SIZE + ((self.trainer?) ? INES_TRAINER_SIZE : 0)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get the iNES header as an array of bytes
|
72
|
+
def header
|
73
|
+
if @bytes.length < INES_HEADER_SIZE
|
74
|
+
raise 'invalid or missing header'
|
75
|
+
end
|
76
|
+
|
77
|
+
return @bytes.slice(0, INES_HEADER_SIZE)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Check whether the ROM has a trainer
|
81
|
+
def trainer?
|
82
|
+
return ((self.header[6] & 0xF) & 4) > 0
|
83
|
+
end
|
84
|
+
|
85
|
+
# Retrieve the trainer from the ROM, if one is available
|
86
|
+
def trainer
|
87
|
+
if self.trainer?
|
88
|
+
if (self.offset + INES_TRAINER_SIZE) > @bytes.length
|
89
|
+
raise 'invalid trainer'
|
90
|
+
end
|
91
|
+
|
92
|
+
return @bytes.slice(self.offset, INES_TRAINER_SIZE)
|
93
|
+
end
|
94
|
+
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# Calculate the program data (PRG) offset from the start of the file
|
99
|
+
def prg_offset
|
100
|
+
return self.offset
|
101
|
+
end
|
102
|
+
|
103
|
+
# Calculate the size of the program data (PRG)
|
104
|
+
def prg_size
|
105
|
+
return self.header[4] * INES_PRG_PAGE_SIZE
|
106
|
+
end
|
107
|
+
|
108
|
+
# Retrieve the program data (PRG) from the ROM
|
109
|
+
def prg
|
110
|
+
if (self.prg_offset + self.prg_size) > @bytes.length
|
111
|
+
raise 'invalid prg'
|
112
|
+
end
|
113
|
+
|
114
|
+
return @bytes.slice(self.prg_offset, self.prg_size)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Calculate the character (CHR) offset from the start of the file
|
118
|
+
def chr_offset
|
119
|
+
return self.offset + self.prg_size
|
120
|
+
end
|
121
|
+
|
122
|
+
# Calculate the size of the character data (CHR)
|
123
|
+
def chr_size
|
124
|
+
return self.header[5] * INES_CHR_PAGE_SIZE
|
125
|
+
end
|
126
|
+
|
127
|
+
# Retrieve the character data (CHR) from the ROM
|
128
|
+
def chr
|
129
|
+
if (self.chr_offset + self.chr_size) > @bytes.length
|
130
|
+
raise 'invalid chr'
|
131
|
+
end
|
132
|
+
|
133
|
+
return @bytes.slice(self.chr_offset, self.chr_size)
|
134
|
+
end
|
135
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iNES
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jack Wilsdon
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-22 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Manipulate iNES ROM files and extract trainer, PRG and CHR roms!
|
15
|
+
email: jack.wilsdon@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/ines.rb
|
21
|
+
- README.md
|
22
|
+
homepage: http://github.com/jackwilsdon/ines
|
23
|
+
licenses: []
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 1.8.11
|
43
|
+
signing_key:
|
44
|
+
specification_version: 3
|
45
|
+
summary: iNES ROM format for Ruby
|
46
|
+
test_files: []
|