Class: Bayonetta::DATFile

Inherits:
LibBin::Structure
  • Object
show all
Includes:
Alignment
Defined in:
lib/bayonetta/dat.rb

Defined Under Namespace

Classes: HashMap, Header

Constant Summary collapse

ALIGNMENTS =
{
  'dat' => 0x2000,
  'wmb' => 0x1000,
  'wtb' => 0x1000,
  'wtp' => 0x1000,
  'wta' =>   0x40,
  'exp' => 0x1000,
  'sop' =>   0x40,
  'eff' => 0x1000,
  'sdx' => 0x1000,
  'bxm' =>   0x40
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(big = false) ⇒ DATFile

Returns a new instance of DATFile.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/bayonetta/dat.rb', line 118

def initialize(big = false)
  @big = big
  super()
  @header = Header::new
  @header.id = "DAT\x00".b
  @header.num_files = 0
  @header.offset_file_offsets = 0
  @header.offset_file_extensions = 0
  @header.offset_file_names = 0
  @header.offset_file_sizes = 0
  @header.offset_hash_map = 0

  @file_offsets = []
  @file_extensions = []
  @file_name_length = 0
  @file_names = []
  @file_sizes = []
  @files = []

  @hash_map = nil
end

Instance Attribute Details

#bigObject (readonly)

Returns the value of attribute big.



5
6
7
# File 'lib/bayonetta/dat.rb', line 5

def big
  @big
end

Class Method Details

.is_big?(f) ⇒ Boolean

Returns:

  • (Boolean)


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/bayonetta/dat.rb', line 101

def self.is_big?(f)
  f.rewind
  block = lambda { |big|
    h = Header::load(f, big)
    h.offset_file_offsets < f.size &&
      h.offset_file_names < f.size &&
      h.offset_file_sizes < f.size &&
      h.offset_hash_map < f.size
  }
  big = block.call(true)
  f.rewind
  small = block.call(false)
  f.rewind
  raise "Invalid data!" unless big ^ small
  return big
end

.load(input_name) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/bayonetta/dat.rb', line 220

def self.load(input_name)
  if input_name.respond_to?(:read) && input_name.respond_to?(:seek)
    input = input_name
  else
    File.open(input_name, "rb") { |f|
      input = StringIO::new(f.read, "rb")
    }
  end
  big = self::is_big?(input)
  dat = self::new(big)
  dat.__load(input, big)
  input.close unless input_name.respond_to?(:read) && input_name.respond_to?(:seek)
  dat
end

Instance Method Details

#[](i) ⇒ Object



165
166
167
# File 'lib/bayonetta/dat.rb', line 165

def [](i)
  return [@file_names[i][0..-2], StringIO::new(@files[i] ? @files[i] : "", "rb")]
end

#compute_layoutObject



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/bayonetta/dat.rb', line 187

def compute_layout
  @header.offset_file_offsets = 0x20
  @header.offset_file_extensions = @header.offset_file_offsets + 4 * @header.num_files
  @header.offset_file_names = @header.offset_file_extensions + 4 * @header.num_files
  max_file_name_length = @file_names.collect(&:length).max
  @file_name_length = max_file_name_length
  @header.offset_file_sizes = @header.offset_file_names + 4 + @file_name_length * @header.num_files
  @header.offset_file_sizes = align(@header.offset_file_sizes, 4)
  if @hash_map
    @header.offset_hash_map = @header.offset_file_sizes + 4 * @header.num_files
    files_offset = @header.offset_hash_map + @hash_map.__size(@header.offset_hash_map, self)
  else
    @offset_hash_map = 0
    files_offset = @header.offset_file_sizes + 4 * @header.num_files
  end
  @file_offsets = @header.num_files.times.collect { |i|
    if @file_sizes[i] > 0
      tmp = align(files_offset, ALIGNMENTS[@file_extensions[i][0..-2]])
      files_offset = align(tmp + @file_sizes[i], ALIGNMENTS[@file_extensions[i][0..-2]])
      tmp
    else
      0
    end
  }
  @total_size = align(files_offset, 0x1000)
  self
end

#dump(output_name) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/bayonetta/dat.rb', line 235

def dump(output_name)
  compute_layout
  if output_name.respond_to?(:write) && output_name.respond_to?(:seek)
    output = output_name
  else
    output = StringIO::new("", "wb")#File.open(output_name, "wb")
    output.write("\x00"*@total_size)
    output.rewind
  end
  output.rewind

  __set_dump_state(output, @big, nil, nil)
  __dump_fields
  __unset_dump_state

  unless output_name.respond_to?(:write) && output_name.respond_to?(:seek)
    File.open(output_name, "wb") { |f|
      f.write output.string
    }
    output.close
  end
  self
end

#eachObject



155
156
157
158
159
160
161
162
163
# File 'lib/bayonetta/dat.rb', line 155

def each
  if block_given? then
    @header.num_files.times { |i|
      yield @file_names[i][0..-2], StringIO::new(@files[i] ? @files[i] : "", "rb")
    }
  else
    to_enum(:each)
  end
end

#invalidate_layoutObject



140
141
142
143
144
145
146
147
148
149
# File 'lib/bayonetta/dat.rb', line 140

def invalidate_layout
  @header.offset_file_offsets = 0
  @header.offset_file_extensions = 0
  @header.offset_file_names = 0
  @header.offset_file_sizes = 0
  @header.offset_hash_map = 0
  @file_offsets = []
  @hash_map = nil
  self
end

#layoutObject



151
152
153
# File 'lib/bayonetta/dat.rb', line 151

def layout
  @file_names.collect { |name| name[0..-2] }
end

#push(name, file) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/bayonetta/dat.rb', line 169

def push(name, file)
  invalidate_layout
  @file_names.push name+"\x00"
  if file.kind_of?(StringIO)
    data = file.string
  else
    file.rewind
    data = file.read
  end
  @files.push data
  @file_sizes.push file.size
  extname = File.extname(name)
  raise "Invalid name, missing extension!" if extname == ""
  @file_extensions.push extname[1..-1]+"\x00"
  @header.num_files += 1
  self
end

#set_hash_map(hash) ⇒ Object



215
216
217
218
# File 'lib/bayonetta/dat.rb', line 215

def set_hash_map(hash)
  @hash_map = HashMap::new
  @hash_map.set hash
end