nwn-lib 0.4.7 → 0.4.8

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
@@ -204,6 +204,7 @@ Bernhard Stoeckner <elven@swordcoast.net> (26):
204
204
 
205
205
  Please browse the commit log for a full list of changes.
206
206
 
207
+ === 0.4.7
207
208
  Bernhard Stoeckner <elven@swordcoast.net> (25):
208
209
  bin/*: do not require rubygems explicitly
209
210
  remove obsolete Gff::Helpers module
@@ -238,3 +239,15 @@ Bernhard Stoeckner <elven@swordcoast.net> (25):
238
239
  putting wrong offsets for files created with nwn-erf.
239
240
 
240
241
  Please browse the commit log for a full list of changes.
242
+
243
+ === 0.4.8
244
+ Bernhard Stoeckner <elven@swordcoast.net> (6):
245
+ IO: add special e_read call to wrap size checks with custom exception msgs
246
+ NWN.setting: generic setting get/set mechanism
247
+ NWN.log_debug: messages always print unless explicitly turned off
248
+ Field :resref validate: warn when too long and not explicitly turned off
249
+ nwn-gff: fix reading from stdin throwing an exception
250
+ 0.4.8-rel
251
+
252
+ Another bugfix and compatibility release. This adds real NWN2 support
253
+ to gff reading, adds a few new SETTINGS, and adds proper IO reading.
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "nwn-lib"
12
- VERS = "0.4.7"
12
+ VERS = "0.4.8"
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/SETTINGS CHANGED
@@ -4,9 +4,33 @@ There are various environment variables you can configure to adjust various part
4
4
 
5
5
  Under linux, just add them to your shell environment (usually .bashrc), like so:
6
6
 
7
- export NWN_LIB_FILTER_EMPTY_EXOLOCSTR=1
7
+ export NWN_LIB_DEBUG=0
8
8
 
9
9
 
10
+ == NWN_LIB_DEBUG
11
+
12
+ nwn-lib prints, by default, various informational and warning messages to stderr.
13
+ This is a non-optimal solution, but needed to indicate various problems or misshapes with
14
+ resource files you are working with.
15
+
16
+ If you want to suppress them for some reason, set NWN_LIB_DEBUG to "0" or "off". Any
17
+ other value will indicate that you want to see the messages.
18
+
19
+ == NWN_LIB_RESREF16
20
+
21
+ Set this to "1" if you are sure that you are only working with NWN1 files. This will
22
+ make nwn-lib fail hard (Exception) on invalid resref lengths, and might save you some
23
+ time tracking things down.
24
+
25
+ Note that nwn-lib takes a parameter that can force a specific NWN version.
26
+
27
+ === NWN_LIB_RESREF32
28
+
29
+ Set this to "1" if you are working with NWN2 files and do not want to see the warnings
30
+ generated by too long resref values.
31
+
32
+ Note that nwn-lib takes a parameter that can force a specific NWN version.
33
+
10
34
  == NWN_LIB_2DA_LOCATION
11
35
 
12
36
  Set to a path containing all 2da files to initialize the 2da cache. This is needed for
data/bin/nwn-gff CHANGED
@@ -49,6 +49,15 @@ begin OptionParser.new do |o|
49
49
  $options[:backup] = b.nil? ? true : b
50
50
  end
51
51
 
52
+ o.on "-1", "--nwn1", "Allow 16 byte resrefs." do
53
+ ENV['NWN_LIB_RESREF32'] = nil
54
+ ENV['NWN_LIB_RESREF16'] = "1"
55
+ end
56
+ o.on "-2", "--nwn2", "Allow 32 byte resrefs. This is needed for NWN2 files." do
57
+ ENV['NWN_LIB_RESREF32'] = "1"
58
+ ENV['NWN_LIB_RESREF16'] = nil
59
+ end
60
+
52
61
  o.on "--force", "Force write even when the resulting data would be the same" do
53
62
  $options[:force] = true
54
63
  end
@@ -116,7 +125,7 @@ elsif :in == $options[:outformat]
116
125
  end
117
126
 
118
127
  vputs "Reading: #{$options[:infile]}"
119
- data_in = $options[:infile] == '-' ? $stdin.read : File.open($options[:infile], "rb")
128
+ data_in = $options[:infile] == '-' ? $stdin : File.open($options[:infile], "rb")
120
129
  data_in = NWN::Gff.read(data_in, $options[:informat])
121
130
 
122
131
  # verify that we read a GFF struct
data/lib/nwn/all.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'stringio'
2
+ require 'nwn/io'
1
3
  require 'nwn/twoda'
2
4
  require 'nwn/res'
3
5
  require 'nwn/gff'
data/lib/nwn/erf.rb CHANGED
@@ -57,17 +57,13 @@ module NWN
57
57
 
58
58
 
59
59
  def read_from io
60
- header = @io.read(160)
61
- raise IOError, "Cannot read header: Not a erf file?" unless
62
- header && header.size == 160
63
-
64
60
  @file_type, @file_version,
65
61
  locstr_count, locstr_size,
66
62
  entry_count,
67
63
  offset_to_locstr, offset_to_keys,
68
64
  offset_to_res,
69
- @year, @day_of_year, @description_str_ref = header.
70
- unpack("A4 A4 VV VV VV VV V a116")
65
+ @year, @day_of_year, @description_str_ref =
66
+ @io.read(160, "header").unpack("A4 A4 VV VV VV VV V a116")
71
67
 
72
68
  raise IOError, "Cannot read erf stream: invalid type #{@file_type.inspect}" unless
73
69
  NWN::Erf::ValidTypes.index(@file_type)
@@ -75,7 +71,7 @@ module NWN
75
71
  fnlen = filename_length @file_version
76
72
 
77
73
  @io.seek(offset_to_locstr)
78
- locstr = @io.read(locstr_size)
74
+ locstr = @io.e_read(locstr_size, "locstr_size")
79
75
 
80
76
  for lstr in 0...locstr_count do
81
77
  if locstr.nil? || locstr.size == 0
@@ -107,8 +103,7 @@ module NWN
107
103
 
108
104
  keylist_entry_size = fnlen + 4 + 2 + 2
109
105
  @io.seek(offset_to_keys)
110
- keylist = @io.read(keylist_entry_size * entry_count)
111
- raise IOError, "keylist too short" if keylist.size != keylist_entry_size * entry_count
106
+ keylist = @io.e_read(keylist_entry_size * entry_count, "keylist")
112
107
  keylist = keylist.unpack("A#{fnlen} V v v" * entry_count)
113
108
  keylist.each_slice(4) {|resref, res_id, res_type, unused|
114
109
  @content << NWN::Resources::ContentObject.new(resref, res_type, @io)
@@ -116,8 +111,7 @@ module NWN
116
111
 
117
112
  resourcelist_entry_size = 4 + 4
118
113
  @io.seek(offset_to_res)
119
- resourcelist = @io.read(resourcelist_entry_size * entry_count)
120
- raise IOError, "resource list too short" if resourcelist.size != resourcelist_entry_size * entry_count
114
+ resourcelist = @io.e_read(resourcelist_entry_size * entry_count, "reslist")
121
115
  resourcelist = resourcelist.unpack("I I" * entry_count)
122
116
  _index = -1
123
117
  resourcelist.each_slice(2) {|offset, size|
data/lib/nwn/gff/field.rb CHANGED
@@ -126,7 +126,16 @@ module NWN::Gff::Field
126
126
  value.is_a?(Float)
127
127
 
128
128
  when :resref
129
- value.is_a?(String) && (0..16).member?(value.size)
129
+ if !NWN.setting(:resref32) && value.is_a?(String) && value.size > 16
130
+ NWN.log_debug("Warning: :resref too long for NWN1, set env NWN_LIB_RESREF32=1 to turn off warning for NWN2.")
131
+ NWN.log_debug(" Value found: #{value.inspect}")
132
+ end
133
+
134
+ if NWN.setting(:resref16)
135
+ value.is_a?(String) && (0..16).member?(value.size)
136
+ else
137
+ value.is_a?(String) && (0..32).member?(value.size)
138
+ end
130
139
 
131
140
  when :cexostr
132
141
  value.is_a?(String)
@@ -20,10 +20,6 @@ class NWN::Gff::Reader
20
20
  private
21
21
 
22
22
  def read_all
23
- header = @io.read(160)
24
- raise IOError, "Cannot read header" unless header &&
25
- header.size == 160
26
-
27
23
  type, version,
28
24
  struct_offset, struct_count,
29
25
  field_offset, field_count,
@@ -31,7 +27,7 @@ class NWN::Gff::Reader
31
27
  field_data_offset, field_data_count,
32
28
  field_indices_offset, field_indices_count,
33
29
  list_indices_offset, list_indices_count =
34
- header.unpack("a4a4 VV VV VV VV VV VV")
30
+ @io.e_read(160, "header").unpack("a4a4 VV VV VV VV VV VV")
35
31
 
36
32
  raise GffError, "Unknown version #{version}; not a gff?" unless
37
33
  version == "V3.2"
@@ -44,32 +40,26 @@ class NWN::Gff::Reader
44
40
  label_len = label_count * 16
45
41
 
46
42
  @io.seek(struct_offset)
47
- @structs = @io.read(struct_len)
48
- raise IOError, "cannot read structs" unless @structs && @structs.size == struct_len
43
+ @structs = @io.e_read(struct_len, "structs")
49
44
  @structs = @structs.unpack("V*")
50
45
 
51
46
  @io.seek(field_offset)
52
- @fields = @io.read(field_len)
53
- raise IOError, "cannot read fields" unless @fields && @fields.size == field_len
47
+ @fields = @io.e_read(field_len, "fields")
54
48
  @fields = @fields.unpack("V*")
55
49
 
56
50
  @io.seek(label_offset)
57
- @labels = @io.read(label_len)
58
- raise IOError, "cannot read labels" unless @labels && @labels.size == label_len
51
+ @labels = @io.e_read(label_len, "labels")
59
52
  @labels = @labels.unpack("A16" * label_count)
60
53
 
61
54
  @io.seek(field_data_offset)
62
- @field_data = @io.read(field_data_count)
63
- raise IOError, "cannot read field_data" unless @field_data && @field_data.size == field_data_count
55
+ @field_data = @io.e_read(field_data_count, "field_data")
64
56
 
65
57
  @io.seek(field_indices_offset)
66
- @field_indices = @io.read(field_indices_count)
67
- raise IOError, "cannot read field_indices" unless @field_indices && @field_indices.size == field_indices_count
58
+ @field_indices = @io.e_read(field_indices_count, "field_indices")
68
59
  @field_indices = @field_indices.unpack("V*")
69
60
 
70
61
  @io.seek(list_indices_offset)
71
- @list_indices = @io.read(list_indices_count)
72
- raise IOError, "cannot read list_indices" unless @list_indices && @list_indices.size == list_indices_count
62
+ @list_indices = @io.e_read(list_indices_count, "list_indices")
73
63
  @list_indices = @list_indices.unpack("V*")
74
64
 
75
65
  @root_struct = read_struct 0, type.strip, version
data/lib/nwn/io.rb ADDED
@@ -0,0 +1,35 @@
1
+ # This is a loose adaption of readbytes.rb, but with more flexibility and
2
+ # StringIO support.
3
+
4
+ # MissingDataError is raised when IO#readbytes fails to read enough data.
5
+ class MissingDataError < IOError
6
+ def initialize(mesg, data) # :nodoc:
7
+ @data = data
8
+ super(mesg)
9
+ end
10
+
11
+ # The read portion of an IO#e_read attempt.
12
+ attr_reader :data
13
+ end
14
+
15
+
16
+ [IO, StringIO].each {|klass|
17
+ klass.class_eval do
18
+ # Reads exactly +n+ bytes.
19
+ #
20
+ # If the data read is nil an EOFError is raised.
21
+ #
22
+ # If the data read is too short a MissingDataError is raised and the read
23
+ # data is obtainable via its #data method.
24
+ def e_read(n, mesg = nil)
25
+ str = read(n)
26
+ if str == nil
27
+ raise EOFError, "End of file reached"
28
+ end
29
+ if str.size < n
30
+ raise MissingDataError.new("data truncated" + (mesg ? ": " + mesg : nil), str)
31
+ end
32
+ str
33
+ end
34
+ end
35
+ }
data/lib/nwn/res.rb CHANGED
@@ -42,11 +42,7 @@ module NWN
42
42
  def get
43
43
  if @io.respond_to?(:read)
44
44
  @io.seek(@offset ? @offset : 0)
45
- d = @io.read(self.size)
46
- raise IOError,
47
- "not enough data available while reading #{self.filename}" if
48
- d.size != self.size
49
- d
45
+ @io.e_read(self.size, "filename = #{filename}")
50
46
  else
51
47
  IO.read(@io)
52
48
  end
data/lib/nwn/settings.rb CHANGED
@@ -1,15 +1,37 @@
1
1
  module NWN
2
2
 
3
- # This writes a debug message to stderr if the environment
4
- # variable +NWN_LIB_DEBUG+ is set to non-nil or $DEBUG is
5
- # true (ruby -d).
3
+ # This writes a internal warnings and debug messages to stderr.
4
+ #
5
+ # Leaving this on is recommended, since it usually points to
6
+ # (fixable) errors in your resource files. You can turn this off
7
+ # anyways by setting the environment variable +NWN_LIB_DEBUG+
8
+ # to "0" or "off".
9
+ #
10
+ # Will return true when printed, false otherwise.
6
11
  def self.log_debug msg
7
- return false unless ENV['NWN_LIB_DEBUG'] || $DEBUG
8
- $stderr.puts "(nwn-lib debug) %s: %s" % [caller[0].to_s, msg]
12
+ # Do not print debug messages if explicitly turned off
13
+ return false if [false, "off"].index(setting(:debug))
14
+
15
+ pa = caller[0].to_s
16
+ pa = pa[(pa.size - 36) .. -1] if pa.size > 36
17
+ $stderr.puts "(nwn-lib) %s: %s" % [pa, msg]
9
18
  true
10
19
  end
11
- end
12
20
 
13
- if ENV['NWN_LIB_2DA_LOCATION'] && ENV['NWN_LIB_2DA_LOCATION'] != ""
14
- NWN::TwoDA::Cache.setup ENV['NWN_LIB_2DA_LOCATION']
21
+ # Get or set a ENV var setting.
22
+ # Returns false for "0" values.
23
+ # Returns the old value for new assignments.
24
+ def self.setting sym, value = :_invalid_
25
+ name = "NWN_LIB_#{sym.to_s.upcase}"
26
+ if value != :_invalid_
27
+ ret = ENV[name] == "0" ? false : ENV[name]
28
+ ENV[name] = value.to_s if value != :_invalid_
29
+ ret
30
+ else
31
+ ENV[name] == "0" ? false : ENV[name]
32
+ end
33
+ end
15
34
  end
35
+
36
+ NWN::TwoDA::Cache.setup NWN.setting("2da_location") if
37
+ NWN.setting("2da_location")
data/lib/nwn/tlk.rb CHANGED
@@ -35,7 +35,7 @@ module NWN
35
35
  # Read the header
36
36
  @file_type, @file_version, language_id,
37
37
  string_count, string_entries_offset =
38
- @io.read(HEADER_SIZE).unpack("A4 A4 I I I")
38
+ @io.e_read(HEADER_SIZE, "header").unpack("A4 A4 I I I")
39
39
 
40
40
  raise IOError, "The given IO does not describe a valid tlk table" unless
41
41
  @file_type == "TLK" && @file_version == "V3.0"
@@ -62,18 +62,14 @@ module NWN
62
62
  raise ArgumentError, "No such string ID: #{id.inspect}" if id > self.highest_id || id < 0
63
63
  seek_to = HEADER_SIZE + (id) * DATA_ELEMENT_SIZE
64
64
  @io.seek(seek_to)
65
- data = @io.read(DATA_ELEMENT_SIZE)
66
-
67
- raise IOError, "Cannot read TLK file, missing string header data." if !data || data.size != 40
65
+ data = @io.e_read(DATA_ELEMENT_SIZE, "tlk entry = #{id}")
68
66
 
69
67
  flags, sound_resref, v_variance, p_variance, offset,
70
68
  size, sound_length = data.unpack("I A16 I I I I f")
71
69
  flags = flags.to_i
72
70
 
73
71
  @io.seek(@entries_offset + offset)
74
- text = @io.read(size)
75
-
76
- raise IOError, "Cannot read TLK file, missing string text data." if !text || text.size != size
72
+ text = @io.e_read(size, "tlk entry = #{id}, offset = #{@entries_offset + offset}")
77
73
 
78
74
  text = flags & 0x1 > 0 ? text : ""
79
75
  sound = flags & 0x2 > 0 ? sound_resref : ""
data/lib/nwn/twoda.rb CHANGED
@@ -285,8 +285,8 @@ module NWN
285
285
  # Append an empty newline.
286
286
  ret << ""
287
287
 
288
- ret.join(case ENV['NWN_LIB_2DA_NEWLINE']
289
- when "0"
288
+ ret.join(case NWN.setting("2da_newline")
289
+ when "0", false
290
290
  "\r\n"
291
291
  when "1"
292
292
  "\n"
data/spec/erf_spec.rb CHANGED
@@ -41,13 +41,17 @@ describe "Erf::Erf", :shared => true do
41
41
  end
42
42
 
43
43
  it "reads ERF with locstr_size = 0 and locstr_count > 0" do
44
+ old_debug = NWN.setting(:debug, "0")
44
45
  @erf[12,4] = [0].pack("V")
45
46
  wellformed_verify @erf, false
47
+ NWN.setting(:debug, old_debug)
46
48
  end
47
49
 
48
50
  it "reads ERF with locstr_size > 0 and locstr_count = 0" do
51
+ old_debug = NWN.setting(:debug, "0")
49
52
  @erf[8,4] = [0].pack("V")
50
53
  wellformed_verify @erf, false
54
+ NWN.setting(:debug, old_debug)
51
55
  end
52
56
  end
53
57
 
data/spec/field_spec.rb CHANGED
@@ -13,9 +13,11 @@ describe "Gff::Field" do
13
13
  end
14
14
 
15
15
  it "rejects bad values for type '#{t.inspect}'" do
16
+ NWN.setting(:resref16, "1")
16
17
  invalid.each do |v|
17
18
  Gff::Field.valid_for?(v, t).should == false
18
19
  end
20
+ NWN.setting(:resref16, nil)
19
21
  end
20
22
  end
21
23
  end
data/spec/gff_spec.rb CHANGED
@@ -58,8 +58,9 @@ describe "Gff::*" do
58
58
  end
59
59
 
60
60
  it "fails on not enough data" do
61
- proc {wellformed_verify WELLFORMED_GFF[0 .. -2] }.should
62
- raise_error IOError, "cannot read list_indices"
61
+ proc {
62
+ wellformed_verify WELLFORMED_GFF[0 .. -2]
63
+ }.should raise_error IOError
63
64
  end
64
65
 
65
66
  end
data/spec/twoda_spec.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
3
  describe TwoDA::Table do
4
+ before do
5
+ NWN.setting(:debug, "0")
6
+ end
7
+ after do
8
+ NWN.setting(:debug, nil)
9
+ end
4
10
 
5
11
  it "parses wellformed files" do
6
12
  proc { subject.parse(TWODA_WELLFORMED) }.should_not raise_error ArgumentError
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.7
4
+ version: 0.4.8
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-05-26 00:00:00 +02:00
12
+ date: 2009-06-30 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -35,57 +35,58 @@ files:
35
35
  - CHANGELOG
36
36
  - README
37
37
  - Rakefile
38
- - bin/nwn-dsl
39
38
  - bin/nwn-gff
40
- - bin/nwn-irb
39
+ - bin/nwn-dsl
41
40
  - bin/nwn-erf
42
- - spec/wellformed_gff.bic
41
+ - bin/nwn-irb
42
+ - spec/bin_dsl_spec.rb
43
43
  - spec/gff_spec.rb
44
- - spec/res_spec.rb
45
- - spec/spec.opts
46
- - spec/erf_spec.rb
44
+ - spec/bin_gff_spec.rb
45
+ - spec/bin_erf_spec.rb
47
46
  - spec/field_spec.rb
48
47
  - spec/cexolocstr_spec.rb
48
+ - spec/erf_spec.rb
49
49
  - spec/struct_spec.rb
50
- - spec/spec_helper.rb
50
+ - spec/spec.opts
51
+ - spec/res_spec.rb
51
52
  - spec/tlk_spec.rb
52
- - spec/bin_dsl_spec.rb
53
- - spec/bin_gff_spec.rb
54
53
  - spec/rcov.opts
55
- - spec/bin_erf_spec.rb
56
54
  - spec/twoda_spec.rb
57
- - lib/nwn
58
- - lib/nwn/scripting.rb
59
- - lib/nwn/yaml.rb
60
- - lib/nwn/twoda.rb
55
+ - spec/spec_helper.rb
56
+ - spec/wellformed_gff.bic
61
57
  - lib/nwn/erf.rb
58
+ - lib/nwn/io.rb
62
59
  - lib/nwn/settings.rb
63
- - lib/nwn/gff.rb
64
- - lib/nwn/tlk.rb
60
+ - lib/nwn/yaml.rb
61
+ - lib/nwn/all.rb
65
62
  - lib/nwn/res.rb
63
+ - lib/nwn/twoda.rb
64
+ - lib/nwn/tlk.rb
65
+ - lib/nwn/gff.rb
66
66
  - lib/nwn/kivinen.rb
67
- - lib/nwn/all.rb
68
- - lib/nwn/gff
69
- - lib/nwn/gff/field.rb
70
- - lib/nwn/gff/reader.rb
71
- - lib/nwn/gff/cexolocstr.rb
67
+ - lib/nwn/scripting.rb
68
+ - lib/nwn/gff/api.rb
69
+ - lib/nwn/gff/writer.rb
72
70
  - lib/nwn/gff/struct.rb
73
71
  - lib/nwn/gff/list.rb
74
- - lib/nwn/gff/writer.rb
75
- - lib/nwn/gff/api.rb
72
+ - lib/nwn/gff/reader.rb
73
+ - lib/nwn/gff/cexolocstr.rb
74
+ - lib/nwn/gff/field.rb
76
75
  - tools/verify.sh
77
76
  - tools/migrate_03x_to_04x.sh
78
77
  - scripts/truncate_floats.rb
79
- - scripts/reformat_2da
80
78
  - scripts/clean_locstrs.rb
81
- - scripts/extract_all_items.rb
82
79
  - scripts/debug_check_objid.rb
80
+ - scripts/extract_all_items.rb
81
+ - scripts/reformat_2da
83
82
  - BINARIES
84
83
  - SCRIPTING
85
84
  - SETTINGS
86
85
  - CHEATSHEET
87
86
  has_rdoc: true
88
87
  homepage: http://nwn-lib.elv.es
88
+ licenses: []
89
+
89
90
  post_install_message:
90
91
  rdoc_options:
91
92
  - --quiet
@@ -114,9 +115,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
115
  requirements: []
115
116
 
116
117
  rubyforge_project: nwn-lib
117
- rubygems_version: 1.3.0
118
+ rubygems_version: 1.3.4
118
119
  signing_key:
119
- specification_version: 2
120
+ specification_version: 3
120
121
  summary: a ruby library for accessing Neverwinter Nights resource files
121
122
  test_files: []
122
123