Class: RuneRb::Cache::FileSystem

Inherits:
Object
  • Object
show all
Includes:
RuneRb::Core::Logging
Defined in:
lib/rune/cache/file_system.rb

Overview

Since:

  • 0.1.0

Defined Under Namespace

Classes: FileDescriptor

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RuneRb::Core::Logging

#err, #err!, #log, #log!

Constructor Details

#initialize(path) ⇒ FileSystem

Constructs a new FileSystem instance.

Parameters:

  • path (String)

    the path to the cache.

Since:

  • 0.1.0



27
28
29
30
31
32
33
34
# File 'lib/rune/cache/file_system.rb', line 27

def initialize(path)
  @indicies = Array.new
  @crc_table = RuneRb::Core::Buffer.new(mode: 'r')
  @crc = Array.new
  @cache = Hash.new
  @data_file = StringIO.new
  read_layout(path)
end

Instance Attribute Details

#cacheHash<FileDescriptor, RuneRb::Cache::Archive> (readonly)

Returns a map of decoded archives.

Returns:

Since:

  • 0.1.0



7
8
9
# File 'lib/rune/cache/file_system.rb', line 7

def cache
  @cache
end

#crcArray<Integer> (readonly)

Returns the CRC values for the cache.

Returns:

  • (Array<Integer>)

    the CRC values for the cache.

Since:

  • 0.1.0



15
16
17
# File 'lib/rune/cache/file_system.rb', line 15

def crc
  @crc
end

#crc_tableRuneRb::Core::Buffer (readonly)

Returns the CRC table for the cache.

Returns:

Since:

  • 0.1.0



11
12
13
# File 'lib/rune/cache/file_system.rb', line 11

def crc_table
  @crc_table
end

#data_fileStringIO (readonly)

Returns the data file for the cache.

Returns:

  • (StringIO)

    the data file for the cache.

Since:

  • 0.1.0



23
24
25
# File 'lib/rune/cache/file_system.rb', line 23

def data_file
  @data_file
end

#indiciesArray<StringIO> (readonly)

Returns the indicies for the cache.

Returns:

  • (Array<StringIO>)

    the indicies for the cache.

Since:

  • 0.1.0



19
20
21
# File 'lib/rune/cache/file_system.rb', line 19

def indicies
  @indicies
end

Instance Method Details

#archive(type, file) ⇒ Object

Retrieves an Archive by the specified FileDescriptor.

Parameters:

  • type (Integer)

    the file type.

  • file (Integer)

    the file identifier.

Since:

  • 0.1.0



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/rune/cache/file_system.rb', line 39

def archive(type, file)
  descriptor = FileDescriptor.new(type, file)
  cached = @cache[descriptor]
  
  if cached == nil
    file = cache_file(descriptor)
    cached = RuneRb::Cache::Archive.decode(file)
    @cache[descriptor] = cached
  end
  
  cached
end

#cache_countInteger

The number of index files in the cache.

Returns:

  • (Integer)

    the number of index files in the cache.

Since:

  • 0.1.0



135
136
137
# File 'lib/rune/cache/file_system.rb', line 135

def cache_count
  @indicies.length
end

#cache_file(descriptor) ⇒ RuneRb::Core::Buffer

Retrieves a RuneRb::Core::Buffer that corresponds to the specified FileDescriptor in the cache.

Parameters:

Returns:

  • (RuneRb::Core::Buffer)

    the buffer containing data that corresponds to the specified descriptor.

Raises:

  • (RuntimeError)

    if a Chunk id does not match what is expected during cache file read.

  • (RuntimeError)

    if a type does not match descriptor type during cache file read.

  • (RuntimeError)

    if a file identifier does not match descriptor file identifier during cache file read.

Since:

  • 0.1.0



58
59
60
61
62
63
64
65
66
67
68
69
70
71
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
# File 'lib/rune/cache/file_system.rb', line 58

def cache_file(descriptor)
  index = index_for(descriptor)
  buffer = RuneRb::Core::Buffer.new(mode: 'r')
  
  position = index.block * RuneRb::Cache::BLOCK_SIZE
  read = 0
  size = index.size
  blocks = size / RuneRb::Cache::CHUNK_SIZE

  if size % RuneRb::Cache::CHUNK_SIZE != 0
    blocks += 1
  end

  info "Reading #{blocks} blocks from position #{position}."

  blocks.times do |i|
    @data_file.seek(position)
    header = @data_file.read
    header_data = header.unpack('C*')
  
    position += RuneRb::Cache::HEADER_SIZE
    
    next_file     = header_data[0] << 8 | header_data[1]
    current_chunk = header_data[2] << 8 | header_data[3]
    next_block    = header_data[4] << 16 | header_data[5] << 8 | header_data[6]
    next_type     = header_data[7]

    raise "Chunk id mismatch! (Current #{current_chunk}, Expected #{i})" if current_chunk != i

    chunk_size = size - read
    chunk_size = RuneRb::Cache::CHUNK_SIZE if chunk_size > RuneRb::Cache::CHUNK_SIZE

    @data_file.seek(position)
    buffer << @data_file.read

    read += chunk_size
    position = next_block * RuneRb::Cache::BLOCK_SIZE

    if size > read
      raise "Next type (#{next_type}) does not match descriptor type (#{descriptor.type + 1})." if next_type != descriptor.type + 1
      raise "Next file (#{next_file}) does not match descriptor file (#{descriptor.file})." if next_file != descriptor.file
    end
  end

  info "Read #{buffer.length} from cache."

  buffer
end

#check_for_archives(path) ⇒ Object

Checks for the existence of cache archives in a path.

Parameters:

  • path (String)

    the path to the cache directory.

Since:

  • 0.1.0



167
168
169
170
171
172
173
174
# File 'lib/rune/cache/file_system.rb', line 167

def check_for_archives(path)
  return false if path.nil?
  return false unless File.directory?(path)
  return false unless File.exist?(path)
  return false unless File.readable?(path)
  return false if Dir.empty?(path)
  true
end

#closeObject

Since:

  • 0.1.0



128
129
130
131
# File 'lib/rune/cache/file_system.rb', line 128

def close
  @indicies.each(&:close)
  @data_file.close
end

#file_count(cache) ⇒ Object

The number of files in a cache.

Parameters:

  • cache (Integer)

    the cache to check.

Since:

  • 0.1.0



141
142
143
# File 'lib/rune/cache/file_system.rb', line 141

def file_count(cache)
  (@indicies[cache].size / RuneRb::Core::INDEX_SIZE) - 1
end

#index_for(descriptor) ⇒ Object

Since:

  • 0.1.0



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rune/cache/file_system.rb', line 107

def index_for(descriptor)
  idx = descriptor.type
  raise "Index out of bounds. (#{idx})" if idx < 0 || idx >= @indicies.length

  buffer = String.new
  idx_file = @indicies[idx]
  position = descriptor.file * RuneRb::Cache::INDEX_SIZE
  info "Reading index from position #{position}"

  if position >= 0 && (idx_file.length >= (position + RuneRb::Cache::INDEX_SIZE))
    idx_file.seek(position, IO::SEEK_CUR)
    buffer << idx_file.read
  else
    raise "Could not find index file at position #{position}."
  end

  info " Length: #{buffer.length}, Index data: #{buffer.bytes}"

  RuneRb::Cache::Index.decode(buffer)
end

#read_layout(path) ⇒ Object

Reads the layout of the cache from the specified path.

Parameters:

  • path (String)

    the path to the cache directory.

Raises:

  • (RuntimeError)

    if the cache archive is not found.

Since:

  • 0.1.0



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rune/cache/file_system.rb', line 148

def read_layout(path)
  raise "Cache archive not found. Please install them into the #{path} directory."  unless check_for_archives(path)

  # Find how many index files exist
  count = 0.upto(255).each do |i|
    break i unless File.exist?(File.join(path, "main_file_cache.idx#{i}"))
  end

  # Gather file objects
  @data_file = File.open(File.join(path, "main_file_cache.dat"), "r")

  count.times do |i|
    data = File.read("#{path}/main_file_cache.idx#{i}")
    @indicies[i] = StringIO.new(data)
  end
end