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 +4 -0
- data/License.txt +56 -0
- data/Manifest.txt +37 -0
- data/README.txt +10 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +72 -0
- data/config/requirements.rb +17 -0
- data/lib/dvi.rb +99 -0
- data/lib/dvi/lsr.rb +41 -0
- data/lib/dvi/opcode.rb +515 -0
- data/lib/dvi/tfm.rb +68 -0
- data/lib/dvi/tfm/format.rb +290 -0
- data/lib/dvi/util.rb +37 -0
- data/lib/dvi/version.rb +9 -0
- data/log/debug.log +0 -0
- data/misc/latex/latex.dvi +0 -0
- data/misc/latex/latex.tex +4 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/spec/dvi_spec.rb +17 -0
- data/spec/lsr_spec.rb +11 -0
- data/spec/opcode_spec.rb +881 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/tfm_spec.rb +167 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/dvi.rake +16 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +17 -0
- data/website/index.html +119 -0
- data/website/index.txt +55 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +87 -0
data/History.txt
ADDED
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
data/Rakefile
ADDED
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
|