Class: PAKFile

Inherits:
Object
  • Object
show all
Defined in:
lib/pakspy.rb

Overview

Class handles Quake style PAK files

Defined Under Namespace

Classes: FileEntry, FileEntryPAK, FileEntrySystem, Header

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = nil) ⇒ PAKFile

Opens an existing PAK file at path or if not specified creates a virtual PAK



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/pakspy.rb', line 6

def initialize(path = nil)
  @file_hash = Hash.new
  @pak_file = nil

  unless path.nil?
    @pak_file = File.open path, "rb"

    header = Header.new @pak_file.read 12
    puts "Warning: Might not be a real PAK" unless header.magic == "PACK"
    file_count = header.size / 64

    @pak_file.seek header.offset
    file_count.times do
      entry = FileEntryPAK.new self, @pak_file.read(64)
      file_add entry
    end
  end
end

Instance Attribute Details

#pak_fileObject (readonly)

Returns the value of attribute pak_file.



120
121
122
# File 'lib/pakspy.rb', line 120

def pak_file
  @pak_file
end

Instance Method Details

#extract(name, path) ⇒ Object

Extracts a file name from this PAKFile to path on system

Raises:

  • (ArgumentError)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/pakspy.rb', line 31

def extract(name, path)
  file_entry = file_find(name)
  raise ArgumentError, "No such file #{name} in this PAK." if file_entry.nil?
  
  # Create the necessary directories
  path_current = ""
  File.dirname(path).split(/[\/\\]/).each do |dir|
    path_current += dir
    Dir.mkdir path_current unless Dir.exists?(path_current)
    path_current += "/"
  end

  # Transfer contents
  file = File.open path, "wb"
  file.write file_entry.read

  file.close
end

#extract_all(dir) ⇒ Object

Extracts all files in PAK to dir directory



52
53
54
55
56
# File 'lib/pakspy.rb', line 52

def extract_all(dir)
  files_list.each do |file_name|
    extract file_name, dir + "/" + file_name
  end
end

#finalizeObject



25
26
27
# File 'lib/pakspy.rb', line 25

def finalize
  @pak_file.close unless @pak_file.nil?
end

#insert(path, name) ⇒ Object

Inserts a system file at path as name



60
61
62
# File 'lib/pakspy.rb', line 60

def insert(path, name)
  file_add FileEntrySystem.new self, path, name
end

#insert_all(dir) ⇒ Object

Inserts a directory dir recursively contents as their names



66
67
68
# File 'lib/pakspy.rb', line 66

def insert_all(dir)
  insert_all_helper(dir, "")
end

#listObject

Lists all files in PAK to an array



116
117
118
# File 'lib/pakspy.rb', line 116

def list
  files_list
end

#save(path) ⇒ Object

Saves all the changes to path



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/pakspy.rb', line 72

def save(path)
  tmp_path = "#{path}.tmp_"
  file = File.open tmp_path, "wb"
  
  file_entries = Array.new

  # Will finish header later when we know where the file entries will be
  file.write "PACK"
  file.seek 12

  # Insert all of the files
  files_list.each do |name|
    entry = file_find name

    file_entry = Hash.new
    file_entry[:name] = entry.name
    file_entry[:offset] = file.pos

    file.write entry.read

    file_entry[:size] = file.pos - file_entry[:offset]
    file_entries.push file_entry
  end

  # Now we know the rest of the info needed for the header
  file_entry_pos = file.pos
  file.seek 4
  file.write [file_entry_pos, file_entries.length * 64].pack("VV")

  # And finally add the file entries
  file.seek file_entry_pos
  file_entries.each do |file_entry|
    file.write [file_entry[:name], file_entry[:offset], file_entry[:size]].pack("a56VV")
  end
  
  # close so we can open it again
  file.close

  # And finally move it to the correct place
  File.rename tmp_path, path
end