nwn-lib 0.4.9 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -269,3 +269,33 @@ Bernhard Stoeckner <elven@swordcoast.net> (10):
269
269
  Some medium rare bugfixes, and a overloaded operator for GFF structs,
270
270
  which can be used to comfortable walk on trees.
271
271
 
272
+ === 0.4.10
273
+ Bernhard Stoeckner <elven@swordcoast.net> (23):
274
+ bin/nwn-erf: exit(1) on errors
275
+ bin/nwn-erf: support extracting parts of archive with -x
276
+ Erf::Erf: set correct internal year on initialize
277
+ bin/nwn-gff: fix reading gff data from stdin
278
+ Gff::Field: transform type to symbols on extend
279
+ Gff::Struct#path: return full data type by walking the tree on the fly
280
+ Gff: add :pretty format that prettyprints
281
+ Gff::Struct, Gff::Field: add generic box/unbox methods
282
+ Gff: JSON support
283
+ new ENV NWN_LIB_IN_ENCODING specifies nwn-gff encoding
284
+ :pretty-print boxes before printing
285
+ Gff: JSON support adheres NWN_LIB_PRETTY_JSON env var
286
+ Kivinen-format: refactor into Marshal load/dump interface
287
+ Res/ContentObject: minor internal cleanups
288
+ Gff::Reader: do not compact exolocstrs on read-in
289
+ YAML/JSON support: fix spec, add dep, fix files to not clash with gem names
290
+ Rakefile: spec support for >= 1.1.9
291
+ NWN::Key: .key, .bif reading support
292
+ Resources::DirectoryContainer: do not fail on invalid files in directory
293
+ documentation updates
294
+ bin/nwn-erf: do not set description str_ref to 0x0
295
+ NWN::Gff: refactor API to properly partition different file format handlers
296
+
297
+ A swath of bugfixes, JSON read/write, and finally .key and .bif reading support.
298
+ Also, Resources::Manager got some documentation and a few touches here and there,
299
+ as did bin/nwn-erf, which supports partial extraction now.
300
+ For our non-ASCII users, there is a ENV variable that can be used to specify the
301
+ encoding in which local GFF data is supposed to be in.
data/HOWTO CHANGED
@@ -168,3 +168,43 @@ Now read-only access with a TlkSet:
168
168
 
169
169
  You cannot use TlkSet to write out .tlk files or modify
170
170
  existing entries - it is merely a wrapper.
171
+
172
+ === Accessing .key index files
173
+
174
+ A key file is an index into all shipped game resources.
175
+
176
+ key = Key::Key.new(File.new("/path/to/chitin.key", "r"), "/path/to/")
177
+
178
+ This will lookup all indexed bif files and the resources
179
+ contained within.
180
+
181
+ === Resource Manager
182
+
183
+ The resource manager can be used to simulate a NWN-style
184
+ resource manager to read files from .key/bifs, override,
185
+ haks, and similar sources. Files are located in the reverse
186
+ order that their containers are added to the Manager.
187
+
188
+ Example detailing the usual NWN lookup procedure:
189
+
190
+ nwn_path = "/path/to/nwn/"
191
+ mgr = Resources::Manager.new
192
+
193
+ # First, all the base data files.
194
+ for key in %w{chitin.key xp1.key xp1patch.key xp2.key xp2patch.key xp3.key}
195
+ mgr.add_container(Key::Key.new(File.new(nwn_path + key, "r"), nwn_path))
196
+ end
197
+
198
+ # Override
199
+ mgr.add_container(Resources::DirectoryContainer.new(nwn_path + "override"))
200
+
201
+ # All custom haks
202
+ for hak in %w{a.hak b.hak c.hak}
203
+ mgr.add_container(Erf::Erf.new(File.new(nwn_path + "hak/" + hak, "r")))
204
+ end
205
+
206
+ # Now you can retrieve any indexed file:
207
+ puts mgr.get("actions.2da")
208
+
209
+ Note that initialising the whole Resource Manager this way takes
210
+ a few seconds depending on IO and CPU speed.
data/README CHANGED
@@ -11,15 +11,22 @@ They should work with NWN2 just as well, since the file format specifications di
11
11
 
12
12
  * GFF 3.2 (are, git, gic, dlg, itp, ifo, jrl, fac, ssf, ut*, among others)
13
13
  * ERF (mod, hak, erf, among others)
14
+ * KEY, BIF (key, data/*.bif)
14
15
  * 2DA V2.0
15
16
  * TLK
16
17
 
17
- ==== nwn-lib can read and write the following representations of GFF data:
18
+ ==== nwn-lib can handle the following representations of GFF data:
18
19
 
19
- * kivinen-style ("gffprint.pl") presentation of data
20
+ ===== read & write:
21
+ * native gff
20
22
  * yaml presentation of data
23
+ * json presentation of data (with proper UTF-8 conversion)
21
24
  * ruby-native marshalling of gff data
22
25
 
26
+ ===== just write, for now:
27
+ * kivinen-style ("gffprint.pl") presentation of data
28
+ * prettyprint (ruby-specific)
29
+
23
30
  ==== Also in the box:
24
31
 
25
32
  * shell scripts and tools to simplify your life (see BINARIES)
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.4.9"
12
+ VERS = "0.4.10"
13
13
  CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage"]
14
14
  RDOC_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', \
15
15
  'nwn-lib: a ruby library for accessing NWN resource files', \
@@ -44,6 +44,7 @@ spec = Gem::Specification.new do |s|
44
44
  s.files = %w(COPYING CHANGELOG README Rakefile) + Dir.glob("{bin,doc,spec,lib,tools,scripts,data}/**/*")
45
45
  s.require_path = "lib"
46
46
  s.bindir = "bin"
47
+ s.add_dependency('json', '>= 1.1.9')
47
48
  end
48
49
 
49
50
  Rake::GemPackageTask.new(spec) do |p|
@@ -70,7 +71,7 @@ end
70
71
 
71
72
  desc "Upload nwn-lib gem to rubyforge"
72
73
  task :release => [:package] do
73
- sh %{rubyforge login}
74
+ #sh %{rubyforge login}
74
75
  sh %{rubyforge add_release nwn-lib #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.tgz}
75
76
  sh %{rubyforge add_file nwn-lib #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.gem}
76
77
  end
@@ -80,8 +81,6 @@ require "spec/rake/spectask"
80
81
  desc "Run specs with coverage"
81
82
  Spec::Rake::SpecTask.new("spec") do |t|
82
83
  t.spec_files = FileList["spec/*_spec.rb"]
83
- t.spec_opts = File.read("spec/spec.opts").split("\n")
84
- t.rcov_opts = File.read("spec/rcov.opts").split("\n")
85
84
  t.rcov = true
86
85
  end
87
86
 
@@ -89,13 +88,10 @@ desc "Run specs without coverage"
89
88
  task :default => [:spec_no_cov]
90
89
  Spec::Rake::SpecTask.new("spec_no_cov") do |t|
91
90
  t.spec_files = FileList["spec/*_spec.rb"]
92
- t.spec_opts = File.read("spec/spec.opts").split("\n")
93
91
  end
94
92
 
95
93
  desc "Run rcov only"
96
94
  Spec::Rake::SpecTask.new("rcov") do |t|
97
- t.rcov_opts = File.read("spec/rcov.opts").split("\n")
98
- t.spec_opts = File.read("spec/spec.opts").split("\n")
99
95
  t.spec_files = FileList["spec/*_spec.rb"]
100
96
  t.rcov = true
101
97
  end
data/SETTINGS CHANGED
@@ -6,6 +6,14 @@ Under linux, just add them to your shell environment (usually .bashrc), like so:
6
6
 
7
7
  export NWN_LIB_DEBUG=0
8
8
 
9
+ == NWN_LIB_IN_ENCODING
10
+
11
+ The character encoding your local data files are in. Defaults to ISO-8859-1.
12
+
13
+ == NWN_LIB_PRETTY_JSON
14
+
15
+ Set to non-nil to make :json print pretty output (with whitespace) instead of a spaghetti
16
+ bowl. nwn-lib returns compact json output, by default. Does not affect reading json.
9
17
 
10
18
  == NWN_LIB_DEBUG
11
19
 
@@ -24,7 +32,7 @@ time tracking things down.
24
32
 
25
33
  Note that nwn-lib takes a parameter that can force a specific NWN version.
26
34
 
27
- === NWN_LIB_RESREF32
35
+ == NWN_LIB_RESREF32
28
36
 
29
37
  Set this to "1" if you are working with NWN2 files and do not want to see the warnings
30
38
  generated by too long resref values.
data/bin/nwn-erf CHANGED
@@ -9,6 +9,8 @@ $type = 'ERF'
9
9
  $allow_duplicates = false
10
10
  $descriptions = {}
11
11
  $version = "V1.0"
12
+ $file = nil
13
+ $error = 0
12
14
 
13
15
  # tar-compat mode: first argument is options if no dash is specified.
14
16
  ARGV[0] = "-" + ARGV[0] if ARGV.size > 0 && ARGV[0][0] != ?-
@@ -28,7 +30,7 @@ begin OptionParser.new do |o|
28
30
  o.on "-c", "--create", "Create a new archive with the given files as contents." do
29
31
  $action = :c
30
32
  end
31
- o.on "-x", "--extract", "Extract all files to current directory." do
33
+ o.on "-x", "--extract", "Extract FILEs (or all) to current directory." do
32
34
  $action = :x
33
35
  end
34
36
  o.on "-a", "--add", "Add files to the given archive.",
@@ -131,7 +133,17 @@ case $action
131
133
  when :x
132
134
  input {|f|
133
135
  erf = NWN::Erf::Erf.new(f)
136
+ ARGV.each {|x|
137
+ wot = erf.content.select {|cc| cc.filename == x }
138
+ if wot.size == 0
139
+ $stderr.puts "nwn-erf: #{x}: not found in erf"
140
+ $error = 1
141
+ end
142
+ }
143
+ what = ARGV.map {|x| x.downcase }
134
144
  erf.content.each {|c|
145
+ next if what.size > 0 && !what.index(c.filename.downcase)
146
+
135
147
  puts "%s" % [c.filename] if $verbose
136
148
  output(c.filename) {|ff|
137
149
  ff.write(c.get)
@@ -146,7 +158,6 @@ case $action
146
158
 
147
159
  if $descriptions
148
160
  erf.localized_strings.merge! $descriptions
149
- erf.description_str_ref = 0
150
161
  end
151
162
 
152
163
  ARGV.each {|a|
@@ -163,7 +174,6 @@ case $action
163
174
 
164
175
  if $descriptions
165
176
  erf.localized_strings.merge! $descriptions
166
- erf.description_str_ref = 0
167
177
  end
168
178
 
169
179
  ARGV.each {|arg|
@@ -192,3 +202,8 @@ case $action
192
202
  else
193
203
  raise ArgumentError, "You need to specify a mode of operation (try -h)."
194
204
  end
205
+
206
+ if $error == 1
207
+ $stderr.puts "nwn-erf: Exiting with failure status due to previous errors"
208
+ exit(1)
209
+ end
data/bin/nwn-gff CHANGED
@@ -7,6 +7,7 @@ Thread.abort_on_exception = true
7
7
 
8
8
  $options = {
9
9
  :backup => nil,
10
+ :encoding => nil,
10
11
  :force => false,
11
12
  :infile => '-',
12
13
  :outfile => '-',
@@ -25,8 +26,8 @@ begin OptionParser.new do |o|
25
26
  o.on "-i", "--infile FILE", "Input file (default: stdin)" do |f|
26
27
  $options[:infile] = f
27
28
  end
28
- o.on "-l, ""--infile-format FORMAT", [:auto] + NWN::Gff::FileFormats,
29
- "Input format (#{([:auto] + NWN::Gff::FileFormats).join(', ')})",
29
+ o.on "-l, ""--infile-format FORMAT", [:auto] + NWN::Gff::InputFormats.keys,
30
+ "Input format (#{([:auto] + NWN::Gff::InputFormats.keys).join(', ')})",
30
31
  "(default: auto - try to guess based on extension)" do |f|
31
32
  $options[:informat] = f
32
33
  end
@@ -34,8 +35,8 @@ begin OptionParser.new do |o|
34
35
  o.on "-o", "--outfile FILE", "Output file (default: stdout)" do |f|
35
36
  $options[:outfile] = f
36
37
  end
37
- o.on "-k", "--outfile-format FORMAT", [:in, :none] + NWN::Gff::FileFormats,
38
- "Output format (#{([:none, :in] + NWN::Gff::FileFormats).join(', ')})",
38
+ o.on "-k", "--outfile-format FORMAT", [:in, :none] + NWN::Gff::OutputFormats.keys,
39
+ "Output format (#{([:none, :in] + NWN::Gff::OutputFormats.keys).join(', ')})",
39
40
  "(default: in when stdout, try to guess based on extension otherwise)" do |f|
40
41
  $options[:outformat] = f
41
42
  end
@@ -48,6 +49,10 @@ begin OptionParser.new do |o|
48
49
  "(see `man cp' for a description)" do |b|
49
50
  $options[:backup] = b.nil? ? true : b
50
51
  end
52
+ o.on "--encoding ENCODING", "sets the used input encoding in which your NWN",
53
+ "files are encoded in" do |e|
54
+ $options[:encoding] = e
55
+ end
51
56
 
52
57
  o.on "-1", "--nwn1", "Allow 16 byte resrefs." do
53
58
  ENV['NWN_LIB_RESREF32'] = nil
@@ -110,6 +115,10 @@ end
110
115
  $options[:informat] or fail "No input format specified."
111
116
  $options[:outformat] or fail "No output format specified."
112
117
 
118
+ if $options[:encoding]
119
+ NWN.setting(:in_encoding, $options[:encoding])
120
+ end
121
+
113
122
  if :auto == $options[:informat]
114
123
  $options[:informat] = NWN::Gff.guess_file_format($options[:infile].downcase)
115
124
  fail "Cannot guess infile format from filename, specify with -l." unless
@@ -125,7 +134,7 @@ elsif :in == $options[:outformat]
125
134
  end
126
135
 
127
136
  vputs "Reading: #{$options[:infile]}"
128
- data_in = $options[:infile] == '-' ? $stdin : File.open($options[:infile], "rb")
137
+ data_in = $options[:infile] == '-' ? StringIO.new($stdin.read) : File.open($options[:infile], "rb")
129
138
  data_in = NWN::Gff.read(data_in, $options[:informat])
130
139
 
131
140
  # verify that we read a GFF struct
data/lib/nwn/all.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  require 'stringio'
2
2
  require 'nwn/io'
3
3
  require 'nwn/twoda'
4
+ require 'nwn/settings'
4
5
  require 'nwn/res'
5
6
  require 'nwn/gff'
6
7
  require 'nwn/tlk'
8
+ require 'nwn/key'
7
9
  require 'nwn/erf'
8
- require 'nwn/yaml'
9
- require 'nwn/kivinen'
10
+ require 'nwn/yaml_support'
11
+ require 'nwn/json_support'
12
+ require 'nwn/kivinen_support'
10
13
  require 'nwn/scripting'
11
- require 'nwn/settings'
data/lib/nwn/erf.rb CHANGED
@@ -22,7 +22,7 @@ module NWN
22
22
  @localized_strings = {}
23
23
  @io = io
24
24
  @file_type, @file_version = "ERF", "V1.0"
25
- @year = Time.now.year
25
+ @year = Time.now.year - 1900
26
26
  @description_str_ref = 0xffffffff
27
27
  @day_of_year = Time.now.yday
28
28
  read_from io if io
data/lib/nwn/gff/field.rb CHANGED
@@ -16,10 +16,15 @@ module NWN::Gff::Field
16
16
  # This is set internally by Gff::Reader on load.
17
17
  attr_accessor :parent
18
18
 
19
+ # Transform type to symbol on extend.
20
+ def self.extended p1 #:nodoc:
21
+ p1['type'] = p1['type'].to_sym if p1['type']
22
+ end
23
+
19
24
  # Create a new NWN::Gff::Field
20
25
  def self.new label, type, value
21
26
  s = {}.extend(self)
22
- s['label'], s['type'], s['value'] = label, type, value
27
+ s['label'], s['type'], s['value'] = label, type.to_sym, value
23
28
  s.extend_meta_classes
24
29
  s.validate
25
30
  s
@@ -190,4 +195,48 @@ module NWN::Gff::Field
190
195
  end
191
196
  #:startdoc:
192
197
 
198
+ # Deep-unboxes a Hash, e.g. iterating down, converting all strings
199
+ # from the native charset.
200
+ def self.unbox! element, parent_label, parent = nil
201
+ element.extend(NWN::Gff::Field)
202
+ element.field_label = parent_label
203
+ element.parent = parent
204
+ element.str_ref ||= NWN::Gff::Field::DEFAULT_STR_REF if element.respond_to?('str_ref=')
205
+
206
+ element.extend_meta_classes
207
+ case element.field_type
208
+ when :cexolocstr
209
+ element.field_value.each {|x,y|
210
+ element.field_value[x.to_i] = NWN::IconvNativeToGff.call.iconv(element.field_value.delete(x))
211
+ }
212
+ when :cexostr
213
+ element.field_value = NWN::IconvNativeToGff.call.iconv(element.field_value)
214
+
215
+ when :list
216
+ element.field_value.each_with_index {|x,idx|
217
+ element.field_value[idx] = NWN::Gff::Struct.unbox!(x, element)
218
+ }
219
+ when :struct
220
+ element.field_value = NWN::Gff::Struct.unbox!(element.field_value, element)
221
+ end
222
+ element.validate
223
+ element
224
+ end
225
+
226
+ # Returns a hash of this Field without the API calls mixed in,
227
+ # all language-strings transformed by str_handler.
228
+ def box
229
+ t = Hash[self]
230
+ t.delete('label')
231
+ case field_type
232
+ when :cexolocstr
233
+ t['value'].each {|x,y|
234
+ t['value'][x] = NWN::IconvGffToNative.call.iconv(y)
235
+ }
236
+ when :cexostr
237
+ t['value'] = NWN::IconvGffToNative.call.iconv(t['value'])
238
+ end
239
+ t
240
+ end
241
+
193
242
  end
@@ -180,8 +180,6 @@ class NWN::Gff::Reader
180
180
  exostr[id] = str
181
181
  }
182
182
  len = total_size + 4
183
- # Filter out empty strings.
184
- exostr.reject! {|k,v| v.nil? || v.empty?}
185
183
  exostr
186
184
 
187
185
  when :void
@@ -189,7 +187,7 @@ class NWN::Gff::Reader
189
187
  @field_data[data_or_offset + 4, len].unpack("H*")[0]
190
188
 
191
189
  when :struct
192
- read_struct data_or_offset, field.path, field.parent.data_version
190
+ read_struct data_or_offset, nil, field.parent.data_version
193
191
 
194
192
  when :list
195
193
  list = []
@@ -210,7 +208,7 @@ class NWN::Gff::Reader
210
208
  data_or_offset += 1
211
209
 
212
210
  for i in data_or_offset...(data_or_offset + count)
213
- list << read_struct(@list_indices[i], field.path, field.parent.data_version)
211
+ list << read_struct(@list_indices[i], nil, field.parent.data_version)
214
212
  end
215
213
 
216
214
  list
@@ -30,7 +30,11 @@ module NWN::Gff::Struct
30
30
 
31
31
  # Returns the path to this struct (which is usually __data_type)
32
32
  def path
33
- @data_type.to_s
33
+ if @element
34
+ @element.path
35
+ else
36
+ @data_type.to_s
37
+ end
34
38
  end
35
39
 
36
40
  def element= e #:nodoc:
@@ -200,4 +204,39 @@ module NWN::Gff::Struct
200
204
  by_path(path)
201
205
  end
202
206
 
207
+ # Deep-unboxes a Hash, e.g. iterating down, converting it to
208
+ # the native charset.
209
+ def self.unbox! o, parent = nil
210
+ o.extend(NWN::Gff::Struct)
211
+ o.struct_id = o.delete('__struct_id')
212
+ o.data_type = if o['__data_type']
213
+ o.delete('__data_type')
214
+ else
215
+ o.path
216
+ end
217
+ o.data_version = o.delete('__data_version')
218
+
219
+ o.element = parent if parent
220
+
221
+ o.each {|label,element|
222
+ o[label] = NWN::Gff::Field.unbox!(element, label, o)
223
+ }
224
+
225
+ o
226
+ end
227
+
228
+ # Returns a hash of this Struct without the API calls mixed in,
229
+ # converting it from the native charset.
230
+ def box
231
+ t = Hash[self]
232
+ t.merge!({
233
+ '__struct_id' => self.struct_id,
234
+ '__data_version' => self.data_version,
235
+ })
236
+ t.merge!({
237
+ '__data_type' => self.data_type
238
+ }) if self.element == nil
239
+ t
240
+ end
241
+
203
242
  end
data/lib/nwn/gff.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'pp'
2
+
1
3
  module NWN
2
4
  module Gff
3
5
  # This error gets thrown if reading or writing fails.
@@ -56,20 +58,35 @@ module NWN
56
58
  :double => 'd',
57
59
  }.freeze
58
60
 
59
- # These field types can never be inlined in YAML.
60
- YAMLNonInlineableFields = [:struct, :list, :cexolocstr]
61
+ # Registers a new format handler that can deal with file formats for nwn-lib gff handling.
62
+ def self.register_format_handler name, fileFormatRegexp, klass, reads = true, writes = true
63
+ InputFormats[name.to_sym] = klass if reads
64
+ OutputFormats[name.to_sym] = klass if writes
65
+ FileFormatGuesses[fileFormatRegexp] = name.to_sym
66
+ end
67
+
68
+ class Handler
69
+ def self.load io
70
+ NWN::Gff::Reader.read(io)
71
+ end
72
+ def self.dump data, io
73
+ NWN::Gff::Writer.dump(data, io)
74
+ end
75
+ end
76
+
77
+ class Pretty
78
+ def self.dump data, io
79
+ old = $> ; $> = io ; pp data.box ; $> = old
80
+ end
81
+ end
61
82
 
62
- FileFormats = [:gff, :yaml, :kivinen, :marshal]
83
+ InputFormats = {}
84
+ OutputFormats = {}
85
+ FileFormatGuesses = {}
63
86
 
64
- FileFormatGuesses = {
65
- /^ut[cdeimpstw]$/ => :gff,
66
- /^(git|are|gic)$/ => :gff,
67
- /^(mod|ifo|fac|ssf|dlg|itp)$/ => :gff,
68
- /^(bic)$/ => :gff,
69
- /^ya?ml$/ => :yaml,
70
- /^marshal$/ => :marshal,
71
- /^k(ivinen)?$/ => :kivinen,
72
- }
87
+ register_format_handler :gff, /^(ut[cdeimpstw]|git|are|gic|mod|ifo|fac|ssf|dlg|itp|bic)$/, NWN::Gff::Handler
88
+ register_format_handler :marshal, /^marshal$/, Marshal
89
+ register_format_handler :pretty, /^$/, Pretty, false, true
73
90
 
74
91
  def self.guess_file_format(filename)
75
92
  extension = File.extname(filename.downcase)[1..-1]
@@ -77,34 +94,18 @@ module NWN
77
94
  end
78
95
 
79
96
  def self.read(io, format)
80
- return case format
81
- when :gff
82
- NWN::Gff::Reader.read(io)
83
- when :yaml
84
- YAML.load(io)
85
- when :marshal
86
- Marshal.load(io)
87
- when :kivinen
88
- raise NotImplementedError, "Reading kivinen-style data is not supported."
89
- else
90
- raise NotImplementedError, "Don't know how to read #{format}."
97
+ if InputFormats[format]
98
+ InputFormats[format].load(io)
99
+ else
100
+ raise NotImplementedError, "Don't know how to read #{format}."
91
101
  end
92
102
  end
93
103
 
94
104
  def self.write(io, format, data)
95
- case format
96
- when :gff
97
- NWN::Gff::Writer.dump(data, io)
98
- when :yaml
99
- io.puts data.to_yaml
100
- when :marshal
101
- io.print Marshal.dump(data)
102
- when :kivinen
103
- data.kivinen_format $options[:types], nil, nil do |l,v|
104
- io.puts "%s:\t%s" % [l, v]
105
- end
106
- else
107
- raise NotImplementedError, "Don't know how to write data-format #{format.inspect}"
105
+ if OutputFormats[format]
106
+ OutputFormats[format].dump(data, io)
107
+ else
108
+ raise NotImplementedError, "Don't know how to write #{format}."
108
109
  end
109
110
  end
110
111
  end
@@ -0,0 +1,37 @@
1
+ require 'json'
2
+
3
+ module NWN::Gff::Struct
4
+ def to_json(*a)
5
+ box.to_json(*a)
6
+ end
7
+ end
8
+
9
+ module NWN::Gff::Field
10
+ def to_json(*a)
11
+ box.to_json(*a)
12
+ end
13
+ end
14
+
15
+ module NWN::Gff::JSON
16
+ def self.load io
17
+ json = if io.respond_to?(:to_str)
18
+ io.to_str
19
+ elsif io.respond_to?(:to_io)
20
+ io.to_io.read
21
+ else
22
+ io.read
23
+ end
24
+
25
+ NWN::Gff::Struct.unbox!(JSON.parse(json), nil)
26
+ end
27
+
28
+ def self.dump struct, io
29
+ if NWN.setting(:pretty_json)
30
+ io.puts JSON.pretty_generate(struct)
31
+ else
32
+ io.print JSON.generate(struct)
33
+ end
34
+ end
35
+ end
36
+
37
+ NWN::Gff.register_format_handler :json, /^json$/, NWN::Gff::JSON
data/lib/nwn/key.rb ADDED
@@ -0,0 +1,144 @@
1
+ module NWN
2
+ module Key
3
+
4
+ # A Bif object encapsulates an open file handle pointing
5
+ # to a .bif file. It's contents are indexed on first access,
6
+ # not on creation by NWN::Key::Key (to speed up things).
7
+ class Bif
8
+
9
+ # The Key object this Bif belongs to.
10
+ attr_reader :key
11
+
12
+ # The IO object pointing to the .bif file.
13
+ attr_reader :io
14
+
15
+ # A hash containing the resources contained. Usually not needed,
16
+ # accessed by the encapsulating Key object.
17
+ attr_reader :contained
18
+
19
+ def initialize key, io
20
+ @key = key
21
+ @io = io
22
+
23
+ @contained = {}
24
+
25
+ @file_type, @file_version,
26
+ @var_res_count, @fix_res_count,
27
+ @var_table_offset =
28
+ io.e_read(4 + 4 + 3 * 4, "header").unpack("a4 a4 V V V")
29
+
30
+ @io.seek(@var_table_offset)
31
+ data = @io.e_read(@var_res_count * 16, "var res table")
32
+ i = 0
33
+ while (x = data[i, 16]) && x.size == 16
34
+ i += 16
35
+ id, offset, size, restype = x.unpack("V V V V")
36
+ id &= 0xfffff
37
+ @contained[id] = [offset, size, restype]
38
+ end
39
+ end
40
+
41
+ def has_res_id? id
42
+ @contained[id] != nil
43
+ end
44
+
45
+ def get_res_id id
46
+ offset, size, restype = @contained[id]
47
+ @io.seek(offset)
48
+ @io.e_read(size, "resource #{id} of type #{restype}")
49
+ end
50
+ end
51
+
52
+ class Key < NWN::Resources::Container
53
+
54
+ # An array of Bif objects contained in this key index.
55
+ # Not needed to access individual files, use Container#content instead.
56
+ attr_reader :bif
57
+
58
+ attr_reader :file_type
59
+ attr_reader :file_version
60
+ attr_reader :day_of_year
61
+ attr_reader :year
62
+
63
+ # Creates a new Key wrapper. The parameters exepected are an
64
+ # IO object pointing to the .key-file, and the base path in
65
+ # which your data/.bif files can be found. (This is usually your
66
+ # NWN directory, NOT the data/ directory).
67
+ def initialize io, data_path
68
+ super()
69
+
70
+ @root = data_path
71
+ @bif = []
72
+
73
+ @file_type, @file_version,
74
+ bif_count, key_count,
75
+ offset_to_file_table, offset_to_key_table,
76
+ @year, @day_of_year, reserved =
77
+ io.e_read(8 + (4 * 6) + 32, "header").unpack("A4 A4 VVVVVV a32")
78
+
79
+ io.seek(offset_to_file_table)
80
+ data = io.e_read(12 * bif_count, "bif data")
81
+
82
+ # Contains all bifs linked in this key
83
+ i = 0
84
+ @file_table = []
85
+ while (x = data[i, 12]) && x.size == 12
86
+ i += 12
87
+ size, name_offset, name_size, drives = x.unpack("VVvv")
88
+ io.seek(name_offset)
89
+ name = io.e_read(name_size, "name table").unpack("A*")[0]
90
+ name.gsub!("\\", "/")
91
+ name = File.expand_path(@root + "/" + name)
92
+
93
+ _io = File.new(name, "r")
94
+ @bif << Bif.new(self, _io)
95
+
96
+ @file_table << [size, name, drives]
97
+ end
98
+
99
+ @key_table = {}
100
+ io.seek(offset_to_key_table)
101
+ data = io.e_read(22 * key_count, "key table")
102
+ i = 0
103
+ while (x = data[i, 22]) && x.size == 22
104
+ i += 22
105
+ resref, res_type, res_id = x.unpack("A16 v V")
106
+ @key_table[res_id] = [resref, res_type]
107
+ end
108
+
109
+ @fn_to_co = {}
110
+ @key_table.each {|res_id, (resref, res_type)|
111
+ bif_index = res_id >> 20
112
+ bif = @bif[bif_index]
113
+ id = res_id & 0xfffff
114
+ bif.contained[id] or fail "#{bif} does not have #{id}"
115
+ ofs, sz, _rt = bif.contained[id]
116
+ o = NWN::Resources::ContentObject.new(resref, res_type, bif.io, ofs, sz)
117
+ if @fn_to_co[o.filename] && @fn_to_co[o.filename][2] < bif_index
118
+ oo, biff = @fn_to_co[o.filename]
119
+ NWN.log_debug "#{o.filename} in #{biff.io.inspect} shadowed by file of same name in #{bif.io.inspect}"
120
+ @content.delete(oo)
121
+ end
122
+ @fn_to_co[o.filename] = [o, bif, bif_index]
123
+ @content << o
124
+ }
125
+ end
126
+ end
127
+
128
+ # Get the ContentObject pointing to the given filename.
129
+ # Raises ENOENT if not mapped.
130
+ def get_content_object filename
131
+ filename = filename.downcase
132
+ ret, bif = @fn_to_co[filename]
133
+ raise Errno::ENOENT,
134
+ "No ContentObject with the given filename #{filename.inspect} found." unless
135
+ ret
136
+ ret
137
+ end
138
+
139
+ def filenames
140
+ @fn_to_co.indices
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,67 @@
1
+ module NWN::Gff::Kivinen
2
+ def self.load io
3
+ raise NotImplementedError, "Reading kivinen not supported"
4
+ end
5
+
6
+ def self.dump struct, io
7
+ ret = ""
8
+ kivinen_format struct, $options[:types], nil, nil do |l,v|
9
+ ret += "%s:\t%s\n" % [l, v]
10
+ end
11
+ io.puts ret
12
+ end
13
+
14
+ # Parses +s+ as an arbitary GFF object and yields for each field found,
15
+ # with the proper prefix.
16
+ #
17
+ # [+struct+] The root-struct to dump
18
+ # [+prefix+] Supply a prefix to add to the output.
19
+ # [+types_too+] Yield type definitions as well (gffprint.pl -t).
20
+ # [+add_prefix+] Add a prefix <tt>(unknown type)</tt> of no type information can be derived from the input.
21
+ # [+file_type+] File type override. If non-null, add a global struct header with the given file type (useful for passing to gffencode.pl)
22
+ # [+struct_id+] Provide a struct_id override (if printing a struct).
23
+ def self.kivinen_format struct, types_too = false, add_prefix = true, file_type = nil, struct_id = nil, &block
24
+
25
+ if types_too
26
+ yield("/", "")
27
+
28
+ ftype = file_type ? file_type : struct.data_type
29
+ yield("/ ____file_type", ftype) if ftype
30
+ yield("/ ____file_version", struct.data_version) if struct.data_version
31
+
32
+ yield("/ ____struct_type", struct.struct_id)
33
+ end
34
+
35
+ struct.each_by_flat_path {|path, field|
36
+ case field
37
+ when String
38
+ yield(path, field)
39
+
40
+ when NWN::Gff::Struct
41
+ yield(path + "/", path)
42
+ yield(path + "/ ____struct_type", field.struct_id)
43
+
44
+ when NWN::Gff::Field
45
+
46
+ case field.field_type
47
+ when :list
48
+ when :struct
49
+ yield(path + "/", path)
50
+ yield(path + "/ ____struct_type", field.field_value.struct_id)
51
+ when :cexolocstr
52
+ else
53
+ yield(path, field.field_value)
54
+ end
55
+
56
+ yield(path + ". ____string_ref",field.str_ref) if
57
+ field.has_str_ref? || field.field_type == :cexolocstr
58
+
59
+ yield(path + ". ____type", NWN::Gff::Types.index(field.field_type)) if
60
+ types_too
61
+
62
+ end
63
+ }
64
+ end
65
+ end
66
+
67
+ NWN::Gff.register_format_handler :kivinen, /^k(ivinen)?$/, NWN::Gff::Kivinen, false, true
data/lib/nwn/res.rb CHANGED
@@ -61,18 +61,18 @@ module NWN
61
61
 
62
62
  # Wraps n ContentObjects; a baseclass for erf/key encapsulation.
63
63
  class Container
64
+
65
+ # An array of all ContentObjects indexed by this Container.
64
66
  attr_reader :content
65
67
 
66
68
  def initialize
67
69
  @content = []
68
70
  end
69
71
 
72
+ # Returns true if the given filename is contained herein.
73
+ # Case-insensitive.
70
74
  def has?(filename)
71
- base = File.basename(filename)
72
- @content.each {|f|
73
- return true if f.filename.downcase == base.downcase
74
- }
75
- return false
75
+ filenames.index(filename.downcase) != nil
76
76
  end
77
77
 
78
78
  # Add a content object giving a +filename+ and a optional
@@ -86,17 +86,18 @@ module NWN
86
86
  @content << o
87
87
  end
88
88
 
89
- # Returns a list of filenames
89
+ # Returns a list of filenames, all lowercase.
90
90
  def filenames
91
- @content.map {|x| x.filename }
91
+ @content.map {|x| x.filename.downcase }
92
92
  end
93
93
 
94
94
  # Get the ContentObject pointing to the given filename.
95
95
  # Raises ENOENT if not mapped.
96
96
  def get_content_object filename
97
- ret = @content.select {|x| filename.downcase == x.filename }
97
+ filename = filename.downcase
98
+ ret = @content.select {|x| filename == x.filename }
98
99
  raise Errno::ENOENT,
99
- "No ContentObject with the given filename found." if
100
+ "No ContentObject with the given filename #{filename.inspect} found." if
100
101
  ret.size == 0
101
102
  ret[0]
102
103
  end
@@ -104,7 +105,7 @@ module NWN
104
105
  # Get the contents of the given filename.
105
106
  # Raises ENOENT if not mapped.
106
107
  def get filename
107
- get_content_object(filename.downcase).get
108
+ get_content_object(filename).get
108
109
  end
109
110
  end
110
111
 
@@ -115,7 +116,10 @@ module NWN
115
116
  super()
116
117
  @path = path
117
118
  Dir[path + "/*.*"].each {|x|
118
- add_file x
119
+ begin add_file x
120
+ rescue ArgumentError => e
121
+ NWN.log_debug e.to_s
122
+ end
119
123
  }
120
124
  end
121
125
  end
@@ -138,7 +142,7 @@ module NWN
138
142
  con.has?(filename) or next
139
143
  return con.get_content_object(filename)
140
144
  }
141
- raise Errno::ENOENT, "No ContentObject with the given filename found."
145
+ raise Errno::ENOENT, "No ContentObject with the given filename #{filename.inspect} found."
142
146
  end
143
147
 
144
148
  # Get the contents of the given filename.
data/lib/nwn/settings.rb CHANGED
@@ -1,4 +1,9 @@
1
+ require 'iconv'
2
+
1
3
  module NWN
4
+ SETTING_DEFAULT_VALUES = {
5
+ 'NWN_LIB_IN_ENCODING' => 'ISO-8859-1'
6
+ }
2
7
 
3
8
  # This writes a internal warnings and debug messages to stderr.
4
9
  #
@@ -28,9 +33,12 @@ module NWN
28
33
  ENV[name] = value.to_s if value != :_invalid_
29
34
  ret
30
35
  else
31
- ENV[name] == "0" ? false : ENV[name]
36
+ ENV[name] == "0" ? false : (ENV[name] || SETTING_DEFAULT_VALUES[name])
32
37
  end
33
38
  end
39
+
40
+ IconvGffToNative = proc { Iconv.new('utf-8', NWN.setting(:in_encoding)) }
41
+ IconvNativeToGff = proc { Iconv.new(NWN.setting(:in_encoding), 'utf-8') }
34
42
  end
35
43
 
36
44
  NWN::TwoDA::Cache.setup NWN.setting("2da_location") if
@@ -1,8 +1,20 @@
1
1
  # This file contains all YAML-specific loading and dumping code.
2
2
  require 'yaml'
3
3
 
4
- # See http://www.taguri.org/ for the exact meaning of this.
5
- NWN::YAML_DOMAIN = "nwn-lib.elv.es,2008-12"
4
+ class NWN::Gff::YAML
5
+ # These field types can never be inlined in YAML.
6
+ NonInlineableFields = [:struct, :list, :cexolocstr]
7
+
8
+ # See http://www.taguri.org/ for the exact meaning of this.
9
+ Domain = "nwn-lib.elv.es,2008-12"
10
+
11
+ def self.load io
12
+ YAML.load(io)
13
+ end
14
+ def self.dump data, io
15
+ io.puts data.to_yaml
16
+ end
17
+ end
6
18
 
7
19
  #:stopdoc:
8
20
  class Array
@@ -34,7 +46,7 @@ end
34
46
 
35
47
  module NWN::Gff::Struct
36
48
  def to_yaml_type
37
- "!#{NWN::YAML_DOMAIN}/struct"
49
+ "!#{NWN::Gff::YAML::Domain}/struct"
38
50
  end
39
51
 
40
52
  def to_yaml(opts = {})
@@ -43,7 +55,7 @@ module NWN::Gff::Struct
43
55
  # Inline certain structs that are small enough.
44
56
  map.style = :inline if self.size <= 1 &&
45
57
  self.values.select {|x|
46
- NWN::Gff::YAMLNonInlineableFields.index(x['type'])
58
+ NWN::Gff::YAML::NonInlineableFields.index(x['type'])
47
59
  }.size == 0
48
60
 
49
61
  map.add('__' + 'data_type', @data_type) if @data_type
@@ -63,7 +75,7 @@ module NWN::Gff::Field
63
75
  def to_yaml(opts = {})
64
76
  YAML::quick_emit(nil, opts) do |out|
65
77
  out.map(taguri, to_yaml_style) do |map|
66
- map.style = :inline unless NWN::Gff::YAMLNonInlineableFields.index(self['type'])
78
+ map.style = :inline unless NWN::Gff::YAML::NonInlineableFields.index(self['type'])
67
79
  map.add('type', self['type'])
68
80
  map.add('str_ref', self['str_ref']) if has_str_ref?
69
81
  map.add('value', self['value'])
@@ -73,7 +85,7 @@ module NWN::Gff::Field
73
85
  end
74
86
 
75
87
  # This parses the struct and extends all fields with their proper type.
76
- YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
88
+ YAML.add_domain_type(NWN::Gff::YAML::Domain,'struct') {|t,hash|
77
89
  struct = {}
78
90
  struct.extend(NWN::Gff::Struct)
79
91
 
@@ -101,3 +113,5 @@ YAML.add_domain_type(NWN::YAML_DOMAIN,'struct') {|t,hash|
101
113
 
102
114
  struct
103
115
  }
116
+
117
+ NWN::Gff.register_format_handler :yaml, /^(y|yml|yaml)$/, NWN::Gff::YAML
data/spec/bin_gff_spec.rb CHANGED
@@ -3,10 +3,10 @@ require File.join(File.dirname(__FILE__), 'spec_helper')
3
3
  describe "nwn-gff" do
4
4
  it_should_behave_like "bin helper"
5
5
 
6
- NWN::Gff::FileFormats.each do |in_format|
6
+ NWN::Gff::InputFormats.each do |in_format, handler|
7
7
  inf = in_format.to_s
8
8
 
9
- NWN::Gff::FileFormats.each do |out_format|
9
+ NWN::Gff::OutputFormats.each do |out_format, handler|
10
10
  otf = out_format.to_s
11
11
 
12
12
  it "converts #{inf} to #{otf}" do
data/spec/erf_spec.rb CHANGED
@@ -30,6 +30,13 @@ describe "Erf::Erf", :shared => true do
30
30
  wellformed_verify @erf
31
31
  end
32
32
 
33
+ it "sets the correct default parameters" do
34
+ t = Erf::Erf.new
35
+ t.year.should == Time.now.year - 1900
36
+ t.day_of_year.should == Time.now.yday
37
+ t.content.size.should == 0
38
+ end
39
+
33
40
  it "reproduces correct ERF binary data" do
34
41
  t = Erf::Erf.new(StringIO.new @erf)
35
42
  io = StringIO.new
data/spec/key_spec.rb ADDED
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe "Key::Key", :shared => true do
4
+ def wellformed_verify binary
5
+ t = Key::Key.new(StringIO.new(binary), Dir.tmpdir)
6
+
7
+ t.file_type.should == "KEY"
8
+ t.file_version.should == "V1"
9
+ t.content.size.should == 2
10
+ t.content[0].resref.should == "abcdef"
11
+ t.content[1].resref.should == "123456"
12
+ t.content[0].get.should == "abcdefghij"
13
+ t.content[1].get.should == "0123456789"
14
+ end
15
+
16
+ it "should work" do
17
+ wellformed_verify @key
18
+ end
19
+
20
+ before do
21
+ @bif0 = File.join(Dir.tmpdir, "bif0.bif")
22
+ File.open(@bif0, "w") do |f|
23
+ f.write(WELLFORMED_BIF_0)
24
+ end
25
+ end
26
+
27
+ after do
28
+ File.unlink(@bif0)
29
+ end
30
+ end
31
+
32
+ describe "Key V1.0" do
33
+ before do
34
+ @key = WELLFORMED_KEY.dup
35
+ end
36
+
37
+ it_should_behave_like "Key::Key"
38
+ end
data/spec/spec_helper.rb CHANGED
@@ -92,6 +92,36 @@ WELLFORMED_TLK = ([
92
92
  "1", "22", "333", "4444"
93
93
  ].join("")).freeze
94
94
 
95
+ WELLFORMED_BIF_0 = ([
96
+ "BIFF", "V1",
97
+ var_res_count = 2,
98
+ fix_res_count = 0,
99
+ var_table_offset = 20
100
+ ].pack("a4 a4 V V V") + [
101
+ id0 = 124, var_table_offset + (16 * var_res_count), size0 = 10, type0 = 0,
102
+ id1 = 125, var_table_offset + (16 * var_res_count) + size0, size1 = 10, type1 = 0,
103
+ ].pack("VVVV VVVV") + [
104
+ "abcdefghij", "0123456789"
105
+ ].pack("a* a*")
106
+ ).freeze
107
+
108
+ WELLFORMED_KEY = ([
109
+ "KEY", "V1",
110
+ bif_count = 1, key_count = 2,
111
+ offset_to_file_table = 8 + (4 * 6) + 32,
112
+ offset_to_key_table = offset_to_file_table + bif_count * 12 + 8,
113
+ 100, 126, ""
114
+ ].pack("a4 a4 VVVVVV a32") + [ # file table containing bifs
115
+ bifsize = WELLFORMED_BIF_0.size, bifname0offset = offset_to_file_table + 12, fnsize = 8, drives = 0,
116
+ ].pack("VVvv") + [ #filename table
117
+ "bif0.bif"
118
+ ].pack("a*") + [ # key table
119
+ "abcdef", 0, 124,
120
+ "123456", 0, 125
121
+ ].pack("a16 v V a16 v V")
122
+ ).freeze
123
+
124
+
95
125
  TWODA_WELLFORMED = <<-EOT
96
126
  2DA V2.0
97
127
 
@@ -172,7 +202,7 @@ describe "bin helper", :shared => true do
172
202
  begin
173
203
  Dir.chdir(@tmp)
174
204
  Open3.popen3(
175
- "ruby", "-I#{incl}",
205
+ "ruby", "-rubygems", "-I#{incl}",
176
206
  binary,
177
207
  *va
178
208
  ) do |i,o,e|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nwn-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.9
4
+ version: 0.4.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard Stoeckner
@@ -9,10 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-19 00:00:00 +02:00
12
+ date: 2009-11-15 00:00:00 +01:00
13
13
  default_executable:
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.9
24
+ version:
16
25
  description: a ruby library for accessing Neverwinter Nights resource files
17
26
  email: elven@swordcoast.net
18
27
  executables:
@@ -36,49 +45,50 @@ files:
36
45
  - CHANGELOG
37
46
  - README
38
47
  - Rakefile
39
- - bin/nwn-dsl
40
48
  - bin/nwn-gff
41
- - bin/nwn-irb
49
+ - bin/nwn-dsl
42
50
  - bin/nwn-erf
43
- - spec/wellformed_gff.bic
51
+ - bin/nwn-irb
52
+ - spec/bin_dsl_spec.rb
44
53
  - spec/gff_spec.rb
45
- - spec/res_spec.rb
46
- - spec/spec.opts
47
- - spec/erf_spec.rb
54
+ - spec/key_spec.rb
55
+ - spec/bin_gff_spec.rb
56
+ - spec/bin_erf_spec.rb
48
57
  - spec/field_spec.rb
49
58
  - spec/cexolocstr_spec.rb
59
+ - spec/erf_spec.rb
50
60
  - spec/struct_spec.rb
51
- - spec/spec_helper.rb
61
+ - spec/res_spec.rb
52
62
  - spec/tlk_spec.rb
53
- - spec/bin_dsl_spec.rb
54
- - spec/bin_gff_spec.rb
55
- - spec/rcov.opts
56
- - spec/bin_erf_spec.rb
57
63
  - spec/twoda_spec.rb
58
- - lib/nwn/scripting.rb
59
- - lib/nwn/yaml.rb
60
- - lib/nwn/twoda.rb
64
+ - spec/spec_helper.rb
65
+ - spec/wellformed_gff.bic
61
66
  - lib/nwn/erf.rb
62
- - lib/nwn/settings.rb
63
- - lib/nwn/gff.rb
64
- - lib/nwn/tlk.rb
67
+ - lib/nwn/json_support.rb
65
68
  - lib/nwn/io.rb
66
- - lib/nwn/res.rb
67
- - lib/nwn/kivinen.rb
69
+ - lib/nwn/settings.rb
70
+ - lib/nwn/key.rb
68
71
  - lib/nwn/all.rb
69
- - lib/nwn/gff/field.rb
70
- - lib/nwn/gff/reader.rb
71
- - lib/nwn/gff/cexolocstr.rb
72
+ - lib/nwn/res.rb
73
+ - lib/nwn/twoda.rb
74
+ - lib/nwn/tlk.rb
75
+ - lib/nwn/gff.rb
76
+ - lib/nwn/yaml_support.rb
77
+ - lib/nwn/scripting.rb
78
+ - lib/nwn/kivinen_support.rb
79
+ - lib/nwn/gff/writer.rb
72
80
  - lib/nwn/gff/struct.rb
73
81
  - lib/nwn/gff/list.rb
74
- - lib/nwn/gff/writer.rb
82
+ - lib/nwn/gff/reader.rb
83
+ - lib/nwn/gff/cexolocstr.rb
84
+ - lib/nwn/gff/field.rb
75
85
  - tools/verify.sh
76
86
  - tools/migrate_03x_to_04x.sh
77
87
  - scripts/truncate_floats.rb
78
- - scripts/reformat_2da
79
88
  - scripts/clean_locstrs.rb
80
- - scripts/extract_all_items.rb
81
89
  - scripts/debug_check_objid.rb
90
+ - scripts/extract_all_items.rb
91
+ - scripts/reformat_2da
82
92
  - BINARIES
83
93
  - HOWTO
84
94
  - SCRIPTING
@@ -116,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
126
  requirements: []
117
127
 
118
128
  rubyforge_project: nwn-lib
119
- rubygems_version: 1.3.4
129
+ rubygems_version: 1.3.5
120
130
  signing_key:
121
131
  specification_version: 3
122
132
  summary: a ruby library for accessing Neverwinter Nights resource files
data/lib/nwn/kivinen.rb DELETED
@@ -1,55 +0,0 @@
1
- module NWN::Gff::Struct
2
-
3
- # yield (key, value) for each element, recursing into substructs.
4
-
5
- # Parses +s+ as an arbitary GFF object and yields for each field found,
6
- # with the proper prefix.
7
- #
8
- # [+prefix+] Supply a prefix to add to the output.
9
- # [+types_too+] Yield type definitions as well (gffprint.pl -t).
10
- # [+add_prefix+] Add a prefix <tt>(unknown type)</tt> of no type information can be derived from the input.
11
- # [+file_type+] File type override. If non-null, add a global struct header with the given file type (useful for passing to gffencode.pl)
12
- # [+struct_id+] Provide a struct_id override (if printing a struct).
13
- def kivinen_format types_too = false, add_prefix = true, file_type = nil, struct_id = nil, &block
14
-
15
- if types_too
16
- yield("/", "")
17
-
18
- ftype = file_type ? file_type : self.data_type
19
- yield("/ ____file_type", ftype) if ftype
20
- yield("/ ____file_version", self.data_version) if self.data_version
21
-
22
- yield("/ ____struct_type", self.struct_id)
23
- end
24
-
25
- self.each_by_flat_path {|path, field|
26
- case field
27
- when String
28
- yield(path, field)
29
-
30
- when NWN::Gff::Struct
31
- yield(path + "/", path)
32
- yield(path + "/ ____struct_type", field.struct_id)
33
-
34
- when NWN::Gff::Field
35
-
36
- case field.field_type
37
- when :list
38
- when :struct
39
- yield(path + "/", path)
40
- yield(path + "/ ____struct_type", field.field_value.struct_id)
41
- when :cexolocstr
42
- else
43
- yield(path, field.field_value)
44
- end
45
-
46
- yield(path + ". ____string_ref",field.str_ref) if
47
- field.has_str_ref? || field.field_type == :cexolocstr
48
-
49
- yield(path + ". ____type", NWN::Gff::Types.index(field.field_type)) if
50
- types_too
51
-
52
- end
53
- }
54
- end
55
- end
data/spec/rcov.opts DELETED
File without changes
data/spec/spec.opts DELETED
File without changes