nwn-lib 0.5.0 → 0.5.1

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