narc 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/LICENSE +9 -0
  2. data/README +11 -1
  3. data/Rakefile +3 -3
  4. data/lib/narc.rb +104 -10
  5. data/lib/narc/cli.rb +27 -1
  6. metadata +4 -2
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ == narc
2
+
3
+ Copyright (c) 2011 arc_meta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README CHANGED
@@ -4,9 +4,19 @@
4
4
  This gem provides a simple API for packing/unpacking *NARC* (Nitro ARChive) files, an archive file format commonly used in Nintendo DS games. It also counts with a (very) simple command line interface.
5
5
 
6
6
  === Known Bugs/Issues
7
- * Unable to pack/unpack NARC files containing files with filenames and/or folders.
7
+ * Unable to pack/unpack NARC files containing folders.
8
8
 
9
9
  === Version Log
10
10
 
11
+ ==== 1.0.0
12
+ * Added support for NARC files with filenamed elements.
13
+ * Now, the filenames of extracted elements of NARC files with no filenames have the format "[element index]_[element index]". E.g:
14
+ 0002_0002
15
+ While the filenames of extracted elements of NARC files with named elements look like this:
16
+ 0002_elementname
17
+ This is done so that when the elements are stored back into the narc, they are stored in the correct order. If the NARC is made with filenamed elements, the index number and the underscore won't appear in the elements' names.
18
+ * Added new command to pack NARC files with element names to the CLI.
19
+ * Added some documentation.
20
+
11
21
  ==== 0.0.0
12
22
  * Initial version.
data/Rakefile CHANGED
@@ -12,17 +12,17 @@ require 'rake/testtask'
12
12
 
13
13
  spec = Gem::Specification.new do |s|
14
14
  s.name = 'narc'
15
- s.version = '0.0.0'
15
+ s.version = '1.0.0'
16
16
  s.platform = Gem::Platform::RUBY
17
17
  s.has_rdoc = true
18
- s.extra_rdoc_files = ['README']
18
+ s.extra_rdoc_files = ['README', 'LICENSE']
19
19
  s.summary = 'A NARC file packing/unpacking gem.'
20
20
  s.description = 'This gem provides a simple API for packing/unpacking NARC (Nitro ARChive) files, an archive file format commonly used in Nintendo DS games. It also counts with a (very) simple command line interface.'
21
21
  s.author = 'arc_meta'
22
22
  s.email = 'arc_nerotech@hotmail.com'
23
23
  s.homepage = 'https://rubygems.org/gems/narc'
24
24
  s.executables << 'narc'
25
- s.files = %w(README Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
25
+ s.files = %w(LICENSE README Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
26
26
  s.require_path = "lib"
27
27
  s.bindir = "bin"
28
28
  end
@@ -15,6 +15,13 @@ require 'narc/cli.rb'
15
15
 
16
16
  class NarcFile
17
17
  attr_accessor :name, :elements
18
+
19
+ =begin rdoc
20
+ NarcFile.new( [name] ) => NarcFile
21
+
22
+
23
+ Instantiates a new <code>NarcFile</code> object. If <code>name</code> is not specified, the name of the NarcFile object will be just "narc".
24
+ =end
18
25
 
19
26
  def initialize(name = "narc")
20
27
  @name = name
@@ -23,6 +30,13 @@ class NarcFile
23
30
  @size_offsets = {}
24
31
  end
25
32
 
33
+ =begin rdoc
34
+ NarcFile.open( filename ) => NarcFile
35
+
36
+
37
+ Instantiates a new <code>NarcFile</code> object from the contents of a NARC file <code>filename</code>.
38
+ =end
39
+
26
40
  def self.open(filename)
27
41
  io = File.open(filename, "rb")
28
42
  narc = self.new(File.basename(filename, ".narc"))
@@ -31,25 +45,39 @@ class NarcFile
31
45
  return narc
32
46
  end
33
47
 
48
+ =begin rdoc
49
+ narcfile.extract_to_folder( [folder name] ) => nil
50
+
51
+
52
+ Dumps the elements of the current <code>NarcFile</code> object to a folder. If <code>folder name</code> is nil or omitted, this folder will be named "ex_<code>[name of the NarcFile object]</code>"
53
+ =end
54
+
34
55
  def extract_to_folder(folder_name = nil)
35
56
  folder_name ||= "ex_" + @name
36
57
  Dir.mkdir(folder_name) unless Dir.exists?(folder_name)
37
58
  Dir.chdir(folder_name) do
38
- for element in @elements
39
- File.open(element.name, "wb") do |file|
59
+ @elements.each_with_index do |element, i|
60
+ File.open(("%04d" % i) + "_" + element.name, "wb") do |file|
40
61
  file.write(element.data)
41
62
  end
42
63
  end
43
64
  end
44
65
  end
45
66
 
67
+ =begin rdoc
68
+ NarcFile.from_folder( [folder name] ) => NarcFile
69
+
70
+
71
+ Instantiates a new <code>NarcFile</code> object from the contents of a folder <code>folder name</code>.
72
+ =end
73
+
46
74
  def self.from_folder(dir)
47
75
  narc = self.new(File.basename(dir))
48
76
  files = Dir.entries(dir).sort - [".", ".."]
49
77
  narc.elements = Array.new(files.size) do Narc::Element.new end
50
78
  Dir.chdir(dir) do
51
79
  files.each_with_index do |file, i|
52
- narc.elements[i].name = file.split("_")[-1]
80
+ narc.elements[i].name = file.split("_", 2)[-1]
53
81
  File.open(file, "rb") do |f|
54
82
  narc.elements[i].data = f.read
55
83
  end
@@ -58,18 +86,52 @@ class NarcFile
58
86
  return narc
59
87
  end
60
88
 
89
+ =begin rdoc
90
+ narcfile.save( [filename] , [include_names?] ) => nil
91
+
92
+
93
+ Makes a NARC file <code>filename</code> from the contents of the current <code>NarcFile</code> object.
94
+
95
+ If <code>filename</code> is nil or omitted, the filename of the new NARC file will be "saved_<code>[name of the NarcFile object]</code>".
96
+
97
+ If <code>include_names?</code> is true, the elements in the NARC file will be named, else, they won't. <em>Default is false</em>.
98
+
99
+
100
+ =end
101
+
61
102
  def save(filename = nil, include_names = false)
62
103
  filename ||= "saved_" + self.name
63
104
  File.open(filename, "w+b") do |f|
64
105
  write_narc_section(f)
65
106
  write_fatb_section(f)
66
- write_fntb_section(f)
107
+ write_fntb_section(f, include_names)
67
108
  write_fimg_section(f)
68
109
  write_size_data(f)
69
110
  end
70
111
  end
71
112
 
72
- def get_data(io)
113
+ =begin rdoc
114
+ narcfile.get_element( [integer] ) => Narc::Element
115
+ narcfile.get_element( [string] ) => Narc::Element
116
+
117
+ If the parameter is a <code>Integer</code>, returns the element of the same index.
118
+
119
+ If it is a <code>String</code>, returns the first element found whose name is the parameter.
120
+
121
+
122
+ =end
123
+
124
+ def get_element(element)
125
+ if element.is_a?(Integer)
126
+ return self.elements[element]
127
+ elsif element.is_a?(String)
128
+ for elm in self.elements
129
+ return elm if elm.name == element
130
+ end
131
+ end
132
+ end
133
+
134
+ def get_data(io) # :nodoc:
73
135
  check_signature(io)
74
136
  get_section_offsets(io)
75
137
  get_elements(io)
@@ -94,9 +156,10 @@ class NarcFile
94
156
  io.pos = @offsets[:btaf] + 0x8
95
157
  @elements = Array.new(io.read(4).unpack('V')[0]) do Narc::Element.new end
96
158
  io.pos = @offsets[:btnf] + 0x8
97
- names = io.read(4).unpack('V')[0] == 0x00000004 ? false : true
159
+ names = io.read(4).unpack('V')[0] == 0x00000004 ? false : true # Check if the narc file has names
160
+ if names then get_names(io) end
98
161
  @elements.size.times do |i|
99
- @elements[i].name = @name + "_" + "%04d" % i
162
+ @elements[i].name = i.to_s unless names
100
163
  io.pos = @offsets[:btaf] + 12 + i * 0x8
101
164
  elem_start, elem_end = io.read(8).unpack('V2')
102
165
  io.pos = @offsets[:gmif] + 0x8 + elem_start
@@ -105,6 +168,16 @@ class NarcFile
105
168
  end
106
169
  end
107
170
 
171
+ def get_names(io)
172
+ io.pos = @offsets[:btnf] + 0x10 # Start of filename data
173
+ i = 0
174
+ for element in self.elements
175
+ size = io.read(1).unpack('C')[0]
176
+ element.name = io.read(size)
177
+ i += 1
178
+ end
179
+ end
180
+
108
181
  def write_narc_section(file)
109
182
  @offsets[:narc] = file.pos
110
183
  file.write(Narc::NarcSignature) # Signature
@@ -129,10 +202,31 @@ class NarcFile
129
202
  end
130
203
  end
131
204
 
132
- def write_fntb_section(file)
205
+ def write_fntb_section(file, include_fntb)
133
206
  @offsets[:btnf] = file.pos
134
207
  file.write(Narc::FntbSignature)
135
- file.write([0x10, 0x4, 0x10000].pack('V3'))
208
+ size = 0x10
209
+ if include_fntb
210
+ @size_offsets[:fntb] = file.pos
211
+ file.write([0x0, 0x8, 0x10000].pack('V3'))
212
+ for element in self.elements
213
+ elmname = element.name
214
+ namesize = elmname.length
215
+ size += namesize + 1
216
+ file.write([namesize].pack('C'))
217
+ file.write(elmname)
218
+ end
219
+ until size % 4 == 0
220
+ file.write([0x0].pack('C'))
221
+ size += 1
222
+ end
223
+ temp = file.pos
224
+ file.pos = @size_offsets[:fntb]
225
+ file.write([size].pack('V'))
226
+ file.pos = temp
227
+ else
228
+ file.write([0x10, 0x4, 0x10000].pack('V3'))
229
+ end
136
230
  end
137
231
 
138
232
  def write_fimg_section(file)
@@ -158,7 +252,7 @@ class NarcFile
158
252
  file.write([filesize].pack('V'))
159
253
  file.pos = @size_offsets[:fatb]
160
254
  file.write([0x8 + 0x4 + (self.elements.size * 8)].pack('V'))
161
-
255
+ # FNTB size was already written in the write_fntb_section method
162
256
  fimgsize = get_fimg_size(file)
163
257
  file.pos = @size_offsets[:fimg]
164
258
  file.write([fimgsize].pack('V'))
@@ -15,10 +15,27 @@ narc -c <input folder> <narc file>
15
15
  file> is absent, the name of the narc file will be the same as the input
16
16
  folder name.
17
17
 
18
+ Options:
19
+ n (only used with the -c parameter): Creates a narc file with named elements.
20
+
21
+ Examples:
22
+
23
+ narc -x n.narc
24
+ Extracts the contents of n.narc to a folder named "ex_n" (because no folder
25
+ name was specified)
26
+
27
+ narc -c folder 1.narc
28
+ Creates a file named "1.narc" (with unnamed elements) with the contents in
29
+ "folder".
30
+
31
+ narc -cn folder 1.narc
32
+ Creates a file named "1.narc" (with named elements) with the contents in
33
+ "folder".
34
+
18
35
  DOC
19
36
 
20
37
  module Narc
21
- class CLI
38
+ class CLI # :nodoc:
22
39
  def initialize(args)
23
40
  @args = args
24
41
  process_cmds
@@ -47,6 +64,15 @@ module Narc
47
64
  narc = NarcFile.from_folder(@args[1])
48
65
  narc.save(@args[2])
49
66
  puts "Narc file was created successfully."
67
+ when '-cn'
68
+ unless @args[1]
69
+ puts "You must provide the path of the folder as argument."
70
+ return
71
+ end
72
+ puts "Creating narc file..."
73
+ narc = NarcFile.from_folder(@args[1])
74
+ narc.save(@args[2], true)
75
+ puts "Narc file was created successfully."
50
76
  end
51
77
  end
52
78
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: narc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-08 00:00:00.000000000Z
12
+ date: 2011-08-10 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: This gem provides a simple API for packing/unpacking NARC (Nitro ARChive)
15
15
  files, an archive file format commonly used in Nintendo DS games. It also counts
@@ -20,7 +20,9 @@ executables:
20
20
  extensions: []
21
21
  extra_rdoc_files:
22
22
  - README
23
+ - LICENSE
23
24
  files:
25
+ - LICENSE
24
26
  - README
25
27
  - Rakefile
26
28
  - bin/narc