nwn-lib 0.5.0 → 0.5.1

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.
@@ -42,10 +42,9 @@ With the release of 0.4.0, the API changed significantly. Previous yaml dumps ma
42
42
  I can't help you with your API bindings, but for your YAML dumps, a converter script has been provided (see {file:BINARIES}).
43
43
 
44
44
 
45
- === Attention Unicode/UTF-users
45
+ === Upgrade from 0.4.x to 0.5.x
46
46
 
47
- 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.
48
- This will be worked around in a future release until the release of ruby 1.9, which will provide native charset support.
47
+ All with version 0.4.x produced files should be compatible with 0.5.0. Your application might require some porting to ruby 1.9.
49
48
 
50
49
 
51
50
  === Quickstart
@@ -8,7 +8,8 @@ Under linux, just add them to your shell environment (usually .bashrc), like so:
8
8
 
9
9
  == NWN_LIB_IN_ENCODING
10
10
 
11
- The character encoding your local data files are in. Defaults to ISO-8859-1.
11
+ The character encoding your local data (gff) files are in. Defaults to ISO-8859-1.
12
+ Extended dump formats like yaml, xml are always format-specific, usually UTF-8.
12
13
 
13
14
  == NWN_LIB_PRETTY_JSON
14
15
 
@@ -8,7 +8,6 @@ Thread.abort_on_exception = true
8
8
  $options = {
9
9
  :backup => nil,
10
10
  :encoding => nil,
11
- :out_encoding => nil,
12
11
  :force => false,
13
12
  :infile => '-',
14
13
  :outfile => '-',
@@ -50,14 +49,10 @@ begin OptionParser.new do |o|
50
49
  "(see `man cp' for a description)" do |b|
51
50
  $options[:backup] = b.nil? ? true : b
52
51
  end
53
- o.on "--encoding ENCODING", "sets the used input encoding in which your NWN",
52
+ o.on "--encoding ENCODING", "sets the used encoding in which your gff",
54
53
  "files are encoded in" do |e|
55
54
  $options[:encoding] = e
56
55
  end
57
- o.on "--out-encoding ENCODING", "sets the used output encoding",
58
- "(defaults to UTF-8)" do |e|
59
- $options[:out_encoding] = e
60
- end
61
56
 
62
57
  o.on "-1", "--nwn1", "Allow 16 byte resrefs." do
63
58
  ENV['NWN_LIB_RESREF32'] = nil
@@ -121,7 +116,6 @@ $options[:informat] or fail "No input format specified."
121
116
  $options[:outformat] or fail "No output format specified."
122
117
 
123
118
  NWN.setting(:in_encoding, $options[:encoding]) if $options[:encoding]
124
- NWN.setting(:out_encoding, $options[:out_encoding]) if $options[:out_encoding]
125
119
 
126
120
  if :auto == $options[:informat]
127
121
  $options[:informat] = NWN::Gff.guess_file_format($options[:infile].downcase)
@@ -49,7 +49,7 @@ module NWN
49
49
  module Pretty
50
50
  def self.dump data, io
51
51
  old = $> ; $> = StringIO.new
52
- pp data.box
52
+ pp data
53
53
  sz = $>.pos
54
54
  $>.seek(0)
55
55
  io.write $>.read
@@ -216,58 +216,4 @@ module NWN::Gff::Field
216
216
  end
217
217
  end
218
218
  #:startdoc:
219
-
220
- # Deep-unboxes a Hash, e.g. iterating down, converting all strings
221
- # from the native charset.
222
- def self.unbox! element, parent_label, parent
223
- element.extend(NWN::Gff::Field)
224
- element.field_label = parent_label
225
- element.parent = parent
226
- element.str_ref ||= NWN::Gff::Field::DEFAULT_STR_REF if element.respond_to?('str_ref=')
227
-
228
- element.extend_meta_classes
229
- case element.field_type
230
- when :cexolocstr
231
- mod = {}
232
- element.field_value.each {|x,y|
233
- mod[x] = NWN.iconv_native_to_gff(y)
234
- }
235
- mod.each {|x,y|
236
- element.field_value.delete(x)
237
- element.field_value[x.to_i] = y
238
- }
239
- when :cexostr
240
- element.field_value = NWN.iconv_native_to_gff(element.field_value)
241
-
242
- when :list
243
- mod = {}
244
- element.field_value.each_with_index {|x,idx|
245
- mod[idx] = NWN::Gff::Struct.unbox!(x, element)
246
- }
247
- mod.each {|x,y|
248
- element.field_value[x] = y
249
- }
250
- when :struct
251
- element.field_value = NWN::Gff::Struct.unbox!(element.field_value, element)
252
- end
253
- element.validate
254
- element
255
- end
256
-
257
- # Returns a hash of this Field without the API calls mixed in,
258
- # all language-strings transformed by str_handler.
259
- def box
260
- t = Hash[self]
261
- t.delete('label')
262
- case field_type
263
- when :cexolocstr
264
- t['value'].each {|x,y|
265
- t['value'][x] = NWN.iconv_gff_to_native(y)
266
- }
267
- when :cexostr
268
- t['value'] = NWN.iconv_gff_to_native(t['value'])
269
- end
270
- t
271
- end
272
-
273
219
  end
@@ -14,6 +14,7 @@ class NWN::Gff::Reader
14
14
 
15
15
  def initialize io #:nodoc:
16
16
  @io = io
17
+ io.internal_encoding == nil or raise "passed io needs to be binary, is #{io.internal_encoding.inspect}"
17
18
  read_all
18
19
  end
19
20
 
@@ -47,7 +48,7 @@ class NWN::Gff::Reader
47
48
  @io.seek(label_offset)
48
49
  @labels = @io.e_read(label_len, "labels")
49
50
  @labels = @labels.unpack("A16" * label_count)
50
- @labels.map! {|l| l.encode("ASCII") }
51
+ @labels.map! {|l| l.force_encoding("ASCII") }
51
52
 
52
53
  @io.seek(field_data_offset)
53
54
  @field_data = @io.e_read(field_data_count, "field_data")
@@ -75,8 +76,8 @@ class NWN::Gff::Reader
75
76
  raise GffError, "struct index #{index} outside of struct_array" if
76
77
  index * 3 + 3 > @structs.size + 1
77
78
 
78
- file_type = file_type.encode('ASCII') if file_type
79
- file_version = file_version.encode('ASCII') if file_version
79
+ file_type = file_type.force_encoding('ASCII') if file_type
80
+ file_version = file_version.force_encoding('ASCII') if file_version
80
81
 
81
82
  struct.struct_id = type
82
83
  struct.data_type = file_type
@@ -159,11 +160,15 @@ class NWN::Gff::Reader
159
160
 
160
161
  when :cexostr
161
162
  len = @field_data[data_or_offset, 4].unpack("V")[0]
162
- @field_data[data_or_offset + 4, len].encode(NWN.setting :in_encoding)
163
+ str = @field_data[data_or_offset + 4, len].force_encoding(NWN.setting :in_encoding)
164
+ str.valid_encoding? or raise "Invalid encoding bytes in cexostr: #{str.inspect}"
165
+ str
163
166
 
164
167
  when :resref
165
168
  len = @field_data[data_or_offset, 1].unpack("C")[0]
166
- @field_data[data_or_offset + 1, len].encode(NWN.setting :in_encoding)
169
+ str = @field_data[data_or_offset + 1, len].force_encoding(NWN.setting :in_encoding)
170
+ str.valid_encoding? or raise "Invalid encoding bytes in resref: #{str.inspect}"
171
+ str
167
172
 
168
173
  when :cexolocstr
169
174
  exostr = {}
@@ -176,7 +181,8 @@ class NWN::Gff::Reader
176
181
 
177
182
  str_count.times {
178
183
  id, len = all.unpack("VV")
179
- str = all[8, len].unpack("a*")[0].encode(NWN.setting :in_encoding)
184
+ str = all[8, len].unpack("a*")[0].force_encoding(NWN.setting :in_encoding)
185
+ str.valid_encoding? or raise "Invalid encoding bytes in cexolocstr: #{str.inspect}"
180
186
  all = all[(8 + len)..-1]
181
187
  exostr[id] = str
182
188
  }
@@ -185,7 +191,7 @@ class NWN::Gff::Reader
185
191
 
186
192
  when :void
187
193
  len = @field_data[data_or_offset, 4].unpack("V")[0]
188
- @field_data[data_or_offset + 4, len].unpack("a*")[0]
194
+ @field_data[data_or_offset + 4, len].unpack("a*")[0].force_encoding("BINARY")
189
195
 
190
196
  when :struct
191
197
  read_struct data_or_offset, nil, field.parent.data_version
@@ -222,44 +222,4 @@ module NWN::Gff::Struct
222
222
  def / path
223
223
  by_path(path)
224
224
  end
225
-
226
- # Deep-unboxes a Hash, e.g. iterating down, converting it to
227
- # the native charset.
228
- def self.unbox! o, parent = nil
229
- o.extend(NWN::Gff::Struct)
230
- o.element = parent if parent
231
- o.struct_id = o.delete('__struct_id')
232
- o.data_type = o.delete('__data_type')
233
- o.data_version = o.delete('__data_version')
234
- o.data_version ||= NWN::Gff::Struct::DEFAULT_DATA_VERSION
235
-
236
- NWN.log_debug("Unboxed without a root data type") if
237
- !parent && !o.data_type
238
- NWN.log_debug("Unboxed with explicit data type #{o.data_type.inspect}") if
239
- parent && o.data_type
240
-
241
- o.each {|label,element|
242
- o[label] = NWN::Gff::Field.unbox!(element, label, o)
243
- }
244
-
245
- o
246
- end
247
-
248
- # Returns a hash of this Struct without the API calls mixed in,
249
- # converting it from the native charset.
250
- def box
251
- t = Hash[self]
252
- t.merge!({
253
- '__struct_id' => self.struct_id
254
- })
255
- t.merge!({
256
- '__data_version' => self.data_version,
257
- }) if self.data_version && self.data_version !=
258
- NWN::Gff::Struct::DEFAULT_DATA_VERSION
259
- t.merge!({
260
- '__data_type' => self.data_type
261
- }) if @data_type
262
- t
263
- end
264
-
265
225
  end
@@ -160,11 +160,13 @@ private
160
160
 
161
161
  when :resref
162
162
  fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size)
163
- @field_data << [v.field_value.size, v.field_value].pack("Ca*")
163
+ fv = v.field_value.encode(NWN.setting :in_encoding)
164
+ @field_data << [fv.size, fv].pack("Ca*")
164
165
 
165
166
  when :cexostr
166
167
  fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size)
167
- @field_data << [v.field_value.size, v.field_value].pack("Va*")
168
+ fv = v.field_value.encode(NWN.setting :in_encoding)
169
+ @field_data << [fv.size, fv].pack("Va*")
168
170
 
169
171
  when :cexolocstr
170
172
  raise GffError, "type = cexolocstr, but value not a hash (#{v.field_value.class})" unless
@@ -184,7 +186,8 @@ private
184
186
  ].pack("VVV")
185
187
 
186
188
  v.field_value.each {|k,v|
187
- @field_data << [k, v.size, v].pack("VVa*")
189
+ vn = v.encode(NWN.setting :in_encoding)
190
+ @field_data << [k, vn.size, vn].pack("VVa*")
188
191
  }
189
192
 
190
193
  else
@@ -1,18 +1,98 @@
1
1
  require 'json'
2
+ require 'base64'
2
3
 
3
4
  module NWN::Gff::Struct
5
+ def json_box
6
+ t = Hash[self]
7
+ t.merge!({
8
+ '__struct_id' => self.struct_id
9
+ })
10
+ t.merge!({
11
+ '__data_version' => self.data_version,
12
+ }) if self.data_version && self.data_version !=
13
+ NWN::Gff::Struct::DEFAULT_DATA_VERSION
14
+ t.merge!({
15
+ '__data_type' => self.data_type
16
+ }) if @data_type
17
+ t
18
+ end
19
+ private :json_box
20
+
4
21
  def to_json(*a)
5
- box.to_json(*a)
22
+ json_box.to_json(*a)
6
23
  end
7
24
  end
8
25
 
9
26
  module NWN::Gff::Field
27
+ def json_box
28
+ t = Hash[self]
29
+ t.delete('label')
30
+ case field_type
31
+ when :void
32
+ t['value'] = Base64::strict_encode64(t['value'])
33
+ end
34
+ t
35
+ end
36
+ private :json_box
37
+
10
38
  def to_json(*a)
11
- box.to_json(*a)
39
+ json_box.to_json(*a)
12
40
  end
13
41
  end
14
42
 
15
43
  module NWN::Gff::Handler::JSON
44
+ def self.json_unbox_field element, parent_label, parent
45
+ element.extend(NWN::Gff::Field)
46
+ element.field_label = parent_label
47
+ element.parent = parent
48
+ element.str_ref ||= NWN::Gff::Field::DEFAULT_STR_REF if element.respond_to?('str_ref=')
49
+
50
+ element.extend_meta_classes
51
+ case element.field_type
52
+ when :cexolocstr
53
+ element.field_value.keys.each {|key|
54
+ val = element.field_value.delete(key)
55
+ element.field_value[key.to_i] = val
56
+ }
57
+
58
+ when :void
59
+ element.field_value = Base64::strict_decode64(element.field_value)
60
+
61
+ when :list
62
+ mod = {}
63
+ element.field_value.each_with_index {|x,idx|
64
+ mod[idx] = self.json_unbox_struct(x, element)
65
+ }
66
+ mod.each {|x,y|
67
+ element.field_value[x] = y
68
+ }
69
+ when :struct
70
+ element.field_value = self.json_unbox_struct(element.field_value, element)
71
+ end
72
+ element.validate
73
+ element
74
+ end
75
+
76
+ def self.json_unbox_struct o, parent = nil
77
+ o.extend(NWN::Gff::Struct)
78
+ o.element = parent if parent
79
+ o.struct_id = o.delete('__struct_id')
80
+ o.data_type = o.delete('__data_type')
81
+ o.data_version = o.delete('__data_version')
82
+ o.data_version ||= NWN::Gff::Struct::DEFAULT_DATA_VERSION
83
+
84
+ NWN.log_debug("Unboxed without a root data type") if
85
+ !parent && !o.data_type
86
+ NWN.log_debug("Unboxed with explicit data type #{o.data_type.inspect}") if
87
+ parent && o.data_type
88
+
89
+ o.each {|label,element|
90
+ o[label] = self.json_unbox_field(element, label, o)
91
+ }
92
+
93
+ o
94
+ end
95
+
16
96
  def self.load io
17
97
  json = if io.respond_to?(:to_str)
18
98
  io.to_str
@@ -22,7 +102,7 @@ module NWN::Gff::Handler::JSON
22
102
  io.read
23
103
  end
24
104
 
25
- NWN::Gff::Struct.unbox!(JSON.parse(json), nil)
105
+ self.json_unbox_struct(JSON.parse(json), nil)
26
106
  end
27
107
 
28
108
  def self.dump struct, io
@@ -1,7 +1,6 @@
1
1
  module NWN
2
2
  SETTING_DEFAULT_VALUES = {
3
- 'NWN_LIB_IN_ENCODING' => 'ISO-8859-1',
4
- 'NWN_LIB_OUT_ENCODING' => 'UTF-8'
3
+ 'NWN_LIB_IN_ENCODING' => 'ISO-8859-1'
5
4
  }
6
5
 
7
6
  # This writes a internal warnings and debug messages to stderr.
@@ -49,7 +48,7 @@ module NWN
49
48
 
50
49
  # Converts text from native format (such as json) to Gff (required by NWN).
51
50
  def self.iconv_native_to_gff text
52
- text.encode(NWN.setting(:out_encoding))
51
+ text.encode(NWN.setting(:in_encoding))
53
52
  end
54
53
 
55
54
  # Converts text from Gff format to native/external, such as json (usually UTF-8).
@@ -1,3 +1,3 @@
1
1
  module NWN
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -152,10 +152,6 @@ public
152
152
  end
153
153
 
154
154
  def load io
155
- old_encoding = NWN.setting(:out_encoding, 'UTF-8')
156
- NWN.log_debug("Ignoring custom out_encoding for xml output, always UTF-8") if
157
- old_encoding != 'UTF-8'
158
-
159
155
  doc = XML::Parser.io(io)
160
156
  root = doc.parse.root
161
157
  ret = case @format
@@ -168,15 +164,10 @@ public
168
164
  raise ArgumentError, "Unsupported XML format registered: #{@format.inspect}"
169
165
  end
170
166
 
171
- NWN.setting(:out_encoding, old_encoding)
172
167
  ret
173
168
  end
174
169
 
175
170
  def dump data, io
176
- old_encoding = NWN.setting(:out_encoding, 'UTF-8')
177
- NWN.log_debug("Ignoring custom out_encoding for xml output, always UTF-8") if
178
- old_encoding != 'UTF-8'
179
-
180
171
  doc = XML::Document.new
181
172
  doc.root = case @format
182
173
  when :nxml
@@ -193,7 +184,6 @@ public
193
184
  t = doc.to_s
194
185
  io.write(t)
195
186
 
196
- NWN.setting(:out_encoding, old_encoding)
197
187
  t.size
198
188
  end
199
189
  end
@@ -81,7 +81,16 @@ module NWN::Gff::Field
81
81
  map.style = :inline unless NWN::Gff::Handler::YAML::NonInlineableFields.index(self['type'])
82
82
  map.add('type', self['type'])
83
83
  map.add('str_ref', self['str_ref']) if has_str_ref?
84
- map.add('value', self['value'])
84
+ map.add('value', case self['type']
85
+ when :resref, :cexostr
86
+ self['value'].encode('utf-8')
87
+ when :cexolocstr
88
+ Hash[self['value'].map {|lang,str|
89
+ [lang, str.encode('utf-8')]
90
+ }]
91
+ else
92
+ self['value']
93
+ end)
85
94
  end
86
95
  end
87
96
  end
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.5.0
4
+ version: 0.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-30 00:00:00.000000000 Z
12
+ date: 2012-12-28 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Neverwinter Nights 1/2 file formats ruby library
15
15
  email: