$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) require 'open-uri' require 'RipXploreLog' require 'SubclassTracking' require 'proc_source' class NativeFileType attr_accessor(:file_system_image,:filename,:contents,:file_type,:aux_code,:meta_data) def initialize(file_system_image,filename,contents,file_type,aux_code) @file_system_image=file_system_image @filename=filename @contents=contents @file_type=file_type @aux_code=aux_code @meta_data={} end def NativeFileType.matching_score ancestors.length end def NativeFileType.non_matching_score 0 end def NativeFileType.all_native_file_types NativeFileType.subclasses end def NativeFileType.native_file_types_possible_on_file_system(file_system) candidates=[] NativeFileType.all_native_file_types.each do |native_file_type| candidates< b.to_s} end #how should this file be described in a catalog list? def type_description self.class end def load_address self.class.load_address(contents) end def NativeFileType.load_address(filebytes) 0 end def <=>(o) return -1 unless o.respond_to?(:filename) if filename==o.filename then return self.to_s<=>o.to_s else return (filename<=>o.filename) end end def to_hex_dump file_system_image.file_system.host_system.hex_dump(contents) end def to_info_dump s="class: #{self.class}\n" s+="filename: #{self.filename}\n" @meta_data.keys.sort.each {|k| s<<"#{k}: #{@meta_data[k]}\n"} s end #some filesystems differentiate between full and partial filenames. #e.g. in ProDOS the 'full' filename includes the full path #by default, full_filename is the same as filename, but can be overridden #for those filesystems that need this def full_filename @filename end def ==(other_object) if !other_object.kind_of? NativeFileType then return false end if self.filename!=other_object.filename then return false end return self.to_s==other_object.to_s end #given metadata and contents of a file from a file system image, return an instance of the NativeFileType subclass that is the closest match def NativeFileType.best_fit(file_system_image,filename,contents,file_type=nil,aux_code=nil) candidates={} NativeFileType.all_native_file_types.each do |native_file_type| if !native_file_type.file_system_file_types.keys.include?(file_system_image.file_system) then RipXploreLog.debug("skipping #{native_file_type} - can't reside on #{file_system_image.file_system}") else RipXploreLog.debug("checking native file type #{native_file_type}") candidate_score=native_file_type.compatability_score(file_system_image,filename,contents,file_type,aux_code) RipXploreLog.debug("score - #{candidate_score}") candidates[native_file_type]=candidate_score end end if candidates.length==0 then RipXploreLog.debug( 'no valid combination of file system and native file types found') return nil end best_candidate=candidates.keys.sort{|a,b| candidates[b]<=>candidates[a]}[0] RipXploreLog.debug("best candidate for #{filename} = #{best_candidate} score: #{candidates[best_candidate]}") native_file=best_candidate.new(file_system_image,filename,contents,file_type,aux_code) if GenericGIF.is_gif?(native_file) then RipXploreLog.debug(" #{filename} is a GIF") native_file.extend GenericGIF end native_file end def NativeFileType.file_type_matches?(file_system_image,file_type) result=false [file_system_file_types[file_system_image.file_system]].flatten.each do |target_file_type| result=true if target_file_type==:any result=true if(file_type.to_s==target_file_type.to_s) RipXploreLog.debug "test for #{file_type} == #{target_file_type} : #{result}" end result end #how many bytes should be skipped to get to the file data? def header_length 0 end def data_without_header (@contents.length>header_length) ? @contents[header_length,@contents.length-header_length] : "" end @@code_for_tests={} def self.code_for_tests @@code_for_tests[self] || [] end def self.is_valid_file_if(code_for_test) #RipXploreLog.debug "adding test for #{self}: #{code_for_test.source}" @@code_for_tests[self] ||=[] @@code_for_tests[self]<