File: resource_file.rb

package info (click to toggle)
ruby-ttfunk 1.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 916 kB
  • sloc: ruby: 1,719; makefile: 16
file content (78 lines) | stat: -rw-r--r-- 2,205 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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