dvi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.0 2007-12-18
2
+
3
+ * Keita Yamaguchi:
4
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the GPL
3
+ (see the file GPL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a) distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
data/Manifest.txt ADDED
@@ -0,0 +1,37 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/dvi.rb
9
+ lib/dvi/lsr.rb
10
+ lib/dvi/opcode.rb
11
+ lib/dvi/tfm.rb
12
+ lib/dvi/tfm/format.rb
13
+ lib/dvi/util.rb
14
+ lib/dvi/version.rb
15
+ log/debug.log
16
+ misc/latex/latex.dvi
17
+ misc/latex/latex.tex
18
+ script/destroy
19
+ script/generate
20
+ script/txt2html
21
+ setup.rb
22
+ spec/dvi_spec.rb
23
+ spec/lsr_spec.rb
24
+ spec/opcode_spec.rb
25
+ spec/spec.opts
26
+ spec/spec_helper.rb
27
+ spec/tfm_spec.rb
28
+ tasks/deployment.rake
29
+ tasks/dvi.rake
30
+ tasks/environment.rake
31
+ tasks/rspec.rake
32
+ tasks/website.rake
33
+ website/index.html
34
+ website/index.txt
35
+ website/javascripts/rounded_corners_lite.inc.js
36
+ website/stylesheets/screen.css
37
+ website/template.rhtml
data/README.txt ADDED
@@ -0,0 +1,10 @@
1
+ = README
2
+
3
+ The library ruby-dvi processes DVI(DeVice Independent: Standard 0 draft 0.05)
4
+ and TFM file format.
5
+
6
+ == Test
7
+
8
+ rake dvi:ls-r spec
9
+
10
+ Copyright (c) 2007 Keita Yamaguchi(keita.yamaguchi@gmail.com)
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/config/hoe.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'dvi/version'
2
+
3
+ AUTHOR = 'Keita Yamaguchi' # can also be an array of Authors
4
+ EMAIL = "keita.yamaguchi@gmail.com"
5
+ DESCRIPTION = "This is a library to read DVI(DeVice Independent) file format."
6
+ GEM_NAME = 'dvi' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'dvi' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Dvi::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'ruby-dvi documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store', 'tmp/*',
59
+ 'misc/**/*.aux', 'misc/**/*.log']
60
+
61
+ # == Optional
62
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
63
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
64
+
65
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
66
+
67
+ end
68
+
69
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
70
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
71
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
72
+ hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'dvi'
data/lib/dvi.rb ADDED
@@ -0,0 +1,99 @@
1
+ module Dvi
2
+ class Processor
3
+ attr_accessor :h, :v, :w, :x, :y, :z, :font, :fonts
4
+ attr_reader :stack, :chars, :rules, :lsr
5
+ attr_accessor :dvi_version, :numerator, :denominator, :mag
6
+ attr_accessor :total_pages
7
+
8
+ def initialize(lsr=Dvi::LsR.default)
9
+ @h = 0 # horizontal position
10
+ @v = 0 # vertical position
11
+ @w = 0 #
12
+ @x = 0
13
+ @y = 0
14
+ @z = 0
15
+ @font = nil
16
+ @stack = []
17
+ @chars = []
18
+ @rules = []
19
+ @fonts = Hash.new
20
+ @lsr = lsr
21
+ end
22
+
23
+ def process(opcode)
24
+ opcode.interpret(self)
25
+ end
26
+ end
27
+
28
+ class Font
29
+ attr_reader :checksum, :scale, :design_size, :area, :name, :tfm
30
+ def initialize(checksum, scale, design_size, area, name, tfm)
31
+ @checksum = checksum # check sum should be same as in tfm file
32
+ @scale = scale # scale factor
33
+ @design_size = design_size # DVI unit
34
+ @area = area # nil
35
+ @name = name # font name for tfm file
36
+ @tfm = tfm
37
+ end
38
+ end
39
+
40
+ # TypesetCharacter is a class of typeset characters.
41
+ class TypesetCharacter
42
+ attr_reader :index, :font, :h , :v, :width
43
+ def initialize(index, h, v, font)
44
+ @font = font
45
+ @h = h
46
+ @v = v
47
+ @index = index
48
+ end
49
+
50
+ def metric
51
+ @font.tfm.char[@index]
52
+ end
53
+ end
54
+
55
+ # Rule is a class for solid black rectangles.
56
+ class Rule
57
+ attr_reader :height, :width, :h, :v
58
+ def initialize(h, v, height, width)
59
+ @h = h
60
+ @v = v
61
+ @height = height
62
+ @width = width
63
+ end
64
+ end
65
+
66
+ # Parse a dvi file as a opcode list.
67
+ def self.parse(io, opcodes = Opcode::BASIC_OPCODES)
68
+ table = Hash.new
69
+ io.extend Util
70
+
71
+ opcodes.each do |opcode|
72
+ opcode.range.each{|i| table[i] = opcode }
73
+ end
74
+
75
+ content = []
76
+
77
+ begin
78
+ while cmd = io.readchar do
79
+ content << table[cmd].read(cmd, io)
80
+ end
81
+ rescue EOFError; end
82
+
83
+ return content
84
+ end
85
+
86
+ def self.process(io, opcodes = Opcode::BASIC_OPCODES)
87
+ ps = Processor.new
88
+ parse(io, opcodes).each do |opcode|
89
+ ps.process(opcode)
90
+ end
91
+ return ps
92
+ end
93
+ end
94
+
95
+ require 'dvi/lsr'
96
+ require 'dvi/tfm'
97
+ require 'dvi/util'
98
+ require 'dvi/opcode'
99
+ require 'dvi/version'
data/lib/dvi/lsr.rb ADDED
@@ -0,0 +1,41 @@
1
+ class Dvi::LsR
2
+ def initialize(texmfdir)
3
+ @texmfdir = texmfdir
4
+ @table = Hash.new
5
+ file = File.open(File.join(texmfdir, "ls-R"))
6
+ begin
7
+ current = nil
8
+ while true do
9
+ case file.readline
10
+ when /^%/, /^$/
11
+ # do nothing
12
+ when /^(.*):$/
13
+ current = $1
14
+ when /^(.+)$/
15
+ @table[$1] = Array.new unless @table.has_key? $1
16
+ @table[$1] << current
17
+ end
18
+ end
19
+ rescue EOFError
20
+ file.close
21
+ end
22
+ end
23
+
24
+ def find(name)
25
+ if @table.has_key? name
26
+ File.join(@texmfdir, @table[name].first, name)
27
+ else
28
+ return nil
29
+ end
30
+ end
31
+
32
+ def self.default
33
+ @default
34
+ end
35
+
36
+ def self.default=(lsr)
37
+ raise ArgumentError unless lsr.kind_of?(self)
38
+ @default = lsr
39
+ end
40
+ end
41
+
data/lib/dvi/opcode.rb ADDED
@@ -0,0 +1,515 @@
1
+ module Dvi::Opcode
2
+ class Error < StandardError; end
3
+ class NotImplemented < StandardError; end
4
+
5
+ # Base is a super class for all Opcode classes.
6
+ class Base
7
+ # Sets the range of opcode byte.
8
+ def self.set_range(r)
9
+ if r.kind_of?(Range)
10
+ @range = r
11
+ else
12
+ @range = r..r
13
+ end
14
+ end
15
+
16
+ # Returns the range of opcode byte.
17
+ def self.range
18
+ return @range
19
+ end
20
+
21
+ def self.read(cmd, io) #:nodoc:
22
+ return self.new
23
+ end
24
+
25
+ def interpret(ps) #:nodoc:
26
+ raise NotImplemented, self
27
+ end
28
+ end
29
+
30
+ # SetChar is a class for set_char_0 ... set_char_127 opcodes.
31
+ class SetChar < Base
32
+ set_range 0..127
33
+ attr_reader :index
34
+
35
+ # index:: character index
36
+ def initialize(index)
37
+ raise ArgumentError unless 0 <= index && index < 256
38
+ @index = index
39
+ end
40
+
41
+ def self.read(cmd, io) #:nodoc:
42
+ return self.new(cmd)
43
+ end
44
+
45
+ # Appends a character and changes the current position.
46
+ def interpret(ps)
47
+ # append a new character
48
+ ps.chars << char = Dvi::TypesetCharacter.new(@index, ps.h, ps.v, ps.font)
49
+ # change the current position
50
+ unless self.kind_of?(Put)
51
+ ps.h += ps.font.design_size * char.metric.width
52
+ end
53
+ end
54
+ end
55
+
56
+ # PrintChar is a base class for set/put opcodes.
57
+ class SetPutBase < SetChar
58
+
59
+ # index:: character index
60
+ # n:: read byte length
61
+ def initialize(index, n)
62
+ if case n
63
+ when 1; 0 <= index && index < 256
64
+ when 2; 0 <= index && index < 65536
65
+ when 3; 0 <= index && index < 16777216
66
+ when 4; -2147483648 <= index && index < 2147483648
67
+ end
68
+ then
69
+ @index = index
70
+ else
71
+ raise ArgumentError, [index, n]
72
+ end
73
+ end
74
+
75
+ def self.read(cmd, io) #:nodoc:
76
+ base = if self == Set then 127 else 132 end
77
+ n = cmd - base
78
+ f = if n < 4 then "read_uint" + n.to_s else "read_int4" end
79
+ return self.new(io.__send__(f), n)
80
+ end
81
+ end
82
+
83
+ # Set is a class for set1 ... set4 opcodes.
84
+ class Set < SetPutBase
85
+ set_range 128..131
86
+ end
87
+
88
+ # Put is a class for put1 ... put4 opcodes.
89
+ class Put < SetPutBase
90
+ set_range 133..136
91
+ end
92
+
93
+ # RuleBase is a base class for SetRule/PutRule opcodes.
94
+ class RuleBase < Base
95
+ attr_reader :height, :width
96
+
97
+ def initialize(height, width)
98
+ unless (-2147483648..2147483647).include?(height) and
99
+ (-2147483648..2147483647).include?(width)
100
+ raise ArgumentError
101
+ end
102
+
103
+ @height = height
104
+ @width = width
105
+ end
106
+
107
+ def self.read(cmd, io)
108
+ return self.new(io.read_int4, io.read_int4)
109
+ end
110
+
111
+ def interpret(ps)
112
+ # append a new rule.
113
+ ps.rules << rule = Dvi::Rule.new(ps.h, ps.v, @height, @width)
114
+ # change the current position.
115
+ ps.h += @width unless self.kind_of?(PutRule)
116
+ end
117
+ end
118
+
119
+ # SetRule is a class for set_rule opcode.
120
+ class SetRule < RuleBase
121
+ set_range 132
122
+ end
123
+
124
+ # PutRule is a class for put_rule opcode.
125
+ class PutRule < RuleBase
126
+ set_range 137
127
+ end
128
+
129
+ # Nop is a class for nop opcode. The nop opcode means "no operation."
130
+ class Nop < Base
131
+ set_range 138
132
+ # do nothing.
133
+ def interpret(ps); end
134
+ end
135
+
136
+ # Bop is a class for bop opcode. The bop opcode means "begging of a page."
137
+ class Bop < Base
138
+ set_range 139
139
+ attr_reader :counters, :previous
140
+
141
+ def initialize(counters, previous)
142
+ raise ArgumentError if counters.size != 10
143
+ # \count0 ... \count9
144
+ @counters = counters
145
+ # previous bop
146
+ @previous = previous
147
+ end
148
+
149
+ def self.read(cmd, io) #:nodoc:
150
+ # read \count0 ... \count9
151
+ counters = (0..9).map{ io.read_int4 }
152
+ # read previous bop position
153
+ previous = io.read_int4
154
+ return self.new(counters, previous)
155
+ end
156
+
157
+ def interpret(ps)
158
+ # clear register
159
+ ps.h = 0
160
+ ps.v = 0
161
+ ps.w = 0
162
+ ps.x = 0
163
+ ps.y = 0
164
+ ps.z = 0
165
+ # set the stack empty
166
+ ps.stack.clear
167
+ # set current font to an undefined value
168
+ ps.font = nil
169
+ # !!! NOT IMPLEMENTED !!!
170
+ # Ci?
171
+ end
172
+ end
173
+
174
+ # Eop is a class for eop opcode. The eop opcode means "end of page."
175
+ class Eop < Base
176
+ set_range 140
177
+ def interpret(ps)
178
+ # the stack should be empty.
179
+ ps.stack.clear
180
+ end
181
+ end
182
+
183
+ # Push is a class for push opcode.
184
+ class Push < Base
185
+ set_range 141
186
+ def interpret(ps)
187
+ # push current registry to the stack.
188
+ ps.stack.push([ps.h, ps.v, ps.w, ps.x, ps.y, ps.z])
189
+ end
190
+ end
191
+
192
+ # Pop is a class for pop opcode.
193
+ class Pop < Base
194
+ set_range 142
195
+ def interpret(ps)
196
+ # pop the stack and set it to current registry.
197
+ ps.h, ps.v, ps.w, ps.x, ps.y, ps.z = ps.stack.pop
198
+ end
199
+ end
200
+
201
+ class ChangeRegister0 < Base
202
+ def self.read(cmd, io)
203
+ base = case cmd
204
+ when Right.range; 142
205
+ when W.range; 148
206
+ when X.range; 152
207
+ when Down.range; 156
208
+ when Y.range; 161
209
+ when Z.range; 166
210
+ else return self.new
211
+ end
212
+ return self.new(io.__send__("read_int" + (cmd - base).to_s))
213
+ end
214
+ end
215
+
216
+ class ChangeRegister < ChangeRegister0
217
+ attr_reader :size
218
+
219
+ def initialize(size)
220
+ @size = size
221
+ end
222
+ end
223
+
224
+ # Right is a class for right1 ... right4 opcodes.
225
+ class Right < ChangeRegister
226
+ set_range 143..146
227
+ def interpret(ps)
228
+ # move right.
229
+ ps.h += @size
230
+ end
231
+ end
232
+
233
+ # W0 is a class for w0 opcode.
234
+ class W0 < ChangeRegister0
235
+ set_range 147
236
+ def interpret(ps)
237
+ # move right.
238
+ ps.h += ps.w
239
+ end
240
+ end
241
+
242
+ # W is a class for w1 ... w4 opcodes.
243
+ class W < ChangeRegister
244
+ set_range 148..151
245
+ def interpret(ps)
246
+ # change w.
247
+ ps.w = @size
248
+ # move right.
249
+ ps.h += @size
250
+ end
251
+ end
252
+
253
+ # X0 is a class for x0 opcode.
254
+ class X0 < ChangeRegister0
255
+ set_range 152
256
+ def interpret(ps)
257
+ # move right.
258
+ ps.h += ps.x
259
+ end
260
+ end
261
+
262
+ # X is a class for x1 ... x4 opcodes.
263
+ class X < ChangeRegister
264
+ set_range 153..156
265
+ def interpret(ps)
266
+ # change x.
267
+ ps.x = @size
268
+ # move right.
269
+ ps.h += ps.x
270
+ end
271
+ end
272
+
273
+ # Down is a class for down1 ... down4 opcodes.
274
+ class Down < ChangeRegister
275
+ set_range 157..160
276
+
277
+ def interpret(ps)
278
+ # move down.
279
+ ps.v += @size
280
+ end
281
+ end
282
+
283
+ # Y0 is a class for y0 opcode.
284
+ class Y0 < ChangeRegister0
285
+ set_range 161
286
+ def interpret(ps)
287
+ # move down.
288
+ ps.v += ps.y
289
+ end
290
+ end
291
+
292
+ # Y is a class for y1 ... y4 opcodes.
293
+ class Y < ChangeRegister
294
+ set_range 162..165
295
+ def interpret(ps)
296
+ # change y.
297
+ ps.y = @size
298
+ # move down.
299
+ ps.v += @size
300
+ end
301
+ end
302
+
303
+ # Z0 is a class for z0 opcode.
304
+ class Z0 < ChangeRegister0
305
+ set_range 166
306
+
307
+ # Moves down processor's z.
308
+ def interpret(ps)
309
+ ps.v += ps.z
310
+ end
311
+ end
312
+
313
+ # Z is a class for z1 ... z4 opcode.
314
+ class Z < ChangeRegister
315
+ set_range 167..170
316
+
317
+ # Changes processor's z and moves down z.
318
+ def interpret(ps)
319
+ # change z.
320
+ ps.z = @size
321
+ # move down.
322
+ ps.v += @size
323
+ end
324
+ end
325
+
326
+ # FunNum is a class for fnt_num_0 ... fnt_num_63 opcodes.
327
+ class FntNum < Base
328
+ set_range 171..234
329
+ attr_reader :index
330
+
331
+ def initialize(index)
332
+ raise ArgumentError unless 0 <= index && index <= 63
333
+ @index = index
334
+ end
335
+
336
+ def self.read(cmd, io)
337
+ return self.new(cmd - 171)
338
+ end
339
+
340
+ # Changes the current processor's font.
341
+ # The font should be defined by fnt_def1 .. fnt_def4.
342
+ def interpret(ps)
343
+ raise Error unless ps.fonts.has_key?(@index)
344
+ ps.font = ps.fonts[@index]
345
+ end
346
+ end
347
+
348
+ # Fnt is a class for fnt1 ... fnt4 opcodes.
349
+ class Fnt < FntNum
350
+ set_range 235..238
351
+
352
+ def initialize(index, n)
353
+ unless case n
354
+ when 1; 0 <= index && index < 256
355
+ when 2; 0 <= index && index < 65536
356
+ when 3; 0 <= index && index < 16777216
357
+ when 4; -2147483648 <= index && index < 2147483648
358
+ else false end
359
+ raise ArgumentError
360
+ end
361
+ end
362
+
363
+ def self.read(cmd, io)
364
+ n = cmd - 234
365
+ f = if n < 4 then "read_uint" + n.to_s else "read_int" + n.to_s end
366
+ return self.new(io.__send__(f), n)
367
+ end
368
+ end
369
+
370
+ # XXX is a class for xxx1 ... xxx4 opcodes.
371
+ class XXX < Base
372
+ set_range 239..242
373
+ attr_reader :content
374
+
375
+ def initialize(content, n)
376
+ @content = content
377
+ end
378
+
379
+ def self.read(cmd, io)
380
+ n = cmd - 238
381
+ size = buf.__send__("read_uint" + n.to_s)
382
+ content = io.read(size)
383
+ return self.new(content, n)
384
+ end
385
+
386
+ # do nothing
387
+ def interpret(ps); end
388
+ end
389
+
390
+ # FntDef is a class for fnt_def1 ... fnt_def4 opcodes.
391
+ class FntDef < Base
392
+ set_range 243..246
393
+ attr_reader :num, :checksum, :scale, :design_size, :area, :fontname
394
+
395
+ def initialize(num, checksum, scale, design_size, area, fontname)
396
+ @num = num
397
+ @checksum = checksum
398
+ @scale = scale
399
+ @design_size = design_size
400
+ @area = area
401
+ @fontname = fontname
402
+ end
403
+
404
+ def self.read(cmd, io)
405
+ n = cmd - 242
406
+ num = if n < 4 then io.__send__("read_uint" + n.to_s) else io.read_int4 end
407
+ checksum = io.read_uint4
408
+ scale = io.read_uint4
409
+ design_size = io.read_uint4
410
+ a = io.read_uint1
411
+ l = io.read_uint1
412
+ area = io.read(a)
413
+ fontname = io.read(l)
414
+ return self.new(num, checksum, scale, design_size, area, fontname)
415
+ end
416
+
417
+ def interpret(ps)
418
+ tfm = Dvi::Tfm.read(ps.lsr.find(@fontname + ".tfm"))
419
+ ps.fonts[@num] =
420
+ Dvi::Font.new(@checksum, @scale, @design_size, @area, @fontname, tfm)
421
+ end
422
+ end
423
+
424
+ # Pre is a class for preamble opcode.
425
+ class Pre < Base
426
+ set_range 247
427
+ attr_reader :version, :num, :den, :mag, :comment
428
+
429
+ def initialize(version, num, den, mag, comment)
430
+ raise ArgumentError unless num > 0 && den > 0 && mag > 0
431
+ @version = version # maybe version is 2
432
+ @num = num # maybe 25400000 = 254cm
433
+ @den = den # maybe 473628672 = 7227*(2**16)
434
+ @mag = mag # mag / 1000
435
+ @comment = comment # not interpreted
436
+ end
437
+
438
+ def self.read(cmd, io)
439
+ version = io.read_uint1
440
+ num = io.read_uint4
441
+ den = io.read_uint4
442
+ mag = io.read_uint4
443
+ size = io.read_uint1
444
+ comment = io.read(size)
445
+ return self.new(version, num, den, mag, comment)
446
+ end
447
+
448
+ def interpret(ps)
449
+ ps.dvi_version = @version
450
+ ps.numerator = @num
451
+ ps.denominator = @den
452
+ ps.mag = @mag
453
+ end
454
+ end
455
+
456
+ # Post is a class for post opcode.
457
+ class Post < Base
458
+ set_range 248
459
+ attr_reader :final_bop, :num, :den, :mag, :l, :u, :stack_depath, :pages
460
+
461
+ def initialize(pointer, num, den, mag, l, u, stack_depth, total_pages)
462
+ @final_bop = pointer # final bop pointer
463
+ @num = num # same as preamble
464
+ @den = den # same as preamble
465
+ @mag = mag # same as preamble
466
+ @l = l # height plus depth of the tallest page
467
+ @u = u # width of the widest page
468
+ @stack_depth = stack_depth # maximum stack depth
469
+ @total_pages = total_pages # total number of pages
470
+ end
471
+
472
+ def self.read(cmd, io)
473
+ pointer = io.read_uint4
474
+ num = io.read_uint4
475
+ den = io.read_uint4
476
+ mag = io.read_uint4
477
+ l = io.read_uint4
478
+ u = io.read_uint4
479
+ stack_size = io.read_uint2
480
+ pages = io.read_uint2
481
+ return self.new(pointer, num, den, mag, l, u, stack_size, pages)
482
+ end
483
+
484
+ def interpret(ps)
485
+ ps.total_pages = @total_pages
486
+ end
487
+ end
488
+
489
+ # PostPost is a class for post_post opcode.
490
+ class PostPost < Base
491
+ set_range 249
492
+
493
+ def initialize(pointer)
494
+ @pointer = pointer # a pointer to the post command
495
+ end
496
+
497
+ def self.read(cmd, io) #:nodoc:
498
+ pointer = io.read_uint4
499
+ dvi_version = io.read_uint1
500
+ # read padding 233
501
+ io.read.unpack("C*").each do |i|
502
+ raise Error unless i == 223
503
+ end
504
+ return self.new(pointer)
505
+ end
506
+
507
+ def interpret(ps)
508
+ # ???
509
+ end
510
+ end
511
+
512
+ BASIC_OPCODES = [SetChar, Set, SetRule, Put, PutRule, Nop, Bop, Eop, Push, Pop,
513
+ Right, W0, W, X0, X, Down, Y0, Y, Z0, Z, FntNum, XXX, FntDef,
514
+ Pre, Post, PostPost]
515
+ end