nwn-lib 0.4.3 → 0.4.4

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
@@ -136,3 +136,14 @@ Bernhard Stoeckner <elven@swordcoast.net> (2):
136
136
  NWN::Erf: basic reading/writing library + tar-like binary
137
137
  add tlk.rb to nwn/all.rb
138
138
  0.4.3-rel
139
+
140
+ === 0.4.4
141
+ Bernhard Stoeckner (7):
142
+ bin/nwn-gff: guess outfile format based on extension
143
+ erf: do not fail on misaligned strings, print warning instead
144
+ bin/nwn-erf: compat mode with tar, options can be without dashes
145
+ API: Add some helpers for creating Gff elements
146
+ scripting: satisfy: return object as-is when no conditions are given
147
+ bin/nwn-erf: -vt: move column type before filename
148
+ erf: fix loctable reading breaking on more than one locstr
149
+ 0.4.4-rel
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.4.3"
12
+ VERS = "0.4.4"
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', \
@@ -10,6 +10,9 @@ $type = 'ERF'
10
10
  $allow_duplicates = false
11
11
  $descriptions = {}
12
12
 
13
+ # tar-compat mode: first argument is options if no dash is specified.
14
+ ARGV[0] = "-" + ARGV[0] if ARGV.size > 0 && ARGV[0][0] != ?-
15
+
13
16
  begin OptionParser.new do |o|
14
17
  o.banner = "Usage: nwn-erf <options> [FILEs] ..."
15
18
 
@@ -80,7 +83,6 @@ begin OptionParser.new do |o|
80
83
  end.parse!
81
84
  rescue => ee
82
85
  $stderr.puts ee.to_s
83
- $stderr.puts ee.backtrace.join("\n")
84
86
  exit 1
85
87
  end
86
88
 
@@ -105,15 +107,15 @@ case $action
105
107
  when :t
106
108
  input {|f|
107
109
  erf = NWN::Erf::Erf.new(f)
108
- $stderr.puts "# %-4s %14s %16s %-10s %s" % %w{type offset size date filename} if $verbose
110
+ $stderr.puts "# %14s %16s %-10s %-4s %s" % %w{offset size date type filename} if $verbose
109
111
  erf.content.each {|c|
110
112
  if !$verbose
111
113
  $stderr.puts "%s" % [c.filename]
112
114
  else
113
- $stderr.puts "%4d %16d %16d %10s %s" % [
114
- c.res_type, c.offset, c.size,
115
+ $stderr.puts "%16d %16d %10s %4d %s" % [
116
+ c.offset, c.size,
115
117
  Date.ordinal(1900 + erf.year, erf.day_of_year).strftime("%Y-%m-%d"),
116
- c.filename
118
+ c.res_type, c.filename
117
119
  ]
118
120
  end
119
121
  }
@@ -36,7 +36,7 @@ begin OptionParser.new do |o|
36
36
  end
37
37
  o.on "-k", "--outfile-format FORMAT", [:in, :none] + NWN::Gff::FileFormats,
38
38
  "Output format (#{([:none, :in] + NWN::Gff::FileFormats).join(', ')})",
39
- "(default: in - same as input)" do |f|
39
+ "(default: in when stdout, try to guess based on extension otherwise)" do |f|
40
40
  $options[:outformat] = f
41
41
  end
42
42
 
@@ -107,7 +107,13 @@ if :auto == $options[:informat]
107
107
  $options[:informat]
108
108
  end
109
109
 
110
- $options[:outformat] = $options[:informat] if :in == $options[:outformat]
110
+ if $options[:outfile] == "-"
111
+ $options[:outformat] = $options[:informat] if :in == $options[:outformat]
112
+ elsif :in == $options[:outformat]
113
+ $options[:outformat] = NWN::Gff.guess_file_format($options[:outfile])
114
+ fail "Cannot guess outfile format from filename, specify with -k." unless
115
+ $options[:outformat]
116
+ end
111
117
 
112
118
  vputs "Reading: #{$options[:infile]}"
113
119
  data_in = $options[:infile] == '-' ? $stdin.read : IO.read($options[:infile])
@@ -235,14 +235,16 @@ module NWN
235
235
  raise IOError, "Cannot read locstr list" unless
236
236
  locstr.size == locstr_size
237
237
 
238
- locstrs = locstr.unpack("V V/a*" * locstr_count)
239
- locstrs.each_slice(3) {|lid, strsz, str|
240
- raise IOError,
241
- "Cannot read localized strings table: string size not met (want: #{strsz}, got #{str.size})" if
242
- str.size != strsz
238
+ for lstr in 0...locstr_count do
239
+ lid, strsz = locstr.unpack("V V")
240
+ str = locstr.unpack("a#{strsz}")[0]
241
+ $stderr.puts "Expected string size does not match actual string size (want: #{strsz}, got #{str.size} of #{str.inspect})" if
242
+ strsz != str.size
243
243
  @localized_strings[lid] = str
244
- }
245
-
244
+ locstr = locstr[8 + str.size .. -1]
245
+ raise IOError, "locstr table does not contain enough entries (want: #{locstr_count}, got: #{lstr + 1})" if locstr.nil? &&
246
+ lstr + 1 < locstr_count
247
+ end
246
248
 
247
249
  keylist_entry_size = @filename_length + 4 + 2 + 2
248
250
  keylist = @io.read(keylist_entry_size * entry_count)
@@ -16,6 +16,14 @@ module NWN::Gff::Field
16
16
  # This is set internally by Gff::Reader on load.
17
17
  attr_accessor :parent
18
18
 
19
+ # Create a new NWN::Gff::Field
20
+ def self.new label, type, value
21
+ s = {}.extend(self)
22
+ s['label'], s['type'], s['value'] = label, type, value
23
+ s.extend_meta_classes
24
+ s
25
+ end
26
+
19
27
  def field_type
20
28
  self['type']
21
29
  end
@@ -1,2 +1,53 @@
1
1
  module NWN::Gff::List
2
+
3
+ # Add a new struct member to this list.
4
+ # You can either add an existing struct to this list
5
+ # (which will reparent it by setting .element), or specify
6
+ # a new struct with a block, or both:
7
+ #
8
+ # root = Gff::Struct.new 0xffffffff, "UTI", "V3.2"
9
+ # list = root.add_list 'test', []
10
+ # list.add_struct 1 do |l|
11
+ # l.add_byte 'inner_test', 5
12
+ # l.add_cexolocstr 'exolocstr', { 0 => 'Hello', 4 => 'Hallo' }
13
+ # end
14
+ # y root
15
+ #
16
+ # results in:
17
+ # --- !nwn-lib.elv.es,2008-12/struct
18
+ # __data_type: UTI
19
+ # __struct_id: 4294967295
20
+ # test:
21
+ # type: :list
22
+ # value:
23
+ # - !nwn-lib.elv.es,2008-12/struct
24
+ # __data_type: UTI/test
25
+ # __struct_id: 1
26
+ # exolocstr:
27
+ # type: :cexolocstr
28
+ # value:
29
+ # 0: Hello
30
+ # 4: Hallo
31
+ # inner_test: {type: :byte, value: 5}}
32
+ def add_struct struct_id_or_struct = 0, &block
33
+ struct = case struct_id_or_struct
34
+ when Integer
35
+ s = NWN::Gff::Struct.new
36
+ s.struct_id = struct_id_or_struct
37
+ s
38
+
39
+ when NWN::Gff::Struct
40
+ struct_id_or_struct
41
+
42
+ else
43
+ raise ArgumentError, "specify either a struct_id or an existing struct"
44
+ end
45
+
46
+ struct.element = self
47
+
48
+ yield(struct) if block_given?
49
+
50
+ self.v << struct
51
+ struct
52
+ end
2
53
  end
@@ -18,17 +18,68 @@ module NWN::Gff::Struct
18
18
  # The field this struct is value of.
19
19
  # It is most likely a Field of :list, or
20
20
  # :nil if it is the root struct.
21
- attr_accessor :element
21
+ # Setting this to a value detaches this struct from
22
+ # the old parent (though the old parent Field may still
23
+ # point to this object).
24
+ attr_reader :element
22
25
 
23
26
  # Returns the path to this struct (which is usually __data_type)
24
27
  def path
25
28
  @data_type.to_s
26
29
  end
27
30
 
31
+ def element= e #:nodoc:
32
+ @element = e
33
+ @data_type = self.element.parent.path + "/" + self.element.l
34
+ end
35
+
28
36
  # Dump this struct as GFF binary data.
29
37
  #
30
38
  # Optionally specify data_type and data_version
31
39
  def to_gff data_type = nil
32
40
  NWN::Gff::Writer.dump(self, data_type)
33
41
  end
42
+
43
+ # Create a new struct.
44
+ # Usually, you can leave out data_type and data_version for non-root structs,
45
+ # because that will be guess-inherited based on the existing associations.
46
+ def self.new struct_id = 0xffffffff, data_type = nil, data_version = nil
47
+ s = {}.extend(self)
48
+ s.struct_id = struct_id
49
+ s.data_type = data_type
50
+ s.data_version = data_version
51
+ s
52
+ end
53
+
54
+ # Create a new field.
55
+ # Alternatively, you can use the shorthand methods:
56
+ # add_#{type} - add_int, add_byte, ..
57
+ # For example:
58
+ # some_struct.add_field 'ID', :byte, 5
59
+ # is equivalent to:
60
+ # some_struct.add_byte 'ID', 5
61
+ def add_field label, type, value, &block
62
+ self[label] = NWN::Gff::Field.new(label, type, value)
63
+ self[label].parent = self
64
+ if block_given?
65
+ yield(self[label])
66
+ end
67
+ self[label]
68
+ end
69
+
70
+ #:nodoc:
71
+ def method_missing meth, *av, &block
72
+ if meth.to_s =~ /^add_(.+)$/
73
+ if NWN::Gff::Types.index($1.to_sym)
74
+ av.size == 2 or super
75
+ t = $1.to_sym
76
+ f = add_field(av[0], t, av[1], &block)
77
+ return f
78
+ else
79
+ super
80
+ end
81
+ end
82
+
83
+ super
84
+ end
34
85
  end
@@ -76,6 +76,9 @@ module NWN::Gff::Scripting
76
76
  #
77
77
  # Returns the object that satisfies the asked-for conditions,
78
78
  # or nil if none can be given.
79
+ #
80
+ # If only a filename/string is given and no further arguments,
81
+ # the read object will be returned as-is.
79
82
  def satisfy *what
80
83
  if $standalone
81
84
  fn = what.shift
@@ -95,6 +98,8 @@ module NWN::Gff::Scripting
95
98
  obj = self
96
99
  end
97
100
 
101
+ return obj if what.size == 1
102
+
98
103
  what.each {|w|
99
104
  case w
100
105
  when Class, Module
@@ -108,7 +113,6 @@ module NWN::Gff::Scripting
108
113
  return obj if obj.field_type.to_sdowncase == w.to_s.downcase
109
114
  end
110
115
  end
111
-
112
116
  }
113
117
 
114
118
  return nil
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.3
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard Stoeckner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-06 00:00:00 +01:00
12
+ date: 2009-03-09 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15