nwn-lib 0.3.2 → 0.3.3

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/CHANGELOG CHANGED
@@ -1,44 +1,77 @@
1
- === 0.3.2
2
-
3
- * Gff: fix reading some type fields raising an exception in rare conditions
4
- * Add NWN::Gff::Struct#set for easy label setting
5
-
6
- === 0.3.1
7
-
8
- * Bugfix release only
9
- * Gff: fix struct delegator bug not passing on blocks (yuk!)
10
-
11
- === 0.3.0
12
-
13
- * Binary: nwn-gff-import
14
- * Binary: nwn-gff-print supports -m, ruby marshalling
15
- * helper: NWN::Gff::Helpers.item_property
16
- * TwoDA: Cache, more compatibility to slightly broken 2da files
17
- * CExoLocString: now has its own proper class for a more convenient API
18
- * Gff::Struct: has changed its internal API (transparent to the outside)
19
-
20
- === 0.2.2
1
+ === 0.1
2
+ Bernhard Stoeckner <elven@swordcoast.net> (15):
3
+ Add proper struct support, fix some values
4
+ Suspected to be fully-working Gff::Reader
5
+ Add working rudimentary Gff::Writer
6
+ Add substruct support
7
+ Add untested support for complex datatypes
8
+ add gff_to_yaml.rb
9
+ Add COPYING, LICENCE, README, Rakefile, spec/
10
+ Update README
11
+ add nwn-gff-print.rb binary, update gff lib
12
+ rename nwn-gff-print.rb to nwn-gff-print
13
+ nwn-gff-print: allow proper printing of sub-structs/lists
14
+ Add proper get/set support for Gff, add Element validations
15
+ Rakefile/gem: add nwn-gff-print to binary list
16
+ Rename project to nwn-lib
17
+ Fix Writer method scope
21
18
 
22
- * Binary: nwn-gff-irb: interactive gff inspection/editing shell
23
- * Gff: Errors are now RuntimeErrors instead of Exceptions
24
- * Gff::Reader: properly read structures with no labels inside
25
- * Gff::Reader: void datatype support
19
+ === 0.2
20
+ Bernhard Stoeckner <elven@swordcoast.net> (6):
21
+ Fix stupid typo in Rakefile
22
+ Add a basic 2da parser
23
+ twoda: Read windows-linebreaks as well.
24
+ Twoda: add .to_2da
25
+ nwn-gff-print/Gff: kivinen_format is now a member of the Gff module and supports printing types
26
+ 0.2-rel, add CHANGELOG
26
27
 
27
28
  === 0.2.1
29
+ Bernhard Stoeckner <elven@swordcoast.net> (6):
30
+ TwoDA: Update API for new schema
31
+ Gff: minor documentation update
32
+ Gff/kivinen_print: be more compatible
33
+ Gff/kivinen_format: add filetype-override for custom headers, add documentation
34
+ Add cheatsheet
35
+ Version 0.2.1-rel
28
36
 
29
- * TwoDA allows creation of tables and proper writing, HAS NEW API. (sorry!)
30
- * NWN::Gff.kivinen_print takes more options, compatibility updates.
31
- * nwn-gff-print takes option --type: override file type, prints a custom header.
32
- * nwn-gff-print takes option -f: print full path. (formerly -k)
33
- * nwn-gff-print takes option --struct: override struct id
34
- * Added CHEATSHEET
37
+ === 0.3.0
38
+ Bernhard Stoeckner <elven@swordcoast.net> (16):
39
+ Gff::Reader: Fix reading structs with no subvalues
40
+ Gff::Reader: void datatype support
41
+ add nwn-gff-irb
42
+ Gff: raise RuntimeError instead of generic Exceptions
43
+ Update CHEATSHEET for gff-irb
44
+ 0.2.2-rel
45
+ TwoDA: Do not parse empty lines
46
+ Add global, optional, 2da cache, add NWN::Gff.item_property helper
47
+ item_property: resolve unique partial matches
48
+ CExoLocString: more comfortable class to manage (API change)
49
+ compatibility fixes: allow non-empty-line-2das, be slightly more verbose
50
+ Gff::Struct is a delegator to Hash to allow seamless YAML marshalling
51
+ nwn-gff-print: -m: add support for native ruby marshalling
52
+ Binary: add nwn-gff-import
53
+ TwoDA: compatibility fixes (just warn on double ID assignments)
54
+ 0.3.0-rel
35
55
 
36
- === 0.2
56
+ === 0.3.1
57
+ Bernhard Stoeckner <elven@swordcoast.net> (2):
58
+ Gff: fix struct delegator bug not passing on blocks (yuk!)
59
+ 0.3.1-rel
37
60
 
38
- * Add TwoDA reading/writing support.
39
- * nwn-gff-print supports kivinen-style ____type printing.
61
+ === 0.3.2
62
+ Bernhard Stoeckner <elven@swordcoast.net> (3):
63
+ Add NWN::Gff::Struct#set for easy label setting
64
+ Gff: fix reading some type fields raising an exception in rare conditions
65
+ 0.3.2-rel
40
66
 
41
- === 0.1
67
+ === 0.3.3
68
+ Bernhard Stoeckner <elven@swordcoast.net> (8):
69
+ Gff#get_or_set: fix addressing exolocstr languages (/Description/0)
70
+ Helpers.item_property: ? expands the full list
71
+ fix private method `select' called while accessing ExoLocStr/Language
72
+ add support for sorted and cleaned-up yaml output
73
+ writer: void written properly
74
+ nwn-gff-print: add support for multiple files
75
+ nwn-gff-import: add support for multiple files
76
+ 0.3.3-rel
42
77
 
43
- * Add basic functionality for reading and writing arbitary gff files.
44
- * Binaries: nwn-gff-print for simple display of gff files.
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.3.2"
12
+ VERS = "0.3.3"
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', \
data/bin/nwn-gff-import CHANGED
@@ -6,49 +6,65 @@ require 'nwn/helpers'
6
6
  require 'yaml'
7
7
 
8
8
  format = nil
9
+ postfix = nil
10
+ outfile = nil
9
11
 
10
12
  OptionParser.new do |o|
11
- o.banner = "Usage: nwn-gff-import [options] file/- outfile/-"
13
+ o.banner = "Usage: nwn-gff-import [options] file/- [file, file, file]"
14
+
12
15
  o.on "-y", "--yaml", "Import as yaml" do
13
16
  format = :yaml
14
17
  end
15
18
  o.on "-m", "--marshal", "Import as native ruby marshal data" do
16
19
  format = :marshal
17
20
  end
21
+
22
+ o.on "-o", "--outfile F", "Write to outfile instead of stdout" do |out|
23
+ outfile = out
24
+ end
25
+
26
+ o.on "--postfix P", "Strip the given postfix from file and write to that instead of stdout (overrides -o)" do |p|
27
+ postfix = p
28
+ end
29
+
18
30
  end.parse!
19
31
 
20
- infile = ARGV.shift or begin
32
+ ARGV.size > 0 or begin
21
33
  $stderr.puts "Required argument: filename to read, or - for stdin (try -h)."
22
34
  exit 1
23
35
  end
24
- outfile = ARGV.shift or begin
25
- $stderr.puts "Required argument: filename to write, or - for stdout (try -h)."
26
- exit 1
27
- end
28
36
 
29
- if infile == "-"
30
- inbytes = $stdin.read
31
- else
37
+ ARGV.each do |infile|
38
+ data = nil
39
+
40
+ if !postfix && !outfile
41
+ outfile = $stdout
42
+ elsif postfix && outfile
43
+ outfile = outfile.gsub(/#{Regexp.escape(postfix)}$/, "")
44
+ outfile = File.new(outfile, "w")
45
+ elsif outfile && !postfix
46
+ outfile = File.new(outfile, "w")
47
+ end
48
+
49
+ infile = $stdin if infile == "-"
32
50
  inbytes = IO.read(infile)
33
- end
34
51
 
35
- data = nil
52
+ case format
53
+ when :yaml
54
+ data = YAML.load(inbytes)
55
+ when :marshal
56
+ data = Marshal.load(inbytes)
57
+ else
58
+ raise ArgumentError, "Unknown format; try -h"
59
+ end
60
+
61
+ raise ArgumentError, "Input stream is NOT a valid gff object" unless
62
+ data.is_a?(NWN::Gff::Gff)
63
+
64
+ outbytes = NWN::Gff::Writer.dump(data)
36
65
 
37
- case format
38
- when :yaml
39
- data = YAML.load(inbytes)
40
- when :marshal
41
- data = Marshal.load(inbytes)
42
- else
43
- raise ArgumentError, "Unknown format; try -h"
44
- end
45
66
 
46
- raise ArgumentError, "Input stream is NOT a valid gff object" unless
47
- data.is_a?(NWN::Gff::Gff)
67
+ outfile.write(outbytes)
48
68
 
49
- outbytes = NWN::Gff::Writer.dump(data)
50
- if outfile == "-"
51
- puts outbytes
52
- else
53
- File.open(outfile, "w") {|f| f.write(outbytes) }
69
+ outfile.close
54
70
  end
data/bin/nwn-gff-print CHANGED
@@ -10,25 +10,45 @@ types_too = false
10
10
  full = false
11
11
  file_type = nil
12
12
  struct_id = nil
13
+ path = nil
14
+ prefix = :none
15
+ postfix = nil
16
+ verbose = false
13
17
 
14
18
  OptionParser.new do |o|
15
- o.banner = "Usage: nwn-gff-print [options] file/- [path]"
19
+ o.banner = "Usage: nwn-gff-print [options] file/- [file, file, ..]"
20
+
16
21
  o.on "-y", "--yaml", "Dump as yaml" do
17
22
  format = :yaml
18
23
  end
24
+
19
25
  o.on "-k", "--kivinen", "Dump as kivinens dump format (like the perl tools)" do
20
26
  format = :kivinen
21
27
  end
22
- o.on "-f", "--kivinen-full-path", "Print the full path (implies -k)" do
28
+ o.on "--kivinen-full-path", "Print the full path (implies -k)" do
23
29
  format = :kivinen
24
30
  full = true
25
31
  end
32
+
33
+ o.on "-b", "--print-basename", "Prefix the file basename to the output" do |b|
34
+ prefix = :base
35
+ end
36
+ o.on "-f", "--print-filename", "Prefix the full filename to the output" do |b|
37
+ prefix = :full
38
+ end
39
+
40
+ o.on "-t", "--print-types", "Print types as well" do
41
+ types_too = true
42
+ end
43
+
26
44
  o.on "-m", "--marshal", "Native ruby marshalling. Warning: raw bytes" do
27
45
  format = :marshal
28
46
  end
29
- o.on "-t", "--types", "Dump types as well (only applies to -k, for now)" do
30
- types_too = true
47
+
48
+ o.on "--postfix P", "Write output to file postfixed with P instead of stdout" do |p|
49
+ postfix = p
31
50
  end
51
+
32
52
  o.on "--type filetype", "Override the file type (implies --struct 0xffffffff)" do |t|
33
53
  if t.size != 3
34
54
  $stderr.puts "Invalid type #{t} passwd."
@@ -37,44 +57,67 @@ OptionParser.new do |o|
37
57
  file_type = t.upcase + " "
38
58
  struct_id = 0xffffffff
39
59
  end
60
+
40
61
  o.on "--struct id", "Override struct id (as hex, please)" do |s|
41
62
  struct_id = s.hex
42
63
  end
64
+ o.on "-p=path", "--path path", "Only print the given path" do |p|
65
+ path = p
66
+ end
67
+
68
+ o.on "-v" "--verbose", "Be verbose" do
69
+ verbose = true
70
+ end
43
71
  end.parse!
44
72
 
45
- file = ARGV.shift or begin
46
- $stderr.puts "Required argument: filename to process, or - for stdin (try -h)."
73
+ ARGV.size > 0 or begin
74
+ $stderr.puts "Required argument: filename to read, or - for stdin (try -h)."
47
75
  exit 1
48
76
  end
49
77
 
50
- path = ARGV.shift
78
+ ARGV.each {|file|
51
79
 
52
- if file == "-"
53
- bytes = $stdin.read
54
- else
55
- bytes = IO.read(file)
56
- end
80
+ if file == "-"
81
+ bytes = $stdin.read
82
+ else
83
+ bytes = IO.read(file)
84
+ end
57
85
 
58
- g = NWN::Gff::Reader.read(bytes)
86
+ g = NWN::Gff::Reader.read(bytes)
59
87
 
60
- if path
61
- begin
62
- g = g[path]
63
- rescue Exception => e
64
- $stderr.puts "Error: " + e.to_s
65
- exit 1
88
+ if path
89
+ begin
90
+ g = g[path]
91
+ rescue Exception => e
92
+ $stderr.puts "Error: " + e.to_s
93
+ exit 1
94
+ end
66
95
  end
67
- end
68
96
 
69
- case format
70
- when :yaml
71
- y g
72
- when :kivinen
73
- NWN::Gff.kivinen_format g, "/", types_too, full, file_type, struct_id do |label, value|
74
- puts "%s:\t%s" % [label, value]
75
- end
76
- when :marshal
77
- puts Marshal.dump(g)
78
- else
79
- puts "Unknown format; try -h"
80
- end
97
+ my_prefix = case prefix
98
+ when :none
99
+ ""
100
+ when :base
101
+ File.basename(file) + ": "
102
+ when :full
103
+ File.expand_path(file) + ": "
104
+ end
105
+
106
+ write_to = postfix ? File.new(file + postfix, "w") : $stdout
107
+ $stderr.puts "Processing `#{file}`" if verbose
108
+ case format
109
+ when :yaml
110
+ write_to.puts g.to_yaml.split("\n").map {|ln| my_prefix + ln }.join("\n")
111
+ when :kivinen
112
+ NWN::Gff.kivinen_format g, my_prefix + "/", types_too, full, file_type, struct_id do |label, value|
113
+ write_to.puts "%s:\t%s" % [label, value]
114
+ end
115
+ when :marshal
116
+ write_to.print Marshal.dump(g)
117
+ else
118
+ $stderr.puts "Unknown format; try -h"
119
+ exit 1
120
+ end
121
+
122
+ write_to.close if postfix
123
+ }
data/lib/nwn/gff.rb CHANGED
@@ -87,6 +87,11 @@ module NWN
87
87
  s = NWN::Gff::Element.new(add_prefix ? "(unlabeled struct)" : "", :struct, s)
88
88
  end
89
89
 
90
+ if s.is_a?(String)
91
+ yield("(unlabeled string)" + prefix, s)
92
+ return
93
+ end
94
+
90
95
  case s.type
91
96
  when :struct
92
97
  yield(prefix + " ____struct_type", struct_id.nil? ? s.value.struct_id : struct_id) if types_too
@@ -101,7 +106,7 @@ module NWN
101
106
  s.value.each {|kk,vv|
102
107
  yield(prefix + s.label + "/" + kk.to_s, vv.gsub(/([\000-\037\177-\377%])/) {|v| "%" + v.unpack("H2")[0] })
103
108
  }
104
- yield(prefix + s.label + ". ____string_ref", s._str_ref)
109
+ yield(prefix + s.label + ". ____string_ref", s.str_ref)
105
110
 
106
111
  when :list
107
112
  s.value.each_with_index {|vv, idx|
@@ -138,6 +143,10 @@ class NWN::Gff::Gff
138
143
  attr_accessor :type
139
144
  attr_accessor :version
140
145
 
146
+ def to_yaml_properties
147
+ [ '@type', '@version', '@hash' ]
148
+ end
149
+
141
150
  # Create a new GFF object from the given +struct+.
142
151
  # This is normally not needed unless you are creating
143
152
  # GFF objects entirely from hand.
@@ -174,7 +183,7 @@ class NWN::Gff::Gff
174
183
  # overwrite an existing one with the same label.
175
184
  # gff['/PropertiesList[0]'] = 'Test'
176
185
  # This will raise an error (obviously)
177
- def get_or_set k, new_value = nil, new_type = nil, new_label = nil, new_str_ref = nil
186
+ def get_or_set k, new_value = nil, new_type = nil, new_label = nil, newstr_ref = nil
178
187
  h = self.root_struct
179
188
  path = []
180
189
  value_path = [h]
@@ -192,8 +201,7 @@ class NWN::Gff::Gff
192
201
  if h.is_a?(Gff::Element)
193
202
  case h.type
194
203
  when :cexolocstr
195
- current_value = h.value.select {|vx| vx.language.to_i == v.to_i}
196
- current_value = current_value[0] != nil ? current_value[0].text : ''
204
+ current_value = h.value.languages[v.to_i] || ''
197
205
 
198
206
  when :list
199
207
  raise GffPathInvalidError, "List-selector access not implemented yet."
@@ -259,10 +267,10 @@ class NWN::Gff::Gff
259
267
 
260
268
  end
261
269
 
262
- if !new_str_ref.nil?
270
+ if !newstr_ref.nil?
263
271
  # Set a new str_ref
264
272
  raise GffTypeError, "specified path is not a CExoStr" unless current_value.is_a?(Gff::CExoString)
265
- current_value._str_ref = new_str_ref.to_i
273
+ current_value.str_ref = new_str_ref.to_i
266
274
  end
267
275
 
268
276
  if !new_value.nil?
@@ -276,7 +284,7 @@ class NWN::Gff::Gff
276
284
 
277
285
  when String #means: cexolocstr assignment
278
286
  if value_path[-2].is_a?(Gff::Element) && value_path[-2].type == :cexolocstr
279
- value_path[-2].value.select{|xy| xy.language == path[-1].to_i }[0].text = new_value
287
+ value_path[-2].value[path[-1].to_i] = new_value
280
288
  else
281
289
  raise GffPathInvalidError, "Dont know how to set #{new_value.class} on #{path.inspect}."
282
290
  end
@@ -304,20 +312,36 @@ end
304
312
 
305
313
  # A Element wraps a GFF label->value pair,
306
314
  # provides a +.type+ and, optionally,
307
- # a +._str_ref+ for CExoLocStrings.
315
+ # a +.str_ref+ for CExoLocStrings.
308
316
  #
309
317
  # Fields:
310
318
  # [+label+] The label of this element, for reference.
311
319
  # [+type+] The type of this element. (See NWN::Gff)
312
320
  # [+value+] The value of this element.
313
321
  class NWN::Gff::Element
314
- attr_accessor :label, :type, :value
315
- attr_accessor :_str_ref
322
+ NonInline = [:struct, :list, :cexolocstr]
323
+
324
+ attr_accessor :label, :type, :value, :str_ref
325
+
326
+ def to_yaml_properties
327
+ [ '@label', '@type', '@value', '@str_ref' ]
328
+ end
316
329
 
317
330
  def initialize label = nil, type = nil, value = nil
318
331
  @label, @type, @value = label, type, value
319
332
  end
320
333
 
334
+ def to_yaml( opts = {} )
335
+ YAML::quick_emit( self, opts ) do |out|
336
+ out.map( taguri, to_yaml_style ) do |map|
337
+ map.style = :inline unless NonInline.index(self.type)
338
+ to_yaml_properties.sort.each do |m|
339
+ map.add( m[1..-1], instance_variable_get( m ) ) unless instance_variable_get( m ).nil?
340
+ end
341
+ end
342
+ end
343
+ end
344
+
321
345
  def validate path_prefix = "/"
322
346
  raise NWN::Gff::GffTypeError, "#{path_prefix}#{self.label}: New value #{self.value} is not compatible with the current type #{self.type}" unless
323
347
  self.class.valid_for?(self.value, self.type)
@@ -376,6 +400,10 @@ class NWN::Gff::Struct
376
400
  attr_accessor :struct_id
377
401
  attr_accessor :hash
378
402
 
403
+ def to_yaml_properties
404
+ [ '@struct_id', '@hash' ]
405
+ end
406
+
379
407
  def initialize
380
408
  @struct_id = 0
381
409
  @hash = {}
@@ -602,7 +630,7 @@ class NWN::Gff::Reader
602
630
  total_size, str_ref, str_count =
603
631
  @field_data[data_or_offset, 12].unpack("VVV")
604
632
  all = @field_data[data_or_offset + 12, total_size]
605
- field._str_ref = str_ref
633
+ field.str_ref = str_ref
606
634
 
607
635
  str_count.times {
608
636
  id, len = all.unpack("VV")
@@ -770,8 +798,6 @@ private
770
798
 
771
799
  # complex data types
772
800
  when :dword64, :int64, :double, :void
773
- $stderr.puts "Warning: complex datatypes dword64, int64, double and void are untested."
774
-
775
801
  fields_of_this_struct << add_data_field(v.type, k, @field_data.size)
776
802
  format = Formats[v.type]
777
803
  @field_data << case v.type
@@ -781,13 +807,11 @@ private
781
807
  v.value % (2**32)
782
808
  ].pack("II")
783
809
  when :void
784
- [ v.value.size, v.value ].pack("VH*")
810
+ [ v.value.size / 2, v.value ].pack("VH*")
785
811
  else
786
812
  [v.value].pack(format)
787
813
  end
788
814
 
789
- raise GffError, "unhandled complex datatype #{v.type}"
790
-
791
815
  when :struct
792
816
  raise GffError, "type = struct, but value not a hash" unless
793
817
  v.value.is_a?(Gff::Struct)
@@ -833,7 +857,7 @@ private
833
857
  }
834
858
  @field_data << [
835
859
  total_size,
836
- v._str_ref,
860
+ v.str_ref,
837
861
  v.value.size
838
862
  ].pack("VVV")
839
863
 
data/lib/nwn/helpers.rb CHANGED
@@ -68,6 +68,8 @@ module NWN
68
68
  def self.resolve_or_match_partial name_spec, list #:nodoc:
69
69
  name_spec = name_spec.downcase
70
70
 
71
+ raise ArgumentError, "?-expand: #{list.inspect}" if name_spec == '?'
72
+
71
73
  list.each {|l|
72
74
  return l if l.downcase == name_spec
73
75
  }
data/lib/nwn/yaml.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'yaml'
2
+
3
+ class Hash
4
+ # Replacing the to_yaml function so it'll serialize hashes sorted (by their keys)
5
+ # Original function is in /usr/lib/ruby/1.8/yaml/rubytypes.rb
6
+ def to_yaml( opts = {} )
7
+ YAML::quick_emit( object_id, opts ) do |out|
8
+ out.map( taguri, to_yaml_style ) do |map|
9
+ sort.each do |k, v|
10
+ map.add( k, v )
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: nwn-lib
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.2
7
- date: 2008-07-10 00:00:00 +02:00
6
+ version: 0.3.3
7
+ date: 2008-08-07 00:00:00 +02:00
8
8
  summary: a ruby library for accessing Neverwinter Nights resource files
9
9
  require_paths:
10
10
  - lib
@@ -39,6 +39,7 @@ files:
39
39
  - spec/spec.opts
40
40
  - spec/rcov.opts
41
41
  - lib/nwn
42
+ - lib/nwn/yaml.rb
42
43
  - lib/nwn/twoda.rb
43
44
  - lib/nwn/gff.rb
44
45
  - lib/nwn/helpers.rb