nwn-lib 0.4.7 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
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