Skip to content
Browse files

Support for reading TTF data from Apple dfont files.

  • Loading branch information...
1 parent 360ff2a commit 158a82ab543f319cd8ed4870e0735c353b747e3b @jamis jamis committed Jan 6, 2009
Showing with 83 additions and 0 deletions.
  1. +5 −0 lib/ttfunk.rb
  2. +78 −0 lib/ttfunk/resource_file.rb
View
5 lib/ttfunk.rb
@@ -1,5 +1,6 @@
require 'stringio'
require 'ttfunk/directory'
+require 'ttfunk/resource_file'
module TTFunk
class File
@@ -10,6 +11,10 @@ def self.open(file)
new(::File.open(file, "rb") { |f| f.read })
end
+ def self.from_dfont(file, which=0)
+ new(ResourceFile.open(file) { |dfont| dfont["sfnt", which] })
+ end
+
def initialize(contents)
@contents = StringIO.new(contents)
@directory = Directory.new(@contents)
View
78 lib/ttfunk/resource_file.rb
@@ -0,0 +1,78 @@
+module TTFunk
+ class ResourceFile
+ attr_reader :map
+
+ def self.open(path)
+ ::File.open(path, "rb") do |io|
+ file = new(io)
+ yield file
+ end
+ end
+
+ def initialize(io)
+ @io = io
+
+ data_offset, map_offset, data_length, map_length = @io.read(16).unpack("N*")
+
+ @map = {}
+ @io.pos = map_offset + 24 # skip header copy, next map handle, file reference, and attrs
+ type_list_offset, name_list_offset = @io.read(4).unpack("n*")
+
+ type_list_offset += map_offset
+ name_list_offset += map_offset
+
+ @io.pos = type_list_offset
+ max_index = @io.read(2).unpack("n").first
+ 0.upto(max_index) do
+ type, max_type_index, ref_list_offset = @io.read(8).unpack("A4nn")
+ @map[type] = { :list => [], :named => {} }
+
+ parse_from(type_list_offset + ref_list_offset) do
+ 0.upto(max_type_index) do
+ id, name_ofs, attr = @io.read(5).unpack("nnC")
+ data_ofs = @io.read(3)
+ data_ofs = data_offset + [0, data_ofs].pack("CA*").unpack("N").first
+ handle = @io.read(4).unpack("N").first
+
+ entry = { :id => id, :attributes => attr, :offset => data_ofs, :handle => handle }
+
+ if name_list_offset + name_ofs < map_offset + map_length
+ parse_from(name_ofs + name_list_offset) do
+ len = @io.read(1).unpack("C").first
+ entry[:name] = @io.read(len)
+ end
+ end
+
+ @map[type][:list] << entry
+ @map[type][:named][entry[:name]] = entry if entry[:name]
+ end
+ end
+ end
+ end
+
+ def [](type, index=0)
+ if @map[type]
+ collection = index.is_a?(Fixnum) ? :list : :named
+ if @map[type][collection][index]
+ parse_from(@map[type][collection][index][:offset]) do
+ length = @io.read(4).unpack("N").first
+ return @io.read(length)
+ end
+ end
+ end
+ end
+
+ def resources_for(type)
+ (@map[type] && @map[type][:named] || {}).keys
+ end
+
+ private
+
+ def parse_from(offset)
+ saved, @io.pos = @io.pos, offset
+ yield
+ ensure
+ @io.pos = saved
+ end
+ end
+end

0 comments on commit 158a82a

Please sign in to comment.
Something went wrong with that request. Please try again.