nwn-lib 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- data/BINARIES +1 -1
- data/CHANGELOG +39 -1
- data/CHEATSHEET +20 -6
- data/README +29 -12
- data/Rakefile +3 -3
- data/SETTINGS +3 -69
- data/bin/nwn-dsl +2 -7
- data/lib/nwn/all.rb +1 -0
- data/lib/nwn/erf.rb +19 -192
- data/lib/nwn/gff.rb +0 -1
- data/lib/nwn/gff/field.rb +53 -14
- data/lib/nwn/gff/reader.rb +2 -2
- data/lib/nwn/gff/struct.rb +27 -9
- data/lib/nwn/res.rb +275 -0
- data/lib/nwn/settings.rb +0 -4
- data/lib/nwn/tlk.rb +1 -1
- data/lib/nwn/twoda.rb +36 -17
- data/lib/nwn/yaml.rb +13 -198
- data/spec/cexolocstr_spec.rb +15 -0
- data/spec/erf_spec.rb +87 -0
- data/spec/field_spec.rb +21 -0
- data/spec/gff_spec.rb +22 -0
- data/spec/res_spec.rb +59 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/struct_spec.rb +61 -0
- data/spec/tlk_spec.rb +47 -0
- data/spec/twoda_spec.rb +146 -0
- data/spec/wellformed_gff.binary +0 -0
- metadata +13 -8
- data/DATA_STRUCTURES +0 -50
- data/TYPE_VALUE_INFERRING +0 -93
- data/data/gff-common-nwn1.yaml +0 -982
- data/lib/nwn/infer.rb +0 -125
data/BINARIES
CHANGED
@@ -43,6 +43,6 @@ Usage is simple: just pass all old .yml files to the script, it will convert the
|
|
43
43
|
in-place (read: make a backup!).
|
44
44
|
|
45
45
|
This uses nwn-gff-convert and nwn-gff, so all environment variables are taken into
|
46
|
-
consideration.
|
46
|
+
consideration.
|
47
47
|
|
48
48
|
Backup and testing is ADVISED!
|
data/CHANGELOG
CHANGED
@@ -164,4 +164,42 @@ Bernhard Stoeckner (14):
|
|
164
164
|
Scripting: ask: fix return value of hash and arrays
|
165
165
|
TwoDA: add disclaimer for Cache references
|
166
166
|
TwoDA: add Table#[], Table#[]=
|
167
|
-
|
167
|
+
0.4.5-rel
|
168
|
+
|
169
|
+
=== 0.4.6
|
170
|
+
Bernhard Stoeckner <elven@swordcoast.net> (26):
|
171
|
+
bin/nwn-dsl: always print backtraces
|
172
|
+
tests: add rspec stub for later test introduction
|
173
|
+
Field: complete valid_for?, add checks in readers, add rspec
|
174
|
+
Field: #path prints proper list indices
|
175
|
+
ResourceManager: generic implementation as per bioware docs
|
176
|
+
TwoDA: read 2da header with arbitary spaces between magic and version
|
177
|
+
TwoDA: make id mismatch parsing more robust
|
178
|
+
TwoDA: nwn does not fill in missing row IDs
|
179
|
+
TwoDA: fix typo preventing #to_2da with NWN_LIB_2DA_NEWLINE absent
|
180
|
+
TwoDA: only print to $stderr when -d/$DEBUG is set
|
181
|
+
TwoDA: do not raise error on misshaped ID column, add documentation
|
182
|
+
TwoDA: do not compact multiple nonquoted cells in last column
|
183
|
+
TwoDA: add specs
|
184
|
+
Erf: skip over lid and strz to read locstrs correctly
|
185
|
+
Erf: seek to offsets instead of depending on constants, handle IOErrors
|
186
|
+
Erf: add specs
|
187
|
+
Tlk: fix reading last strref in a tlk
|
188
|
+
Tlk: add specs
|
189
|
+
Cexolocstr: add specs
|
190
|
+
Struct: .new accepts a block
|
191
|
+
Struct: add specs
|
192
|
+
Gff: add specs
|
193
|
+
feature kill: remove type/value inferring, NWN_LIB_INFER_*
|
194
|
+
Revert "add env setting NWN_LIB_FILTER_EMPTY_EXOLOCSTR"
|
195
|
+
Rakefile/rdoc: use mislav-hanna if available
|
196
|
+
update all documentation to reflect current situation
|
197
|
+
0.4.6-rel
|
198
|
+
|
199
|
+
This release changes a few features; most prominent of all is the
|
200
|
+
infer mechanism - it is removed completely for sanity reasons.
|
201
|
+
|
202
|
+
Also, quite a few bugfixes found their way into this release, thanks
|
203
|
+
to the newly-added specs.
|
204
|
+
|
205
|
+
Please browse the commit log for a full list of changes.
|
data/CHEATSHEET
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
==== Convert all item files in the current directory to yaml and back
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
for x in *.uti; do
|
4
|
+
nwn-gff -i"$x" -o"$x.yml"
|
5
|
+
done
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
for x in *.uti.yml; do
|
8
|
+
nwn-gff -i"$x" -o"$(basename $x .yml)"
|
9
|
+
done
|
10
|
+
|
11
|
+
==== A Makefile that rebuilds only changed resources
|
12
|
+
|
13
|
+
This can be done with a GNU Makefile too, with the added benefit that
|
14
|
+
it will keep track of changes automagically and only rebuild those resources
|
15
|
+
that you have changed (saving you a lot of time).
|
16
|
+
|
17
|
+
yml = $(wildcard *.yml)
|
18
|
+
gff = $(basename $(yml))
|
19
|
+
|
20
|
+
all: $(gff)
|
21
|
+
|
22
|
+
% : %.yml
|
23
|
+
nwn-gff -i $< -o $@
|
data/README
CHANGED
@@ -4,36 +4,41 @@ This package provides a library for reading, changing, and writing common file f
|
|
4
4
|
|
5
5
|
They should work with NWN2 just as well, since the file format specifications did not change.
|
6
6
|
|
7
|
-
=== Upgrade from 0.3.6 to 0.4.x
|
8
7
|
|
9
|
-
|
10
|
-
I can't help you with your API bindings, but for your YAML dumps, a converter script has been provided (see BINARIES).
|
8
|
+
=== Features of nwn-lib
|
11
9
|
|
12
|
-
|
10
|
+
==== nwn-lib reads and writes the following file formats (hopefully bug-free!), both with an API and useful command-line tools:
|
13
11
|
|
14
|
-
|
12
|
+
* GFF 3.2 (are, git, gic, dlg, itp, ifo, jrl, fac, ssf, ut*, among others)
|
13
|
+
* ERF (mod, hak, erf, among others)
|
14
|
+
* 2DA V2.0
|
15
|
+
* TLK
|
15
16
|
|
16
|
-
|
17
|
+
==== nwn-lib can read and write the following representations of GFF data:
|
17
18
|
|
18
|
-
* a feature-complete parser and generator of valid GFF V3.2 data
|
19
|
-
* shell scripts and tools to simplify your life (see BINARIES)
|
20
19
|
* kivinen-style ("gffprint.pl") presentation of data
|
21
20
|
* yaml presentation of data
|
22
21
|
* ruby-native marshalling of gff data
|
22
|
+
|
23
|
+
==== Also in the box:
|
24
|
+
|
25
|
+
* shell scripts and tools to simplify your life (see BINARIES)
|
23
26
|
* extensive developer API
|
24
27
|
* a powerful get-out-of-my-way scripting system for data transformation (see SCRIPTING)
|
25
|
-
* guessing of field-types and -values for shorter plaintext data dumps (see TYPE_AND_VALUE_INFERRING)
|
26
28
|
|
27
|
-
Also in the box:
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
=== Upgrade from 0.3.6 to 0.4.x
|
31
|
+
|
32
|
+
With the release of 0.4.0, the API changed significantly. Previous yaml dumps made with 0.3.x are INCOMPATIBLE, and so are all scripts.
|
33
|
+
I can't help you with your API bindings, but for your YAML dumps, a converter script has been provided (see BINARIES).
|
34
|
+
|
31
35
|
|
32
36
|
=== Attention Unicode/UTF-users
|
33
37
|
|
34
38
|
ruby 1.8 does not support character sets natively, and as such nwn-gff-irb will <b>FAIL</b> to encode non-standard characters properly on non-latin1 shells.
|
35
39
|
This will be worked around in a future release until the release of ruby 1.9, which will provide native charset support.
|
36
40
|
|
41
|
+
|
37
42
|
=== Quickstart
|
38
43
|
|
39
44
|
To use it, simply install the gem (available on rubyforge):
|
@@ -45,4 +50,16 @@ And do the following in a script of your own devising:
|
|
45
50
|
require 'rubygems'
|
46
51
|
require 'nwn/all'
|
47
52
|
|
53
|
+
Also, Read BINARIES.
|
54
|
+
|
48
55
|
For nwn-lib scripts, see SCRIPTING.
|
56
|
+
|
57
|
+
For using the developer API, I suggest you start reading NWN::Gff::Struct.
|
58
|
+
|
59
|
+
=== Latest code & developer contact
|
60
|
+
|
61
|
+
The latest source is available through git[http://git.swordcoast.net/?p=nwn/nwn-lib.git;a=summary].
|
62
|
+
|
63
|
+
All stable releases are tagged properly.
|
64
|
+
|
65
|
+
You can reach me via email[mailto:elven@swordcoast.net].
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "rake"
|
2
2
|
require "rake/clean"
|
3
3
|
require "rake/gempackagetask"
|
4
|
-
require "rake/rdoctask"
|
4
|
+
require "hanna/rdoctask" rescue require "rake/rdoctask"
|
5
5
|
require "fileutils"
|
6
6
|
include FileUtils
|
7
7
|
|
@@ -9,13 +9,13 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "nwn-lib"
|
12
|
-
VERS = "0.4.
|
12
|
+
VERS = "0.4.6"
|
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', \
|
16
16
|
'--main', 'README']
|
17
17
|
|
18
|
-
DOCS = ["README", "BINARIES", "
|
18
|
+
DOCS = ["README", "BINARIES", "SCRIPTING", "SETTINGS", "CHEATSHEET", "CHANGELOG", "COPYING"]
|
19
19
|
|
20
20
|
Rake::RDocTask.new do |rdoc|
|
21
21
|
rdoc.rdoc_dir = "rdoc"
|
data/SETTINGS
CHANGED
@@ -1,82 +1,16 @@
|
|
1
1
|
There are various environment variables you can configure to adjust various parts of nwn-lib.
|
2
2
|
|
3
|
-
<b>All of them are optional!</b>
|
3
|
+
<b>All of them are optional, and, in fact, can waste your time!</b>
|
4
4
|
|
5
5
|
Under linux, just add them to your shell environment (usually .bashrc), like so:
|
6
6
|
|
7
|
-
export
|
7
|
+
export NWN_LIB_FILTER_EMPTY_EXOLOCSTR=1
|
8
8
|
|
9
9
|
|
10
|
-
== NWN_LIB_INFER_DATA_FILE
|
11
|
-
|
12
|
-
The path to the type/value inferring data file. See TYPE_VALUE_INFERRING for a definition.
|
13
|
-
|
14
|
-
Please be advised that inferring support for YAML is <b>EXPERIMENTAL</b> and may result in
|
15
|
-
<b>module and gff file corruption</b>.
|
16
|
-
|
17
|
-
== NWN_LIB_DONT_COMPACT_FIELDS
|
18
|
-
|
19
|
-
Set to non-nil ("1" will do) to prevent nwn-lib from compacting scalar fields into a more-readable
|
20
|
-
(but still fully parseable) format, if type inferring data is available.
|
21
|
-
|
22
|
-
=== Without compacting
|
23
|
-
ItemList:
|
24
|
-
value:
|
25
|
-
- !nwn-lib.elv.es,2008-12/struct
|
26
|
-
__data_type: UTC/ItemList
|
27
|
-
__struct_id: 0
|
28
|
-
InventoryRes: {value: herb053}
|
29
|
-
PaletteID: {value: 6}
|
30
|
-
SkillList: [{value: 0}, {value: 0}, {value: 0}, {value: 0}, ...
|
31
|
-
|
32
|
-
=== With compacting
|
33
|
-
ItemList:
|
34
|
-
- !nwn-lib.elv.es,2008-12/struct
|
35
|
-
__data_type: UTC/ItemList
|
36
|
-
InventoryRes: herb053
|
37
|
-
PaletteID: 6
|
38
|
-
SkillList: [0, 0, 0, 0, 0, 0, 2, 0, 0, 0 ...
|
39
|
-
|
40
|
-
|
41
|
-
== NWN_LIB_DONT_COMPACT_LIST_STRUCTS
|
42
|
-
|
43
|
-
Setting this to non-nil ("1" will do) will prevent nwn-lib from compacting lists that contain
|
44
|
-
structs, if type inferring data is available.
|
45
|
-
|
46
|
-
=== Without compacting
|
47
|
-
SkillList:
|
48
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
49
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
50
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
51
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
52
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
53
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
54
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 2}
|
55
|
-
- !nwn-lib.elv.es,2008-12/struct {__data_type: UTC/SkillList, Rank: 0}
|
56
|
-
...
|
57
|
-
|
58
|
-
=== With compacting
|
59
|
-
SkillList: [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, ...
|
60
|
-
|
61
|
-
|
62
|
-
== NWN_LIB_CLEAR_KNOWN_VALUES
|
63
|
-
|
64
|
-
Set to non-nil ("1" will do) to make nwn-lib omit fields that resolve to default values
|
65
|
-
as configured in $NWN_LIB_INFER_DATA_FILE.
|
66
|
-
|
67
|
-
The default is to not omit known-value data fields.
|
68
|
-
|
69
|
-
== NWN_LIB_FILTER_EMPTY_EXOLOCSTR
|
70
|
-
|
71
|
-
Set to non-nil ("1" will do) to make nwn-lib filter out empty exolocstr fields from
|
72
|
-
input files on reading.
|
73
|
-
|
74
|
-
The default is to keep them as-is.
|
75
|
-
|
76
10
|
== NWN_LIB_2DA_LOCATION
|
77
11
|
|
78
12
|
Set to a path containing all 2da files to initialize the 2da cache. This is needed for
|
79
|
-
most interactive helpers and a few
|
13
|
+
most interactive helpers and a few gizmos, and, of course, for TwoDA::Cache.
|
80
14
|
|
81
15
|
== NWN_LIB_TWODA_NEWLINE
|
82
16
|
|
data/bin/nwn-dsl
CHANGED
@@ -6,9 +6,6 @@ require 'nwn/all'
|
|
6
6
|
$backtrace = false
|
7
7
|
OptionParser.new do |o|
|
8
8
|
o.banner = "Usage: nwn-dsl [options] <script> -- [arguments to script]"
|
9
|
-
o.on "-b", "--backtrace", "Show a backtrace on error" do
|
10
|
-
$backtrace = true
|
11
|
-
end
|
12
9
|
end.parse!
|
13
10
|
|
14
11
|
fail "Not enough arguments (try -h)." unless ARGV.size > 0
|
@@ -19,9 +16,7 @@ begin
|
|
19
16
|
NWN::Gff::Scripting.run_script(IO.read($SCRIPT), nil, ARGV)
|
20
17
|
rescue => e
|
21
18
|
$stderr.puts e.message
|
22
|
-
|
23
|
-
|
24
|
-
$stderr.puts " " + e.backtrace.join("\n")
|
25
|
-
end
|
19
|
+
$stderr.puts ""
|
20
|
+
$stderr.puts " " + e.backtrace.join("\n")
|
26
21
|
exit 1
|
27
22
|
end
|
data/lib/nwn/all.rb
CHANGED
data/lib/nwn/erf.rb
CHANGED
@@ -4,123 +4,10 @@ module NWN
|
|
4
4
|
module Erf
|
5
5
|
ValidTypes = %w{ERF HAK MOD}
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
'mve' => 2,
|
11
|
-
'tga' => 3,
|
12
|
-
'wav' => 4,
|
13
|
-
'wfx' => 5,
|
14
|
-
'plt' => 6,
|
15
|
-
'ini' => 7,
|
16
|
-
'mp3' => 8,
|
17
|
-
'mpg' => 9,
|
18
|
-
'txt' => 10,
|
19
|
-
'plh' => 2000,
|
20
|
-
'tex' => 2001,
|
21
|
-
'mdl' => 2002,
|
22
|
-
'thg' => 2003,
|
23
|
-
'fnt' => 2005,
|
24
|
-
'lua' => 2007,
|
25
|
-
'slt' => 2008,
|
26
|
-
'nss' => 2009,
|
27
|
-
'ncs' => 2010,
|
28
|
-
'mod' => 2011,
|
29
|
-
'are' => 2012,
|
30
|
-
'set' => 2013,
|
31
|
-
'ifo' => 2014,
|
32
|
-
'bic' => 2015,
|
33
|
-
'wok' => 2016,
|
34
|
-
'2da' => 2017,
|
35
|
-
'tlk' => 2018,
|
36
|
-
'txi' => 2022,
|
37
|
-
'git' => 2023,
|
38
|
-
'bti' => 2024,
|
39
|
-
'uti' => 2025,
|
40
|
-
'btc' => 2026,
|
41
|
-
'utc' => 2027,
|
42
|
-
'dlg' => 2029,
|
43
|
-
'itp' => 2030,
|
44
|
-
'btt' => 2031,
|
45
|
-
'utt' => 2032,
|
46
|
-
'dds' => 2033,
|
47
|
-
'bts' => 2034,
|
48
|
-
'uts' => 2035,
|
49
|
-
'ltr' => 2036,
|
50
|
-
'gff' => 2037,
|
51
|
-
'fac' => 2038,
|
52
|
-
'bte' => 2039,
|
53
|
-
'ute' => 2040,
|
54
|
-
'btd' => 2041,
|
55
|
-
'utd' => 2042,
|
56
|
-
'btp' => 2043,
|
57
|
-
'utp' => 2044,
|
58
|
-
'dft' => 2045,
|
59
|
-
'gic' => 2046,
|
60
|
-
'gui' => 2047,
|
61
|
-
'css' => 2048,
|
62
|
-
'ccs' => 2049,
|
63
|
-
'btm' => 2050,
|
64
|
-
'utm' => 2051,
|
65
|
-
'dwk' => 2052,
|
66
|
-
'pwk' => 2053,
|
67
|
-
'btg' => 2054,
|
68
|
-
'utg' => 2055,
|
69
|
-
'jrl' => 2056,
|
70
|
-
'sav' => 2057,
|
71
|
-
'utw' => 2058,
|
72
|
-
'4pc' => 2059,
|
73
|
-
'ssf' => 2060,
|
74
|
-
'hak' => 2061,
|
75
|
-
'nwm' => 2062,
|
76
|
-
'bik' => 2063,
|
77
|
-
'ndb' => 2064,
|
78
|
-
'ptm' => 2065,
|
79
|
-
'ptt' => 2066,
|
80
|
-
'bak' => 2067,
|
81
|
-
'osc' => 3000,
|
82
|
-
'usc' => 3001,
|
83
|
-
'trn' => 3002,
|
84
|
-
'utr' => 3003,
|
85
|
-
'uen' => 3004,
|
86
|
-
'ult' => 3005,
|
87
|
-
'sef' => 3006,
|
88
|
-
'pfx' => 3007,
|
89
|
-
'cam' => 3008,
|
90
|
-
'lfx' => 3009,
|
91
|
-
'bfx' => 3010,
|
92
|
-
'upe' => 3011,
|
93
|
-
'ros' => 3012,
|
94
|
-
'rst' => 3013,
|
95
|
-
'ifx' => 3014,
|
96
|
-
'pfb' => 3015,
|
97
|
-
'zip' => 3016,
|
98
|
-
'wmp' => 3017,
|
99
|
-
'bbx' => 3018,
|
100
|
-
'tfx' => 3019,
|
101
|
-
'wlk' => 3020,
|
102
|
-
'xml' => 3021,
|
103
|
-
'scc' => 3022,
|
104
|
-
'ptx' => 3033,
|
105
|
-
'ltx' => 3034,
|
106
|
-
'trx' => 3035,
|
107
|
-
'mdb' => 4000,
|
108
|
-
'mda' => 4001,
|
109
|
-
'spt' => 4002,
|
110
|
-
'gr2' => 4003,
|
111
|
-
'fxa' => 4004,
|
112
|
-
'fxe' => 4005,
|
113
|
-
'jpg' => 4007,
|
114
|
-
'pwc' => 4008,
|
115
|
-
'ids' => 9996,
|
116
|
-
'erf' => 9997,
|
117
|
-
'bif' => 9998,
|
118
|
-
'key' => 9999,
|
119
|
-
}.freeze
|
7
|
+
# This reads and writes NWN::Resources::Container
|
8
|
+
# as valid ERF binary data.
|
9
|
+
class Erf < NWN::Resources::Container
|
120
10
|
|
121
|
-
class Erf
|
122
|
-
|
123
|
-
attr_accessor :content
|
124
11
|
attr_accessor :localized_strings
|
125
12
|
attr_accessor :description_str_ref
|
126
13
|
|
@@ -131,74 +18,16 @@ module NWN
|
|
131
18
|
|
132
19
|
# Create a new Erf object, optionally reading a existing file from +io+.
|
133
20
|
def initialize io = nil
|
134
|
-
|
21
|
+
super()
|
135
22
|
@localized_strings = {}
|
136
23
|
@io = io
|
137
24
|
@file_type, @file_version = "ERF", "V1.0"
|
138
25
|
@year = Time.now.year
|
139
26
|
@description_str_ref = 0xffffffff
|
140
|
-
@day_of_year = Time.now.yday
|
27
|
+
@day_of_year = Time.now.yday
|
141
28
|
read_from io if io
|
142
29
|
end
|
143
30
|
|
144
|
-
def add filename
|
145
|
-
@content << ContentObject.new_from(filename)
|
146
|
-
end
|
147
|
-
|
148
|
-
def has?(filename)
|
149
|
-
base = File.basename(filename)
|
150
|
-
@content.each {|f|
|
151
|
-
return true if f.filename.downcase == base.downcase
|
152
|
-
}
|
153
|
-
return false
|
154
|
-
end
|
155
|
-
|
156
|
-
class ContentObject
|
157
|
-
attr_accessor :resref
|
158
|
-
attr_accessor :res_type
|
159
|
-
attr_accessor :io
|
160
|
-
attr_accessor :offset
|
161
|
-
attr_accessor :size_override
|
162
|
-
|
163
|
-
def self.new_from filename
|
164
|
-
stat = File.stat(filename)
|
165
|
-
base = File.basename(filename).split(".")[0..-2].join(".")
|
166
|
-
ext = File.extname(filename)[1..-1]
|
167
|
-
res_type = NWN::Erf::Extensions[ext] or raise ArgumentError,
|
168
|
-
"Not a valid extension: #{ext.inspect} (while packing #{filename})"
|
169
|
-
|
170
|
-
ContentObject.new(base, res_type, filename, 0, stat.size)
|
171
|
-
end
|
172
|
-
|
173
|
-
def initialize resref, res_type, io = nil, offset = nil, size = nil
|
174
|
-
@resref, @res_type = resref, res_type
|
175
|
-
@io, @offset = io, offset
|
176
|
-
@size_override = size
|
177
|
-
end
|
178
|
-
|
179
|
-
# Get the size in bytes of this object.
|
180
|
-
def size
|
181
|
-
@size_override || (@io.is_a?(IO) ? @io.stat.size : File.stat(@io).size)
|
182
|
-
end
|
183
|
-
|
184
|
-
def get
|
185
|
-
if @io.is_a?(IO)
|
186
|
-
@io.seek(@offset) if @offset
|
187
|
-
@io.read(self.size)
|
188
|
-
else
|
189
|
-
IO.read(@io)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def filename
|
194
|
-
@resref + "." + self.extension
|
195
|
-
end
|
196
|
-
|
197
|
-
def extension
|
198
|
-
NWN::Erf::Extensions.index(@res_type)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
31
|
private
|
203
32
|
|
204
33
|
def read_from io
|
@@ -219,42 +48,40 @@ module NWN
|
|
219
48
|
|
220
49
|
if @file_version == "V1.0"
|
221
50
|
@filename_length = 16
|
222
|
-
# elsif version == "V1.1"
|
223
|
-
# @filename_length = 32
|
224
51
|
else
|
225
52
|
raise IOError, "Invalid erf version: #{@file_version}"
|
226
53
|
end
|
227
54
|
|
228
|
-
|
229
|
-
offset_to_keys == offset_to_locstr + locstr_size
|
230
|
-
|
231
|
-
raise IOError, "Offset to locstr list is not after header" if
|
232
|
-
offset_to_locstr != 160
|
233
|
-
|
55
|
+
@io.seek(offset_to_locstr)
|
234
56
|
locstr = @io.read(locstr_size)
|
235
|
-
raise IOError, "Cannot read locstr list" unless
|
236
|
-
locstr.size == locstr_size
|
237
57
|
|
238
58
|
for lstr in 0...locstr_count do
|
59
|
+
raise IOError, "locstr table does not contain enough entries or locstr_size is too small" if
|
60
|
+
locstr.nil? || locstr.size < 8
|
61
|
+
|
239
62
|
lid, strsz = locstr.unpack("V V")
|
240
|
-
str = locstr.unpack("a#{strsz}")[0]
|
241
|
-
|
242
|
-
strsz
|
63
|
+
str = locstr.unpack("x8 a#{strsz}")[0]
|
64
|
+
raise IOError,
|
65
|
+
"Expected locstr size does not match actual string size (want: #{strsz}, got #{str.size} of #{str.inspect})" if
|
66
|
+
strsz != str.size
|
67
|
+
|
243
68
|
@localized_strings[lid] = str
|
244
69
|
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
70
|
end
|
248
71
|
|
249
72
|
keylist_entry_size = @filename_length + 4 + 2 + 2
|
73
|
+
@io.seek(offset_to_keys)
|
250
74
|
keylist = @io.read(keylist_entry_size * entry_count)
|
75
|
+
raise IOError, "keylist too short" if keylist.size != keylist_entry_size * entry_count
|
251
76
|
keylist = keylist.unpack("A16 V v v" * entry_count)
|
252
77
|
keylist.each_slice(4) {|resref, res_id, res_type, unused|
|
253
|
-
@content << ContentObject.new(resref, res_type, @io)
|
78
|
+
@content << NWN::Resources::ContentObject.new(resref, res_type, @io)
|
254
79
|
}
|
255
80
|
|
256
81
|
resourcelist_entry_size = 4 + 4
|
82
|
+
@io.seek(offset_to_res)
|
257
83
|
resourcelist = @io.read(resourcelist_entry_size * entry_count)
|
84
|
+
raise IOError, "resource list too short" if resourcelist.size != resourcelist_entry_size * entry_count
|
258
85
|
resourcelist = resourcelist.unpack("I I" * entry_count)
|
259
86
|
_index = -1
|
260
87
|
resourcelist.each_slice(2) {|offset, size|
|