class NWN::Gff::Writer
Attributes
bytes[R]
Public Class Methods
dump(gff, io = nil, data_type = nil)
click to toggle source
Takes a NWN::Gff::Gff object and dumps it to io
, including the header. If io
is nil, return the raw bytes, otherwise the number of bytes written.
# File lib/nwn/gff/writer.rb, line 12 def self.dump(gff, io = nil, data_type = nil) ret = new(gff, data_type).bytes if io io.write(ret) ret.size else ret end end
Private Instance Methods
add_data_field(type, label, content)
click to toggle source
# File lib/nwn/gff/writer.rb, line 43 def add_data_field type, label, content label_id = get_label_id_for_label label @fields.push Types.key(type), label_id, content (@fields.size - 1) / 3 end
get_label_id_for_label(str)
click to toggle source
# File lib/nwn/gff/writer.rb, line 38 def get_label_id_for_label str @labels << str unless @labels.index(str) @labels.index(str) end
write_all()
click to toggle source
# File lib/nwn/gff/writer.rb, line 49 def write_all data = [] write_struct @gff c_offset = 0 data << [ @data_type || @gff.data_type, @gff.data_version, # Offset of Struct array as bytes from the beginning of the file c_offset += 56, # Number of elements in Struct array @structs.size / 3, # Offset of Field array as bytes from the beginning of the file fields_start = c_offset += @structs.size / 3 * 12, # Number of elements in Field array @fields.size / 3, # Offset of Label array as bytes from the beginning of the file c_offset += @fields.size / 3 * 12, # Number of elements in Label array @labels.size, # Offset of Field Data as bytes from the beginning of the file c_offset += @labels.size * 16, # Number of bytes in Field Data block @field_data.size, # Offset of Field Indices array as bytes from the beginning of the file c_offset += @field_data.size, # Number of bytes in Field Indices array @field_indices.size * 4, # Offset of List Indices array as bytes from the beginning of the file c_offset += @field_indices.size * 4, # Number of bytes in List Indices array @list_indices.size * 4 ].pack("A4a4 VV VV VV VV VV VV") data << @structs.pack("V*") data << @fields.pack("V*") data << @labels.pack("a16" * @labels.size) data << @field_data data << @field_indices.pack("V*") data << @list_indices.pack("V*") @bytes = data.join("") end
write_struct(struct)
click to toggle source
# File lib/nwn/gff/writer.rb, line 100 def write_struct struct raise GffError, "struct invalid: #{struct.inspect}" unless struct.is_a?(NWN::Gff::Struct) raise GffError, "struct_id missing from struct" unless struct.struct_id # This holds all field label ids this struct has as a member fields_of_this_struct = [] # This will hold the index of this struct index = @structs.size / 3 @structs.push struct.struct_id, 0, 0 struct.sort.each {|k,v| raise GffError, "Empty label." if !k || k == "" case v.field_type # simple data types when :byte, :char, :word, :short, :dword, :int, :float format = Formats[v.field_type] fields_of_this_struct << add_data_field(v.field_type, k, [v.field_value].pack(format).unpack("V")[0]) # complex data types when :dword64, :int64, :double, :void fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size) format = Formats[v.field_type] @field_data << case v.field_type when :dword64 [ ( v.field_value / (2**32) ) & 0xffffffff, v.field_value % (2**32) ].pack("II") when :void [ v.field_value.size, v.field_value ].pack("Va*") else [v.field_value].pack(format) end when :struct raise GffError, "type = struct, but value not a hash" unless v.field_value.is_a?(Struct) fields_of_this_struct << add_data_field(v.field_type, k, write_struct(v.field_value)) when :list raise GffError, "type = list, but value not an array" unless v.field_value.is_a?(Array) fields_of_this_struct << add_data_field(v.field_type, k, 4 * @list_indices.size) count = v.field_value.size tmp = @list_indices.size @list_indices << count count.times { @list_indices << 0 } v.field_value.each_with_index do |kk, idx| vv = write_struct(kk) @list_indices[ idx + tmp + 1 ] = vv end when :resref fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size) fv = v.field_value.encode(NWN.setting :in_encoding) @field_data << [fv.size, fv].pack("Ca*") when :cexostr fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size) fv = v.field_value.encode(NWN.setting :in_encoding) @field_data << [fv.size, fv].pack("Va*") when :cexolocstr raise GffError, "type = cexolocstr, but value not a hash (#{v.field_value.class})" unless v.field_value.is_a?(Hash) fields_of_this_struct << add_data_field(v.field_type, k, @field_data.size) # total size (4), str_ref (4), str_count (4) total_size = 8 v.field_value.each {|kk,vv| total_size += vv.size + 8 } @field_data << [ total_size, v.str_ref, v.field_value.size ].pack("VVV") v.field_value.each {|k,v| vn = v.encode(NWN.setting :in_encoding) @field_data << [k, vn.size, vn].pack("VVa*") } else raise GffError, "Unknown data type: #{v.field_type}" end } # id/type, data_or_offset, nr_of_fields @structs[3 * (index) + 2] = fields_of_this_struct.size if fields_of_this_struct.size < 1 elsif fields_of_this_struct.size == 1 @structs[3 * (index) + 1] = fields_of_this_struct[0] else # Offset into field_indices starting where are number of nr_of_fields # dwords as indexes into @fields @structs[3 * (index) + 1] = 4 * (@field_indices.size) @field_indices.push *fields_of_this_struct end index end