class FastLib

The FastLib class implements the meat of the FASTLIB archive format

Constants

FLAG_COMPRESS
FLAG_ENCRYPT
VERSION

Public Class Methods

cache() click to toggle source

Expose the cache to callers

# File lib/fastlib.rb, line 273
def self.cache
        @@cache
end
create(lib, flags, bdir, *dirs) click to toggle source

This method provides a way to create a FASTLIB archive programatically, the key arguments are the name of the destination archive, the base directory that should be excluded from the archived path, and finally the list of specific files and directories to include in the archive.

# File lib/fastlib.rb, line 182
def self.create(lib, flags, bdir, *dirs)
        head = ""
        data = ""
        hidx = 0
        didx = 0
        
        bdir = bdir.gsub(/\/$/, '')
        brex = /^#{Regexp.escape(bdir)}\//
        
        if flags.kind_of?(::String)
                if flags =~ /^0x/
                        flags = flags.to_i(16)
                else
                        flags = flags.to_i
                end
        end

        @@cache[lib] = {
                :fastlib_flags => flags
        }
        
        dirs.each do |dir|
                ::Find.find(dir).each do |path|
                        next if not ::File.file?(path)
                        name = fastlib_filter_encode( lib, path.sub( brex, "" ) )
                        
                        buff = ""
                        ::File.open(path, "rb") do |fd|
                                buff = fastlib_filter_encode(lib, fd.read(fd.stat.size))
                        end
                        
                        head << [ name.length, didx, buff.length, ::File.stat(path).mtime.utc.to_i ].pack("NNNN")
                        head << name
                        hidx = hidx + 16 + name.length
                
                        data << buff
                        didx = didx + buff.length
                end
        end
        
        head << [0,0,0].pack("NNN")
        
        ::File.open(lib, "wb") do |fd|
                fd.write("FAST")
                fd.write( [ head.length, flags ].pack("NN") )
                fd.write( head )
                fd.write( data )
        end   
end
decrypt_00000000(data) click to toggle source
# File lib/fastlib.rb, line 266
def self.decrypt_00000000(data)
        encrypt_00000000(data)
end
decrypt_12345600(data) click to toggle source
# File lib/fastlib.rb, line 258
def self.decrypt_12345600(data)
        encrypt_00000000(data)
end
encrypt_00000000(data) click to toggle source
# File lib/fastlib.rb, line 262
def self.encrypt_00000000(data)
        data.unpack("C*").map{ |c| c ^ 0x90 }.pack("C*")
end
encrypt_12345600(data) click to toggle source

This is a stub crypto handler that performs a basic XOR operation against a fixed one byte key. The two usable IDs are 12345600 and 00000000

# File lib/fastlib.rb, line 254
def self.encrypt_12345600(data)
        encrypt_00000000(data)
end
fastlib_filter_decode(lib, buff) click to toggle source

This method provides compression and encryption capabilities for the fastlib archive format.

# File lib/fastlib.rb, line 119
def self.fastlib_filter_decode(lib, buff)

        if (@@cache[lib][:fastlib_flags] & FLAG_ENCRYPT) != 0
        
                @@cache[lib][:fastlib_decrypt] ||= ::Proc.new do |data|
                        stub = "decrypt_%.8x" % ( @@cache[lib][:fastlib_flags] & 0xfffffff0 )
                        FastLib.send(stub, data)
                end

                buff = @@cache[lib][:fastlib_decrypt].call( buff )
        end
        
        if (@@cache[lib][:fastlib_flags] & FLAG_COMPRESS) != 0
                if not @@has_zlib
                        raise ::RuntimeError, "zlib is required to open this archive"
                end

                z = Zlib::Inflate.new
                buff = z.inflate(buff)
                buff << z.finish
                z.close      
        end
        
        buff
end
fastlib_filter_encode(lib, buff) click to toggle source

This method provides compression and encryption capabilities for the fastlib archive format.

# File lib/fastlib.rb, line 149
def self.fastlib_filter_encode(lib, buff)
        
        if (@@cache[lib][:fastlib_flags] & FLAG_COMPRESS) != 0
                if not @@has_zlib
                        raise ::RuntimeError, "zlib is required to open this archive"
                end

                z = Zlib::Deflate.new
                buff = z.deflate(buff)
                buff << z.finish
                z.close      
        end

        if (@@cache[lib][:fastlib_flags] & FLAG_ENCRYPT) != 0
        
                @@cache[lib][:fastlib_encrypt] ||= ::Proc.new do |data|
                        stub = "encrypt_%.8x" % ( @@cache[lib][:fastlib_flags] & 0xfffffff0 )
                        FastLib.send(stub, data)
                end

                buff = @@cache[lib][:fastlib_encrypt].call( buff )
        end
        
        buff
end
list(lib) click to toggle source

This method provides a way to list the contents of an archive file, returning the names only in sorted order.

# File lib/fastlib.rb, line 236
def self.list(lib)
        load_cache(lib)
        ( @@cache[lib] || {} ).keys.map{|x| x.to_s }.sort.select{ |x| @@cache[lib][x] }
end
load(lib, name, noprocess=false) click to toggle source

This method loads content from a specific archive file by name. If the noprocess argument is set to true, the contents will not be expanded to include workarounds for things such as __FILE__. This is useful when loading raw binary data where these strings may occur

# File lib/fastlib.rb, line 62
def self.load(lib, name, noprocess=false)
        data = ""
        load_cache(lib)

        return if not ( @@cache[lib] and @@cache[lib][name] )
        
        
        ::File.open(lib, "rb") do |fd|
                fd.seek(
                        @@cache[lib][:fastlib_header][0] +
                        @@cache[lib][:fastlib_header][1] + 
                        @@cache[lib][name][0]
                )
                data = fastlib_filter_decode( lib, fd.read(@@cache[lib][name][1] ))
        end
        
        # Return the contents in raw or processed form
        noprocess ? data : post_process(lib, name, data)
end
load_cache(lib) click to toggle source

This method caches the file list and offsets within the archive

# File lib/fastlib.rb, line 85
def self.load_cache(lib)
        return if @@cache[lib]
        @@cache[lib] = {}
        
        return if not ::File.exists?(lib)
                        
        ::File.open(lib, 'rb') do |fd|
                dict = {}
                head = fd.read(4)
                return if head != "FAST"
                hlen = fd.read(4).unpack("N")[0]
                flag = fd.read(4).unpack("N")[0]                     
        
                @@cache[lib][:fastlib_header] = [12, hlen, fd.stat.mtime.utc.to_i ]
                @@cache[lib][:fastlib_flags]  = flag
                
                nlen, doff, dlen, tims = fd.read(16).unpack("N*")
                
                while nlen > 0
                        name = fastlib_filter_decode( lib, fd.read(nlen) )
                        dict[name] = [doff, dlen, tims]
                        
                        nlen, doff, dlen, tims = fd.read(16).unpack("N*")
                end
                
                @@cache[lib].merge!(dict)
        end
        
end
post_process(lib, name, data) click to toggle source

This method is expands __FILE__ sequences and other inline dynamic constants to map to the correct location.

# File lib/fastlib.rb, line 245
def self.post_process(lib, name, data)
        data.gsub('__FILE__', "'#{ ::File.expand_path(::File.join(::File.dirname(lib), name)) }'")
end
version() click to toggle source

This method returns the version of the fastlib library

# File lib/fastlib.rb, line 52
def self.version
        VERSION
end