dvi 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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