1 /* dvipos-20070107
2
3 Copyright (C) 2003 by Jin-Hwan <chofchof@ktug.or.kr>
4
5 Includes two small fixes by Sanjoy Mahajan <sanjoy@mit.edu>. See
6 the ChangeLog.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 */
22
23 #include "utils.h"
24 #include "dvicore.h"
25 #include "tfm.h"
26
27 #include <math.h>
28 #include <time.h>
29
30 /* Global variables */
31 int dvi_pages = 0;
32
33 /* Internal variables */
34 static FILE *dvi_file;
35 static SIGNED_QUAD dvi_fsize, dvi_location;
36 static SIGNED_QUAD post_location, post_post_location, *page_location = NULL;
37 static SIGNED_QUAD prev_page_location = -1;
38 static int current_page, new_dvi_pages = 0;
39
40 #define DVI_MAX_STACK_DEPTH 256
41 static int dvi_stack_depth = 0;
42 static struct dvi_register {
43 SIGNED_QUAD h, v, w, x, y, z, d, hh, vv;
44 } dvi_state, dvi_stack[DVI_MAX_STACK_DEPTH];
45
46 static int cur_font = -1, num_dvi_fonts = 0, max_dvi_fonts = 0;
47 static struct dvi_font {
48 SIGNED_QUAD size, id; /* size == scaled_size */
49 int tfm_id, used; char *name;
50 } *dvi_fonts = NULL;
51
52 static SIGNED_QUAD numerator, denominator, dvi_mag, new_mag, mag;
53 static double tfm_conv, true_conv, conv, resolution;
54
55 static UNSIGNED_BYTE id;
56 static SIGNED_QUAD max_v, max_h, max_v_so_far, max_h_so_far;
57 static SIGNED_PAIR max_s, total_pages;
58 static SIGNED_PAIR max_s_so_far, page_count;
59
60 typedef struct a_bbox {
61 SIGNED_QUAD h1, v1, h2, v2, fb, cb; /* first and current baseline */
62 int type, lev_s;
63 char *tag;
64 struct a_bbox *next;
65 } BBOX;
66 static BBOX page_bbox;
67
68 static char comment[257];
69
70 /* Internal buffer */
71 #define DVI_BUFFER_SIZE 1024
72 static int dvi_buffer_len = 0;
73 static unsigned char dvi_buffer[DVI_BUFFER_SIZE];
74
calc_bbox(SIGNED_QUAD width,SIGNED_QUAD height,SIGNED_QUAD depth)75 static void calc_bbox (SIGNED_QUAD width, SIGNED_QUAD height, SIGNED_QUAD depth)
76 {
77 BBOX *bb = &page_bbox;
78
79 if (do_smashchars) height = depth = 0;
80
81 while (bb) {
82 if (bb->fb == -WEB_INFINITY) bb->fb = dvi_state.v;
83 bb->cb = dvi_state.v;
84 if (bb->h1 > dvi_state.h) bb->h1 = dvi_state.h;
85 if (bb->v1 > dvi_state.v - height) bb->v1 = dvi_state.v - height;
86 if (bb->h2 < dvi_state.h + width) bb->h2 = dvi_state.h + width;
87 if (bb->v2 < dvi_state.v + depth) bb->v2 = dvi_state.v + depth;
88 bb = bb->next;
89 }
90 }
91
92 #define PAGE_TYPE 0
93 #define BOX_TYPE 1
94 #define LINES_TYPE 2
95 #define LINES_TYPE_SUSPEND 3
96
draw_frame(BBOX * bb)97 static void draw_frame (BBOX *bb)
98 {
99 SIGNED_QUAD width, height;
100
101 width = bb->h2 - bb->h1 + 2 * rule_width;
102 height = bb->v2 - bb->v1 + 2 * rule_width;
103
104 /* color special */
105 put_unsigned_byte(XXX1, frmfp);
106 put_unsigned_byte(20, frmfp);
107 switch (bb->type) {
108 case BOX_TYPE:
109 fwrite("color push rgb 0 1 0", 1, 20, frmfp);
110 break;
111 case LINES_TYPE:
112 fwrite("color push rgb 0 0 1", 1, 20, frmfp);
113 break;
114 case PAGE_TYPE:
115 default:
116 fwrite("color push rgb 1 0 0", 1, 20, frmfp);
117 break;
118 }
119 dbg_location += 20;
120
121 /* push the current state */
122 put_unsigned_byte(PUSH, frmfp);
123
124 /* move to ll corner plus (-rule_width,rule_width) */
125 put_unsigned_byte(RIGHT4, frmfp);
126 put_signed_quad(-dvi_state.h + bb->h1 - rule_width, frmfp);
127 put_unsigned_byte(DOWN4, frmfp);
128 put_signed_quad(-dvi_state.v + bb->v2 + rule_width, frmfp);
129
130 /* draw a horizontal line connecting ll corner to lr corner */
131 put_unsigned_byte(PUT_RULE, frmfp);
132 put_signed_quad(rule_width, frmfp);
133 put_signed_quad(width, frmfp);
134
135 /* draw a vertical line connecting ll corner to ul corner */
136 put_unsigned_byte(PUT_RULE, frmfp);
137 put_signed_quad(height, frmfp);
138 put_signed_quad(rule_width, frmfp);
139
140 /* push the location of ll corner */
141 put_unsigned_byte(PUSH, frmfp);
142
143 /* move to ul corner plus (-rule_width,0) */
144 put_unsigned_byte(DOWN4, frmfp);
145 put_signed_quad(-bb->v2 + bb->v1 - rule_width, frmfp);
146
147 /* draw a horizontal line connecting ul corner to ur corner */
148 put_unsigned_byte(PUT_RULE, frmfp);
149 put_signed_quad(rule_width, frmfp);
150 put_signed_quad(width, frmfp);
151
152 /* restore the location of ll corner */
153 put_unsigned_byte(POP, frmfp);
154
155 /* move to lr corner plus (0,rule_width) */
156 put_unsigned_byte(RIGHT4, frmfp);
157 put_signed_quad(-bb->h1 + bb->h2 + rule_width, frmfp);
158
159 /* draw a vertical line connecting ll corner to ul corner */
160 put_unsigned_byte(PUT_RULE, frmfp);
161 put_signed_quad(height, frmfp);
162 put_signed_quad(rule_width, frmfp);
163
164 /* restore the original location */
165 put_unsigned_byte(POP, frmfp);
166
167 /* restore color special */
168 put_unsigned_byte(XXX1, frmfp);
169 put_unsigned_byte(9, frmfp);
170 fwrite("color pop", 1, 9, frmfp);
171 dbg_location += 9;
172 }
173
reset_bbox(BBOX * bb)174 static void reset_bbox (BBOX *bb)
175 {
176 bb->h1 = bb->v1 = WEB_INFINITY;
177 bb->h2 = bb->v2 = -WEB_INFINITY;
178 bb->fb = bb->cb = -WEB_INFINITY;
179 }
180
clear_bbox(int init)181 static void clear_bbox (int init)
182 {
183 /* calculate bounding box of each page */
184 reset_bbox(&page_bbox);
185 page_bbox.type = PAGE_TYPE;
186 if (init) {
187 page_bbox.tag = xstrdup("pagebb");
188 page_bbox.next = NULL;
189 }
190 }
191
new_bbox(char * tag,int type)192 static void new_bbox (char *tag, int type)
193 {
194 BBOX *bb = &page_bbox;
195
196 while (bb->next) {
197 // if (strcmp(tag, (bb->next)->tag) == 0) {
198 // msg_out(M_WARNING, "Warning: Found an entry with the same tag (%s).\n", tag);
199 // return;
200 // }
201 bb = bb->next;
202 }
203
204 /* allocate a new entry */
205 bb = bb->next = (BBOX *)xmalloc(sizeof(BBOX));
206 bb->tag = xstrdup(tag);
207 bb->next = NULL;
208 bb->lev_s = dvi_stack_depth;
209 bb->type = type;
210
211 reset_bbox(bb);
212
213 if (bbxfp && bb->type == LINES_TYPE)
214 fprintf(bbxfp, "\n## KEY & TAG\nbeglines & \"%s\"\n", bb->tag);
215 }
216
write_bbox(BBOX * bb)217 static void write_bbox (BBOX *bb)
218 {
219 if (bbxfp) {
220 fprintf(bbxfp, "\"%ld.%04lX & ",
221 (bb->fb / 65536), (bb->fb < 0 ? -1 : 1) * (bb->fb % 65536));
222 fprintf(bbxfp, "\"%ld.%04lX \"%ld.%04lX \"%ld.%04lX \"%ld.%04lX & ",
223 (bb->v1 / 65536), (bb->v1 < 0 ? -1 : 1) * (bb->v1 % 65536),
224 (bb->h1 / 65536), (bb->h1 < 0 ? -1 : 1) * (bb->h1 % 65536),
225 (bb->v2 / 65536), (bb->v2 < 0 ? -1 : 1) * (bb->v2 % 65536),
226 (bb->h2 / 65536), (bb->h2 < 0 ? -1 : 1) * (bb->h2 % 65536));
227 fprintf(bbxfp, "\"%ld.%04lX\n",
228 (bb->cb / 65536), (bb->cb < 0 ? -1 : 1) * (bb->cb % 65536));
229 /*
230 fprintf(bbxfp, "\"%ld & ", bb->fb);
231 fprintf(bbxfp, "\"%ld \"%ld \"%ld \"%ld & ", bb->v1, bb->h1, bb->v2, bb->h2);
232 fprintf(bbxfp, "\"%ld\n", bb->cb);
233 */
234 }
235 }
236
flush_bbox(BBOX * bb)237 static void flush_bbox (BBOX *bb)
238 {
239 if (bb == NULL) return;
240 if (frmfp) draw_frame(bb);
241 if (bbxfp) {
242 switch (bb->type) {
243 case PAGE_TYPE:
244 fprintf(bbxfp, "\n## KEY & PAGENO & ENTRY-V & TOP-V LEFT-H BOTTOM-V RIGHT-H & EXIT-V\n");
245 fprintf(bbxfp, "%s & %d & ", "pagebb", current_page);
246 write_bbox(bb);
247 break;
248 case BOX_TYPE:
249 fprintf(bbxfp, "\n## KEY & TAG & ENTRY-V & TOP-V LEFT-H BOTTOM-V RIGHT-H & EXIT-V\n");
250 fprintf(bbxfp, "%s & \"%s\" & ", "box", bb->tag);
251 write_bbox(bb);
252 break;
253 case LINES_TYPE:
254 fprintf(bbxfp, " %s & ", "line");
255 write_bbox(bb);
256 break;
257 case LINES_TYPE_SUSPEND:
258 bb->type = LINES_TYPE;
259 fprintf(bbxfp, "\n[resume]lines & \"%s\"\n", bb->tag);
260 fprintf(bbxfp, " %s & ", "line");
261 write_bbox(bb);
262 default:
263 break;
264 }
265 }
266 }
267
close_bbox(char * tag)268 static void close_bbox (char *tag)
269 {
270 BBOX *obb = &page_bbox, *nbb = obb->next;
271
272 /* find the entry with the same tag */
273 while (nbb)
274 if (strcmp(nbb->tag, tag) == 0) {
275 flush_bbox(nbb);
276 if (bbxfp && nbb->type == LINES_TYPE)
277 fprintf(bbxfp, "endlines & \"%s\"\n", nbb->tag);
278 free(nbb->tag);
279 obb->next = (nbb->next ? nbb->next : NULL);
280 free(nbb);
281 break;
282 } else {
283 if (bbxfp && nbb->type == LINES_TYPE) {
284 fprintf(bbxfp, "[suspend]lines & \"%s\"\n", nbb->tag);
285 nbb->type = LINES_TYPE_SUSPEND;
286 }
287 obb = nbb;
288 nbb = nbb->next;
289 }
290 }
291
dvi_unsigned_byte(void)292 static UNSIGNED_BYTE dvi_unsigned_byte (void)
293 {
294 dvi_location++;
295 return get_unsigned_byte(dvi_file);
296 }
297
dvi_signed_byte(void)298 static SIGNED_BYTE dvi_signed_byte (void)
299 {
300 dvi_location++;
301 return get_signed_byte(dvi_file);
302 }
303
dvi_unsigned_pair(void)304 static UNSIGNED_PAIR dvi_unsigned_pair (void)
305 {
306 dvi_location += 2;
307 return get_unsigned_pair(dvi_file);
308 }
309
dvi_signed_pair(void)310 static SIGNED_PAIR dvi_signed_pair (void)
311 {
312 dvi_location += 2;
313 return get_signed_pair(dvi_file);
314 }
315
dvi_unsigned_triple(void)316 static UNSIGNED_PAIR dvi_unsigned_triple (void)
317 {
318 dvi_location += 3;
319 return get_unsigned_triple(dvi_file);
320 }
321
dvi_signed_triple(void)322 static SIGNED_PAIR dvi_signed_triple (void)
323 {
324 dvi_location += 3;
325 return get_signed_triple(dvi_file);
326 }
327
328 #if 0
329 /* Not used */
330 static UNSIGNED_PAIR dvi_unsigned_quad (void)
331 {
332 dvi_location += 4;
333 return get_unsigned_quad(dvi_file);
334 }
335 #endif
336
dvi_signed_quad(void)337 static SIGNED_PAIR dvi_signed_quad (void)
338 {
339 dvi_location += 4;
340 return get_signed_quad(dvi_file);
341 }
342
sqxfw(SIGNED_QUAD z,SIGNED_QUAD b)343 static SIGNED_QUAD sqxfw (SIGNED_QUAD z, SIGNED_QUAD b)
344 {
345 SIGNED_QUAD alpha, beta, result;
346 UNSIGNED_BYTE b0, b1, b2, b3;
347
348 alpha = 16;
349 while (z >= 0x800000L) {
350 z = z / 2;
351 alpha = alpha + alpha;
352 }
353 beta = 256 / alpha;
354 alpha = alpha * z;
355
356 b0 = (b >> 24) & 0xFF; b1 = (b >> 16) & 0xFF;
357 b2 = (b >> 8) & 0xFF; b3 = b & 0xFF;
358
359 result = (((((b3 * z) / 0x100) + (b2 * z)) / 0x100) + (b1 * z)) / beta;
360
361 if (b0 == 255) result -= alpha;
362 else if (b0 != 0)
363 msg_out(M_FAIL, "[fatal] sqxfw(): TFM file is bad.\n");
364
365 return result;
366 }
367
xround(double p)368 static SIGNED_QUAD xround (double p)
369 {
370 if (p < 0)
371 return (SIGNED_QUAD)ceil(p - .5);
372 else
373 return (SIGNED_QUAD)floor(p + .5);
374 }
375
376 #define LINE_LENGTH 79
377 /* 69. The flush_text procedure will empty the buffer if there is something
378 * in it. */
flush_text(void)379 static void flush_text (void)
380 {
381 if (dvi_buffer_len > 0) {
382 dvi_buffer[dvi_buffer_len] = 0;
383 msg_out(M_DEBUG, "[%s]\n", dvi_buffer);
384 dvi_buffer_len = 0;
385 }
386 }
387
388 /* 70. And the out_text procedure puts something in it. */
out_text(char c)389 static void out_text (char c)
390 {
391 if (dvi_buffer_len == LINE_LENGTH - 2) flush_text();
392 dvi_buffer[dvi_buffer_len++] = c;
393 }
394
395 #define WEB_INFINITY 0x7FFFFFFFL //017777777777
396 #define MAX_DRIFT 2
397 #define PIXEL_ROUND(p) xround(conv*(p))
398
move_right(SIGNED_QUAD q)399 static void move_right (SIGNED_QUAD q)
400 {
401 SIGNED_QUAD h, hh, hhh;
402
403 h = dvi_state.h; hh = dvi_state.hh;
404
405 if (h > 0 && q > 0 && h > WEB_INFINITY - q) {
406 msg_out(M_DEBUG, " arithmetic overflow! parameter changed from '%ld' to '%ld'\n", q, WEB_INFINITY - h);
407 q = WEB_INFINITY - h;
408 }
409 if (h < 0 && q < 0 && -h > q + WEB_INFINITY) {
410 msg_out(M_DEBUG, " arithmetic overflow! parameter changed from '%ld' to '%ld'\n", q, (-h) - WEB_INFINITY);
411 q = (-h) - WEB_INFINITY;
412 }
413 hhh = PIXEL_ROUND(h + q);
414 if (labs(hhh - hh) > MAX_DRIFT) {
415 if (hhh > hh) hh = hhh - MAX_DRIFT;
416 else hh = hhh + MAX_DRIFT;
417 }
418 msg_out(M_DEBUG, " h:=%ld", h);
419 if (q >= 0) msg_out(M_DEBUG, "+");
420 msg_out(M_DEBUG, "%ld=%ld, hh:=%ld", q, h + q, hh);
421 h = h + q;
422 if (labs(h) > max_h_so_far) {
423 if (labs(h) > max_h + 99) {
424 msg_out(M_DEBUG, " warning: |h|>%ld!", max_h);
425 max_h = labs(h);
426 }
427 max_h_so_far = labs(h);
428 }
429 msg_out(M_DEBUG, " \n");
430 dvi_state.h = h; dvi_state.hh = hh;
431 }
432
433 /* 92. <Finish a command that sets v = v + p, then goto done> */
move_down(SIGNED_QUAD p)434 static void move_down (SIGNED_QUAD p)
435 {
436 SIGNED_QUAD v, vv, vvv;
437
438 v = dvi_state.v; vv = dvi_state.vv;
439
440 if (v > 0 && p > 0 && v > WEB_INFINITY - p) {
441 msg_out(M_DEBUG, " arithmetic overflow! parameter changed from '%ld' to '%ld'\n", p, WEB_INFINITY - v);
442 p = WEB_INFINITY - v;
443 }
444 if (v < 0 && p < 0 && -v > p + WEB_INFINITY) {
445 msg_out(M_DEBUG, " arithmetic overflow! parameter changed from '%ld' to '%ld'\n", p, (-v) - WEB_INFINITY);
446 p = (-v) - WEB_INFINITY;
447 }
448 vvv = PIXEL_ROUND(v + p);
449 if (labs(vvv - vv) > MAX_DRIFT) {
450 if (vvv > vv) vv = vvv - MAX_DRIFT;
451 else vv = vvv + MAX_DRIFT;
452 }
453 msg_out(M_DEBUG, " v:=%ld", v);
454 if (p >= 0) msg_out(M_DEBUG, "+");
455 msg_out(M_DEBUG, "%ld=%ld, vv:=%ld", p, v + p, vv);
456 v = v + p;
457 if (labs(v) > max_v_so_far) {
458 if (labs(v) > max_v + 99) {
459 msg_out(M_DEBUG, " warning: |v|>%ld!", max_v);
460 max_v = labs(v);
461 }
462 max_v_so_far = labs(v);
463 }
464 msg_out(M_DEBUG, " \n");
465 dvi_state.v = v; dvi_state.vv = vv;
466 }
467
468 /* 84. Rounding to the nearest pixel is best done in the manner shown here,
469 * so as to be inoffensive to the eye: When the horizontal motion is small,
470 * like a kern, hh changes by rounding the kern; but when the motion is
471 * large, hh changes by rounding the true position h so that accumulated
472 * rounding errors disappear. We allow a larger space in the negative
473 * direction than in the positive one, because \TeX{} makes comparatively
474 * large backspaces when it positions accents. */
out_space(SIGNED_QUAD p)475 static void out_space (SIGNED_QUAD p)
476 {
477 SIGNED_QUAD font_space;
478
479 font_space = (cur_font >= 0 ? dvi_fonts[cur_font].size / 6 : 0);
480
481 if (p >= font_space || p <= -4 * font_space) {
482 out_text(' ');
483 dvi_state.hh = PIXEL_ROUND(dvi_state.h + p);
484 } else
485 dvi_state.hh += PIXEL_ROUND(p);
486
487 move_right(p);
488 }
489
490 /* 85. Vertical motion is done similarly, but with the threshold between
491 * ``small'' and ``large'' increased by a factor of five. The idea is to
492 * make fractions like ``1\over2'' round consistently, but to absorb
493 * accumulated rounding errors in the baseline-skip moves. */
out_vmove(SIGNED_QUAD p)494 static void out_vmove (SIGNED_QUAD p)
495 {
496 SIGNED_QUAD font_space;
497
498 font_space = (cur_font >= 0 ? dvi_fonts[cur_font].size / 6 : 0);
499
500 if (labs(p) >= 5 * font_space)
501 dvi_state.vv = PIXEL_ROUND(dvi_state.v + p);
502 else
503 dvi_state.vv += PIXEL_ROUND(p);
504
505 move_down(p);
506 }
507
do_space(UNSIGNED_BYTE opcode)508 static void do_space (UNSIGNED_BYTE opcode)
509 {
510 SIGNED_QUAD x = 0; /* avoid uninitialized warning */
511
512 msg_out(M_DEBUG, "%ld: ", dvi_location);
513 switch (opcode) {
514 case RIGHT1:
515 x = dvi_signed_byte();
516 if (frmfp) put_signed_byte(x, frmfp);
517 msg_out(M_DEBUG, "right1");
518 break;
519 case RIGHT2:
520 x = dvi_signed_pair();
521 if (frmfp) put_signed_pair(x, frmfp);
522 msg_out(M_DEBUG, "right2");
523 break;
524 case RIGHT3:
525 x = dvi_signed_triple();
526 if (frmfp) put_signed_triple(x, frmfp);
527 msg_out(M_DEBUG, "right3");
528 break;
529 case RIGHT4:
530 x = dvi_signed_quad();
531 if (frmfp) put_signed_quad(x, frmfp);
532 msg_out(M_DEBUG, "right4");
533 break;
534 case W0:
535 x = dvi_state.w;
536 msg_out(M_DEBUG, "w0");
537 break;
538 case W1:
539 x = dvi_state.w = dvi_signed_byte();
540 if (frmfp) put_signed_byte(x, frmfp);
541 msg_out(M_DEBUG, "w1");
542 break;
543 case W2:
544 x = dvi_state.w = dvi_signed_pair();
545 if (frmfp) put_signed_pair(x, frmfp);
546 msg_out(M_DEBUG, "w2");
547 break;
548 case W3:
549 x = dvi_state.w = dvi_signed_triple();
550 if (frmfp) put_signed_triple(x, frmfp);
551 msg_out(M_DEBUG, "w3");
552 break;
553 case W4:
554 x = dvi_state.w = dvi_signed_quad();
555 if (frmfp) put_signed_quad(x, frmfp);
556 msg_out(M_DEBUG, "w4");
557 break;
558 case X0:
559 x = dvi_state.x;
560 msg_out(M_DEBUG, "x0");
561 break;
562 case X1:
563 x = dvi_state.x = dvi_signed_byte();
564 if (frmfp) put_signed_byte(x, frmfp);
565 msg_out(M_DEBUG, "x1");
566 break;
567 case X2:
568 x = dvi_state.x = dvi_signed_pair();
569 if (frmfp) put_signed_pair(x, frmfp);
570 msg_out(M_DEBUG, "x2");
571 break;
572 case X3:
573 x = dvi_state.x = dvi_signed_triple();
574 if (frmfp) put_signed_triple(x, frmfp);
575 msg_out(M_DEBUG, "x3");
576 break;
577 case X4:
578 x = dvi_state.x = dvi_signed_quad();
579 if (frmfp) put_signed_quad(x, frmfp);
580 msg_out(M_DEBUG, "x4");
581 break;
582 }
583 msg_out(M_DEBUG, " %ld", x);
584
585 if (!dvi_state.d)
586 out_space(x);
587 else
588 out_vmove(x);
589 }
590
do_vmove(UNSIGNED_BYTE opcode)591 static void do_vmove (UNSIGNED_BYTE opcode)
592 {
593 SIGNED_QUAD y = 0; /* avoid uninitialized warning */
594
595 flush_text();
596 msg_out(M_DEBUG, "%ld: ", dvi_location);
597 switch (opcode) {
598 case DOWN1:
599 y = dvi_signed_byte();
600 if (frmfp) put_signed_byte(y, frmfp);
601 msg_out(M_DEBUG, "down1");
602 break;
603 case DOWN2:
604 y = dvi_signed_pair();
605 if (frmfp) put_signed_pair(y, frmfp);
606 msg_out(M_DEBUG, "down2");
607 break;
608 case DOWN3:
609 y = dvi_signed_triple();
610 if (frmfp) put_signed_triple(y, frmfp);
611 msg_out(M_DEBUG, "down3");
612 break;
613 case DOWN4:
614 y = dvi_signed_quad();
615 if (frmfp) put_signed_quad(y, frmfp);
616 msg_out(M_DEBUG, "down4");
617 break;
618 case Y0:
619 y = dvi_state.y;
620 msg_out(M_DEBUG, "y0");
621 break;
622 case Y1:
623 y = dvi_state.y = dvi_signed_byte();
624 if (frmfp) put_signed_byte(y, frmfp);
625 msg_out(M_DEBUG, "y1");
626 break;
627 case Y2:
628 y = dvi_state.y = dvi_signed_pair();
629 if (frmfp) put_signed_pair(y, frmfp);
630 msg_out(M_DEBUG, "y2");
631 break;
632 case Y3:
633 y = dvi_state.y = dvi_signed_triple();
634 if (frmfp) put_signed_triple(y, frmfp);
635 msg_out(M_DEBUG, "y3");
636 break;
637 case Y4:
638 y = dvi_state.y = dvi_signed_quad();
639 if (frmfp) put_signed_quad(y, frmfp);
640 msg_out(M_DEBUG, "y4");
641 break;
642 case Z0:
643 y = dvi_state.z;
644 msg_out(M_DEBUG, "z0");
645 break;
646 case Z1:
647 y = dvi_state.z = dvi_signed_byte();
648 if (frmfp) put_signed_byte(y, frmfp);
649 msg_out(M_DEBUG, "z1");
650 break;
651 case Z2:
652 y = dvi_state.z = dvi_signed_pair();
653 if (frmfp) put_signed_pair(y, frmfp);
654 msg_out(M_DEBUG, "z2");
655 break;
656 case Z3:
657 y = dvi_state.z = dvi_signed_triple();
658 if (frmfp) put_signed_triple(y, frmfp);
659 msg_out(M_DEBUG, "z3");
660 break;
661 case Z4:
662 y = dvi_state.z = dvi_signed_quad();
663 if (frmfp) put_signed_pair(y, frmfp);
664 msg_out(M_DEBUG, "z4");
665 break;
666 }
667 msg_out(M_DEBUG, " %ld", y);
668
669 if (!dvi_state.d)
670 out_vmove(y);
671 else
672 out_space(-y);
673 }
674
675 #define RULE_PIXELS(p) (SIGNED_QUAD)ceil(conv*(p))
676
677 /* 90. <Finish a command that either sets or puts a rule, then goto
678 * move_right or done> */
do_rule(UNSIGNED_BYTE opcode)679 static void do_rule (UNSIGNED_BYTE opcode)
680 {
681 SIGNED_QUAD width, height;
682
683 flush_text();
684 switch (opcode) {
685 case SET_RULE:
686 msg_out(M_DEBUG, "%ld: setrule", dvi_location);
687 break;
688 case PUT_RULE:
689 msg_out(M_DEBUG, "%ld: putrule", dvi_location);
690 break;
691 }
692
693 height = dvi_signed_quad(); width = dvi_signed_quad();
694 if (frmfp) {
695 put_signed_quad(height, frmfp); put_signed_quad(width, frmfp);
696 }
697 msg_out(M_DEBUG, " height %ld width %ld", height, width);
698 if (height <= 0 || width <= 0)
699 msg_out(M_DEBUG, " (invisible) \n");
700 else {
701 msg_out(M_DEBUG, " %ldx%ld pixels \n", RULE_PIXELS(height), RULE_PIXELS(width));
702 calc_bbox(width, height, 0);
703 }
704
705 /*
706 * SET_RULE: Typeset a solid black rectangle of height |a| and width |b|,
707 * with its bottom left corner at |(h,v)|. Then set |h:=h+b|. If either
708 * |a<=0| or |b<=0|, nothing should be typeset. Note that if |b<0|, the
709 * value of |h| will decrease even though nothing else happens.
710 */
711 if (opcode == SET_RULE) {
712 dvi_state.hh += RULE_PIXELS(width);
713 move_right(width);
714 }
715 }
716
717 /* 89. <Finish a command that either sets or puts a character, then
718 * goto move_right or done> */
fin_set(UNSIGNED_BYTE p,int move)719 static void fin_set (UNSIGNED_BYTE p, int move)
720 {
721 SIGNED_QUAD width, height, depth;
722
723 if (cur_font < 0)
724 msg_out(M_FAIL, "[fatal] fin_set(): No font selected.\n");
725
726 width = sqxfw(dvi_fonts[cur_font].size, tfm_get_fw_width(dvi_fonts[cur_font].tfm_id, p));
727 height = sqxfw(dvi_fonts[cur_font].size, tfm_get_fw_height(dvi_fonts[cur_font].tfm_id, p));
728 depth = sqxfw(dvi_fonts[cur_font].size, tfm_get_fw_depth(dvi_fonts[cur_font].tfm_id, p));
729
730 calc_bbox(width, height, depth);
731
732 if (!move) return;
733
734 if (!dvi_state.d) {
735 dvi_state.hh += PIXEL_ROUND(width);
736 move_right(width);
737 } else {
738 dvi_state.vv += PIXEL_ROUND(width);
739 move_down(width);
740 }
741 }
742
743 /* 88. Translate a set_char command. */
do_setchar(UNSIGNED_BYTE opcode)744 static void do_setchar (UNSIGNED_BYTE opcode)
745 {
746 if (opcode > 32 && opcode < 127) /* from '!' to '~' */
747 out_text((char)(opcode - SET_CHAR_0));
748 else
749 flush_text();
750 msg_out(M_DEBUG, "%ld: setchar%d", dvi_location, opcode - SET_CHAR_0);
751
752 fin_set(opcode - SET_CHAR_0, 1);
753 }
754
755 /* 89. <Finish a command that either sets or puts a character, then
756 * goto move_right or done> */
do_set(UNSIGNED_BYTE opcode)757 static void do_set (UNSIGNED_BYTE opcode)
758 {
759 SIGNED_QUAD ch = 0; /* avoid uninitialized warning */
760
761 flush_text();
762 msg_out(M_DEBUG, "%ld: ", dvi_location);
763
764 switch (opcode) {
765 case SET1:
766 ch = dvi_unsigned_byte();
767 if (frmfp) put_unsigned_byte(ch, frmfp);
768 break;
769 case SET2:
770 ch = dvi_unsigned_pair();
771 if (frmfp) put_unsigned_pair(ch, frmfp);
772 break;
773 case SET3:
774 ch = dvi_unsigned_triple();
775 if (frmfp) put_unsigned_triple(ch, frmfp);
776 break;
777 case SET4:
778 ch = dvi_signed_quad();
779 if (frmfp) put_signed_quad(ch, frmfp);
780 break;
781 }
782 msg_out(M_DEBUG, " set%c %ld ", '1' + (opcode - SET1), ch);
783
784 fin_set(ch, 1);
785 }
786
787 /* 89. <Finish a command that either sets or puts a character, then
788 * goto move_right or done> */
do_put(UNSIGNED_BYTE opcode)789 static void do_put (UNSIGNED_BYTE opcode)
790 {
791 SIGNED_QUAD ch = 0; /* avoid uninitialized warning */
792
793 flush_text();
794 msg_out(M_DEBUG, "%ld: ", dvi_location);
795 switch (opcode) {
796 case PUT1:
797 ch = dvi_unsigned_byte();
798 if (frmfp) put_unsigned_byte(ch, frmfp);
799 break;
800 case PUT2:
801 ch = dvi_unsigned_pair();
802 if (frmfp) put_unsigned_pair(ch, frmfp);
803 break;
804 case PUT3:
805 ch = dvi_unsigned_triple();
806 if (frmfp) put_unsigned_triple(ch, frmfp);
807 break;
808 case PUT4:
809 ch = dvi_signed_quad();
810 if (frmfp) put_signed_quad(ch, frmfp);
811 break;
812 }
813 msg_out(M_DEBUG, " put%c %ld ", '1' + (opcode - PUT1), ch);
814
815 fin_set(ch, 0);
816 }
817
show_state(void)818 static void show_state (void)
819 {
820 msg_out(M_DEBUG, "level %d:(h=%ld,v=%ld,w=%ld,x=%ld,y=%ld,z=%ld,hh=%ld,vv=%ld) \n", dvi_stack_depth, dvi_state.h, dvi_state.v, dvi_state.w, dvi_state.x, dvi_state.y, dvi_state.z, dvi_state.hh, dvi_state.vv);
821 }
822
do_push(void)823 static void do_push (void)
824 {
825 flush_text();
826 msg_out(M_DEBUG, "%ld: push \n", dvi_location);
827 show_state();
828 if (dvi_stack_depth < DVI_MAX_STACK_DEPTH)
829 dvi_stack[dvi_stack_depth++] = dvi_state;
830 else
831 msg_out(M_FAIL, "[fatal] do_push(): DVI stack exceeded.\n");
832 }
833
do_pop(void)834 static void do_pop (void)
835 {
836 BBOX *bb;
837
838 if (dvi_stack_depth > 0)
839 dvi_state = dvi_stack[--dvi_stack_depth];
840 else
841 msg_out(M_FAIL, "[fatal] do_pop(): Tried to pop an empty stack.\n");
842 flush_text();
843 msg_out(M_DEBUG, "%ld: pop \n", dvi_location);
844 show_state();
845
846 /* reset bounding boxes */
847 bb = page_bbox.next;
848 while (bb) {
849 if (bb->lev_s == dvi_stack_depth + 1 && bb->type == LINES_TYPE) {
850 flush_bbox(bb);
851 reset_bbox(bb);
852 }
853 bb = bb->next;
854 }
855 }
856
do_fnt_num(UNSIGNED_BYTE opcode)857 static void do_fnt_num (UNSIGNED_BYTE opcode)
858 {
859 register int i;
860 SIGNED_QUAD id = 0; /* avoid uninitialized warning */
861
862 flush_text();
863 msg_out(M_DEBUG, "%ld: ", dvi_location);
864 if (opcode >= FNT_NUM_0 && opcode <= FNT_NUM_63) {
865 id = opcode - FNT_NUM_0;
866 msg_out(M_DEBUG, "fntnum%ld ", id);
867 } else {
868 switch (opcode) {
869 case FNT1:
870 id = dvi_unsigned_byte();
871 if (frmfp) put_unsigned_byte(id, frmfp);
872 break;
873 case FNT2:
874 id = dvi_unsigned_pair();
875 if (frmfp) put_unsigned_pair(id, frmfp);
876 break;
877 case FNT3:
878 id = dvi_unsigned_triple();
879 if (frmfp) put_unsigned_triple(id, frmfp);
880 break;
881 case FNT4:
882 id = dvi_signed_quad();
883 if (frmfp) put_signed_quad(id, frmfp);
884 break;
885 }
886 msg_out(M_DEBUG, "fnt%c %ld ", '1' + (opcode - FNT1), id);
887 }
888
889 for (i = 0; i < num_dvi_fonts; i++)
890 if (dvi_fonts[i].id == id) break;
891
892 if (i == num_dvi_fonts)
893 msg_out(M_FAIL, "[fatal] do_fnt_num(): Tried to select a font (ID %ld) that hasn't been defined.\n", id);
894
895 msg_out(M_DEBUG, "current font is %s \n", dvi_fonts[i].name);
896
897 if (!dvi_fonts[i].used) {
898 dvi_fonts[i].tfm_id = tfm_open(dvi_fonts[i].name, 1);
899 dvi_fonts[i].used = 1;
900 }
901
902 cur_font = i;
903 }
904
do_pos_special(unsigned char * buffer,SIGNED_QUAD buffer_len)905 static void do_pos_special (unsigned char *buffer, SIGNED_QUAD buffer_len)
906 {
907 unsigned char *cmd, *tag, *p;
908 SIGNED_QUAD x, y;
909 SIGNED_QUAD w = 0, h = 0, d = 0; /* avoid uninitialized warning */
910 double w_pt, h_pt, d_pt; /* in pt */
911 int parsed = 0; /* how many conversions the sscanf managed */
912
913 struct /* see \doregisterparoptions in ConTeXt's core-pos.tex */
914 {
915 double hsize, leftskip, rightskip, hangindent, parindent;
916 SIGNED_QUAD hangafter;
917 } list;
918
919 for (p = buffer; p - buffer < buffer_len && isspace(*p); p++)
920 ; /* skip white chars */
921 if (strncmp((char *)p, "pos:", 4)) return;
922
923 for (cmd = p; p - buffer < buffer_len && !isspace(*p); p++)
924 ; /* retrieve POS command */
925
926 for (*p++ = 0; p - buffer < buffer_len && isspace(*p); p++)
927 ; /* skip white chars */
928
929 /* retrieve POS identification */
930 if (*p == '"')
931 for (tag = ++p; p - buffer < buffer_len && *p != '"'; p++);
932 else
933 for (tag = p; p - buffer < buffer_len && !isspace(*p); p++);
934 *p = 0;
935
936 for (p++; p - buffer < buffer_len && isspace(*p); p++)
937 ; /* skip white chars */
938 if (p - buffer < buffer_len)
939 {
940 /* hangafter is a number, not a dimension, hence its %ld */
941 parsed = sscanf((char *)p, "%lfpt %lfpt %lfpt %lfpt,%lfpt,%lfpt,%lfpt,%ld,%lfpt",
942 &w_pt, &h_pt, &d_pt,
943 &list.hsize, &list.leftskip, &list.rightskip,
944 &list.hangindent, &list.hangafter, &list.parindent);
945 /* convert pt to sp. Forget about rounding (add 0.5 if you want it). */
946 w = w_pt * 65536;
947 h = h_pt * 65536;
948 d = d_pt * 65536;
949 }
950
951 x = dvi_state.h + denominator / 100;
952 y = max_v - dvi_state.v;
953
954 if (strcmp((char *)cmd, "pos:pxy") == 0)
955 fprintf(outfp, "\\pospxy{%s}{%d}{%ldsp}{%ldsp}\n", tag, current_page, x, y);
956 else if (strcmp((char *)cmd, "pos:pxywhd") == 0)
957 fprintf(outfp, "\\pospxywhd{%s}{%d}{%ldsp}{%ldsp}{%ldsp}{%ldsp}{%ldsp}\n", tag, current_page, x, y, w, h, d);
958 else if (strcmp((char *)cmd, "pos:pxyplus") == 0) {
959 if (parsed < 9)
960 fprintf(stderr, "dvipos: only %d conversions for \\pospxyplus but 9 are needed\nBeward: Coordinates in the output may therefore be junk. Continuing anyway...", parsed);
961 fprintf(outfp, "\\pospxyplus{%s}{%d}{%ldsp}{%ldsp}{%ldsp}{%ldsp}{%ldsp}", tag, current_page, x, y, w, h, d);
962 fprintf(outfp, "{%lfpt,%lfpt,%lfpt,%lfpt,%ld,%lfpt}\n",
963 list.hsize, list.leftskip, list.rightskip,
964 list.hangindent, list.hangafter, list.parindent);
965 }
966 else if (strcmp((char *)cmd, "pos:begbox") == 0)
967 new_bbox((char *)tag, BOX_TYPE);
968 else if (strcmp((char *)cmd, "pos:endbox") == 0)
969 close_bbox((char *)tag);
970 else if (strcmp((char *)cmd, "pos:beglines") == 0)
971 new_bbox((char *)tag, LINES_TYPE);
972 else if (strcmp((char *)cmd, "pos:endlines") == 0)
973 close_bbox((char *)tag);
974 }
975
do_xxx(UNSIGNED_BYTE opcode)976 static void do_xxx (UNSIGNED_BYTE opcode)
977 {
978 SIGNED_QUAD size = 0; /* avoid uninitialized warning */
979 unsigned char *sp_buf;
980
981 flush_text();
982 msg_out(M_DEBUG, "%ld: xxx ", dvi_location);
983 switch (opcode) {
984 case XXX1:
985 size = dvi_unsigned_byte();
986 if (frmfp) put_unsigned_byte(size, frmfp);
987 break;
988 case XXX2:
989 size = dvi_unsigned_pair();
990 if (frmfp) put_unsigned_pair(size, frmfp);
991 break;
992 case XXX3:
993 size = dvi_unsigned_triple();
994 if (frmfp) put_unsigned_triple(size, frmfp);
995 break;
996 case XXX4:
997 size = dvi_signed_quad();
998 if (frmfp) put_signed_quad(size, frmfp);
999 break;
1000 }
1001
1002 sp_buf = (unsigned char *)calloc(size+1, sizeof(unsigned char));
1003 if (fread(sp_buf, sizeof(unsigned char), size, dvi_file) != size)
1004 msg_out(M_FAIL, "[fatal] do_xxx(): Failed to read the special commands with size %d.\n", size);
1005 if (frmfp) {
1006 fwrite(sp_buf, sizeof(unsigned char), size, frmfp);
1007 dbg_location += size;
1008 }
1009
1010 msg_out(M_DEBUG, "'%s' \n", sp_buf);
1011 dvi_location += size;
1012
1013 do_pos_special(sp_buf, size); /* defined in dvispec.c */
1014
1015 free(sp_buf);
1016 }
1017
dvi_clear_state(void)1018 static void dvi_clear_state (void)
1019 {
1020 cur_font = -1; /* set current font undefined */
1021 dvi_stack_depth = 0;
1022 dvi_state.h = 0; dvi_state.v = 0; dvi_state.w = 0;
1023 dvi_state.x = 0; dvi_state.y = 0; dvi_state.z = 0;
1024 dvi_state.hh = 0; dvi_state.vv = 0;
1025 dvi_state.d = 0; /* direction for ASCII pTeX */
1026 }
1027
do_bop(void)1028 static void do_bop (void)
1029 {
1030 int i;
1031
1032 msg_out(M_DEBUG, " \n%ld: beginning of page %d \n", dvi_location, current_page);
1033 if (frmfp) {
1034 for (i = 0; i < 10; i++) put_signed_quad(dvi_signed_quad(), frmfp);
1035 /* the previous page location */
1036 dvi_signed_quad();
1037 put_signed_quad(prev_page_location, frmfp);
1038 prev_page_location = dbg_location - 45;
1039 } else
1040 for (i = 0; i < 11; i++) dvi_signed_quad();
1041 dvi_clear_state();
1042 clear_bbox(0);
1043 }
1044
do_eop(void)1045 static void do_eop (void)
1046 {
1047 BBOX *bb;
1048
1049 flush_text();
1050 msg_out(M_DEBUG, "%ld: eop ", dvi_location);
1051 msg_out(M_DEBUG, "[%ld %ld %ld %ld]", page_bbox.h1, page_bbox.v1, page_bbox.h2, page_bbox.v2);
1052
1053 /* reset bounding boxes */
1054 bb = page_bbox.next;
1055 while (bb) {
1056 reset_bbox(bb);
1057 bb = bb->next;
1058 }
1059
1060 flush_bbox(&page_bbox);
1061 if (frmfp) put_unsigned_byte(EOP, frmfp);
1062 }
1063
do_dir(void)1064 static void do_dir (void)
1065 {
1066 dvi_state.d = dvi_unsigned_byte();
1067 if (frmfp) put_unsigned_byte(dvi_state.d, frmfp);
1068 msg_out(M_DEBUG, "%ld: dir %d \n", dvi_location-1, dvi_state.d);
1069 }
1070
do_fnt_def(UNSIGNED_BYTE opcode)1071 static void do_fnt_def (UNSIGNED_BYTE opcode)
1072 {
1073 register int dlen, flen;
1074 SIGNED_QUAD id;
1075 char *fnt_buf;
1076
1077 flush_text();
1078 switch (opcode) {
1079 case FNT_DEF1:
1080 id = dvi_unsigned_byte();
1081 if (frmfp) put_unsigned_byte(id, frmfp);
1082 msg_out(M_DEBUG, "%ld: fntdef1 %ld: ", dvi_location-1, id);
1083 break;
1084 case FNT_DEF2:
1085 id = dvi_unsigned_pair();
1086 if (frmfp) put_unsigned_pair(id, frmfp);
1087 msg_out(M_DEBUG, "%ld: fntdef2 %ld: ", dvi_location-2, id);
1088 break;
1089 case FNT_DEF3:
1090 id = dvi_unsigned_triple();
1091 if (frmfp) put_unsigned_triple(id, frmfp);
1092 msg_out(M_DEBUG, "%ld: fntdef3 %ld: ", dvi_location-3, id);
1093 break;
1094 case FNT_DEF4:
1095 id = dvi_signed_quad();
1096 if (frmfp) put_signed_quad(id, frmfp);
1097 msg_out(M_DEBUG, "%ld: fntdef4 %ld: ", dvi_location-4, id);
1098 break;
1099 }
1100
1101 /* the checksum that TeX found in the TFM file for this font */
1102 if (frmfp) put_signed_quad(dvi_signed_quad(), frmfp);
1103 else dvi_signed_quad();
1104 /* a fixed-point scale factor */
1105 if (frmfp) put_signed_quad(dvi_signed_quad(), frmfp);
1106 else dvi_signed_quad();
1107 /* the "design size" */
1108 if (frmfp) put_signed_quad(dvi_signed_quad(), frmfp);
1109 else dvi_signed_quad();
1110 /* the length of the "area" or directory */
1111 dlen = dvi_unsigned_byte();
1112 if (frmfp) put_unsigned_byte(dlen, frmfp);
1113 /* the length of the font name itself */
1114 flen = dvi_unsigned_byte();
1115 if (frmfp) put_unsigned_byte(flen, frmfp);
1116
1117 /* the external name of the font */
1118 fnt_buf = (char *)calloc(dlen+flen+1, sizeof(char));
1119 flen = fread(fnt_buf, sizeof(char), dlen+flen, dvi_file);
1120 if (frmfp) {
1121 fwrite(fnt_buf, sizeof(char), flen, frmfp);
1122 dbg_location += flen;
1123 }
1124 fnt_buf[flen] = 0;
1125 msg_out(M_DEBUG, "%s \n", fnt_buf);
1126 dvi_location += flen;
1127 free(fnt_buf);
1128 }
1129
1130 /* 110. The conversion factor \emph{conv} is figured as follows: There are
1131 * exactly $n/d$ decimicrons per DVI unit, and 254000 decimicrons per inch,
1132 * and \emph{resolution} pixels per inch. Then we have to adjust this by
1133 * the stated amount of magnification. */
compute_conversion_factors(void)1134 static void compute_conversion_factors (void)
1135 {
1136 if ((numerator = dvi_signed_quad()) <= 0)
1137 msg_out(M_FAIL, "Bad DVI file: numerator is %d!\n", numerator);
1138
1139 if ((denominator = dvi_signed_quad()) <= 0)
1140 msg_out(M_FAIL, "Bad DVI file: denominator is %d!\n", denominator);
1141
1142 msg_out(M_DEBUG, "numerator/denominator=%ld/%ld\n", numerator, denominator);
1143
1144 tfm_conv = ((double)25400000.0/numerator) * (denominator/(double)473628672)/16.0;
1145 conv = (numerator/(double)254000.0) * (resolution/denominator);
1146
1147 dvi_mag = mag = dvi_signed_quad();
1148 if (new_mag > 0)
1149 mag = new_mag; /* override the existing maginification */
1150 else if (mag <= 0)
1151 msg_out(M_FAIL, "Bad DVI file: magnification is %d!\n", mag);
1152
1153 true_conv = conv;
1154 conv = true_conv * (mag/(double)1000.0);
1155
1156 msg_out(M_DEBUG, "magnification=%ld; %16.8f pixels per DVI unit\n", mag, conv);
1157 }
1158
1159 /* 109. A DVI-reading program that reads the postamble first need not look
1160 * at the preamble; but DVItype looks at the preamble in order to do error
1161 * checking, and to display the introductory comment. */
process_preamble(void)1162 static void process_preamble (void)
1163 {
1164 fseek(dvi_file, 0L, SEEK_SET);
1165
1166 /* fetch the first byte */
1167 if (dvi_unsigned_byte() != PRE)
1168 msg_out(M_FAIL, "First byte isn't start of preamble!\n");
1169 /* fetch the identification byte */
1170 if ((id = dvi_unsigned_byte()) != DVI_ID && id != DVIV_ID)
1171 msg_out(M_FAIL, "identification in byte 1 should be %d or %d.\n", DVI_ID, DVIV_ID);
1172
1173 compute_conversion_factors();
1174
1175 /* fetch the introductory comment */
1176 comment[fread(comment, sizeof(char), dvi_unsigned_byte(), dvi_file)] = 0;
1177 msg_out(M_DEBUG, "'%s'\n", comment);
1178 }
1179
1180 /* 19. The last page in a DVI file is followed by `\emph{post}'; this command
1181 * introduces the postamble, which summarizes important facts that \TeX{} has
1182 * accumulated about the file, making it possible to print subsets of the data
1183 * with reasonable efficiency. The postamble has the form
1184 *
1185 * post p[4] num[4] den[4] mag[4] l[4] u[4] s[2] t[2]
1186 * <font definitions>
1187 * post_post q[4] i[1] 223's[>=4]
1188 *
1189 * Here $p$ is a pointer to the final bop in the file. The next three
1190 * parameters, $num$, $den$, and $mag$, are duplicates of the quantities that
1191 * appeared in the preamble.
1192 */
1193
1194 /* 103. Reading the postamble. Now imagine that we are reading the DVI file
1195 * and positioned just four bytes after the \emph{post} command. That,
1196 * in fact, is the situation, when the following part of DVItype is called
1197 * upon to read, translate, and check the rest of the postamble. */
1198
1199 /* 20. The curious way to finish off a DVI file makes it feasible for
1200 * DVI-reading programs to find the postamble first, on most computers,
1201 * even though \TeX{} wants to write the postamble last. Most operating
1202 * systems permit random access to individual words or bytes of a file,
1203 * so the DVI reader can start at the end and skip backwards over the
1204 * 223's until finding the identification byte. Then it can back up four
1205 * bytes, read $q$, and move to byte $q$ of the file. This byte should,
1206 * of course, contain the value 248 (\emph{post}); now the postamble can
1207 * be read, so the DVI reader discovers all the information needed for
1208 * typesetting the pages. Note that it is also possible to skip through
1209 * the DVI file at reasonably high speed to locate a particular page,
1210 * if that proves desirable. This saves a lot of time, since DVI files
1211 * used in production jobs tend to be large. */
read_postamble(void)1212 static void read_postamble (void)
1213 {
1214 UNSIGNED_BYTE opcode;
1215 SIGNED_QUAD current_location = dvi_fsize;
1216
1217 /* scan backwards through PADDING */
1218 do {
1219 current_location--;
1220 fseek(dvi_file, current_location, SEEK_SET);
1221 } while((opcode = dvi_unsigned_byte()) == PADDING && current_location > 0);
1222
1223 /* current_location now points to the identification byte */
1224 if (dvi_fsize <= current_location + 4)
1225 msg_out(M_FAIL, "Bad DVI file: not enough signature bytes at end of file (%ld)\n", dvi_fsize - current_location - 1);
1226
1227 post_post_location = current_location - 5;
1228 fseek(dvi_file, post_post_location, SEEK_SET);
1229 if ((opcode = dvi_unsigned_byte()) != POST_POST)
1230 msg_out(M_FAIL, "[fatal] Found (%d) where POST_POST should be.\n", opcode);
1231
1232 /* now points to the pointer $q$ to the \emph{post} command */
1233 post_location = dvi_signed_quad();
1234 fseek(dvi_file, post_location, SEEK_SET);
1235 if ((opcode = dvi_unsigned_byte()) != POST)
1236 msg_out(M_FAIL, "[fatal] Found (%d) where POST should be\n", opcode);
1237
1238 msg_out(M_DEBUG, "Postamble starts at byte %ld.\n", post_location);
1239
1240 dvi_signed_quad(); /* skip the first four bytes; p[4] */
1241
1242 if (dvi_signed_quad() != numerator)
1243 msg_out(M_FAIL, "Bad DVI file: numerator doesn't match the preamble!\n");
1244
1245 if (dvi_signed_quad() != denominator)
1246 msg_out(M_FAIL, "Bad DVI file: denominator doesn't match the preamble!\n");
1247
1248 if (dvi_signed_quad() != mag && new_mag == 0)
1249 msg_out(M_FAIL, "Bad DVI file: magnification doesn't match the preamble!\n");
1250
1251 max_v = dvi_signed_quad();
1252 max_h = dvi_signed_quad();
1253 msg_out(M_DEBUG, "maxv=%ld, maxh=%ld, ", max_v, max_h);
1254
1255 if ((max_s = dvi_signed_pair()) > DVI_MAX_STACK_DEPTH)
1256 msg_out(M_FAIL, "[fatal] maxstackdepth %d exceeds DVI_MAX_STACK_DEPTH %d\n", max_s, DVI_MAX_STACK_DEPTH);
1257 total_pages = dvi_signed_pair();
1258 msg_out(M_DEBUG, "maxstackdepth=%d, totalpages=%d\n", max_s, total_pages);
1259 }
1260
find_page_location(void)1261 static void find_page_location (void)
1262 {
1263 int i;
1264
1265 /* Read the total page number */
1266 fseek(dvi_file, post_location+27, SEEK_SET);
1267 if ((dvi_pages = dvi_unsigned_pair()) == 0)
1268 msg_out(M_FAIL, "[fatal] Total page number is zero.\n");
1269
1270 /* Read the location of each page */
1271 page_location = (SIGNED_QUAD *)calloc(dvi_pages, sizeof(SIGNED_QUAD));
1272 fseek(dvi_file, post_location+1, SEEK_SET);
1273 page_location[dvi_pages-1] = dvi_signed_quad();
1274 if (page_location[dvi_pages-1] + 41 > dvi_fsize)
1275 msg_out(M_FAIL, "[fatal] The location of the page %d was broken.\n", dvi_pages);
1276 for (i = dvi_pages-2; i >= 0; i--) {
1277 fseek(dvi_file, page_location[i+1] + 41, SEEK_SET);
1278 page_location[i] = dvi_signed_quad();
1279 if (page_location[i] + 41 > dvi_fsize)
1280 msg_out(M_FAIL, "[fatal] The location of the page %d was broken.\n", i+1);
1281 }
1282 }
1283
1284 /* 59. The following subroutine does the necessary things when a fnt_def
1285 * command is being processed. */
define_font(SIGNED_QUAD e)1286 static void define_font (SIGNED_QUAD e)
1287 {
1288 SIGNED_QUAD q, d, m;
1289 int p, n;
1290 char *name;
1291
1292 if (num_dvi_fonts >= max_dvi_fonts) {
1293 max_dvi_fonts += MAX_FONTS_STEP;
1294 dvi_fonts = (struct dvi_font *)realloc(dvi_fonts, max_dvi_fonts * sizeof(struct dvi_font));
1295 }
1296
1297 dvi_signed_quad(); /* font_check_sum */
1298 q = dvi_signed_quad(); /* font_scaled_size */
1299 d = dvi_signed_quad(); /* font_design_size */
1300
1301 if (q <= 0 || d <= 0) m = 1000;
1302 else m = xround((1000.0*conv*q)/(true_conv*d));
1303
1304 p = dvi_unsigned_byte();
1305 n = dvi_unsigned_byte();
1306
1307 msg_out(M_DEBUG, "Font %ld: ", e);
1308
1309 /* Retrieve the directory name and the font name */
1310 name = (char *)calloc(p+n+1, sizeof(char));
1311 if (p + n > 0) {
1312 if (fread(name, sizeof(char), p+n, dvi_file) != p+n)
1313 msg_out(M_FAIL, "[fatal] Failed to retrieve a font name.\n");
1314 }
1315 name[p+n] = 0;
1316
1317 msg_out(M_DEBUG, "%s", (p + n > 0 ? name : "null font name!"));
1318
1319 if (m != 1000)
1320 msg_out(M_DEBUG, " scaled %ld", m);
1321
1322 dvi_fonts[num_dvi_fonts].name = name;
1323 dvi_fonts[num_dvi_fonts].size = q; /* scaled_size */
1324 dvi_fonts[num_dvi_fonts].id = e;
1325 dvi_fonts[num_dvi_fonts].used = 0;
1326
1327 msg_out(M_DEBUG, "---loaded at size %ld DVI units \n", q);
1328 d = xround((100.0*conv*q)/(true_conv*d));
1329 if (d != 100)
1330 msg_out(M_DEBUG, " (this font is magnified %ld%c) \n", d, '%');
1331
1332 num_dvi_fonts++;
1333 }
1334
process_fonts(void)1335 static void process_fonts (void)
1336 {
1337 UNSIGNED_BYTE opcode;
1338 // fseek(dvi_file, post_location+29, SEEK_SET);
1339 while ((opcode = dvi_unsigned_byte()) != POST_POST)
1340 switch (opcode) {
1341 case FNT_DEF1: define_font(dvi_unsigned_byte()); break;
1342 case FNT_DEF2: define_font(dvi_unsigned_pair()); break;
1343 case FNT_DEF3: define_font(dvi_unsigned_triple()); break;
1344 case FNT_DEF4: define_font(dvi_signed_quad()); break;
1345 default: msg_out(M_FAIL, "Bad DVI file: byte %ld is not postpost!\n", dvi_location);
1346 }
1347 }
1348
dvi_init(int m,int r)1349 void dvi_init (int m, int r)
1350 {
1351 time_t tm = time(NULL);
1352 /* get all variables initialized */
1353 dvi_file = infp;
1354 new_mag = (SIGNED_QUAD)m;
1355 resolution = (double)r;
1356
1357 /* 73. Three characteristics of the pages (their max_v, max_h, and max_s)
1358 * are specified in the postamble, and a warning message is printed if
1359 * their limits are exceeded. Actually max_v is set to the maximum height
1360 * plus depth of a page, and max_h to the maximum width, for purposes of
1361 * page layout. Since characters can legally be set outside of the page
1362 * boundaries, it is not an error when max_v or max_h is exceeded. But
1363 * max_s should not be exceeded.
1364 * The postamble also specifies the total number of pages; DVItype
1365 * checks to see if this total is accurate. */
1366 // max_v = max_h = 017777777777 - 99;
1367 // max_s = stack_size + 1;
1368 max_v_so_far = max_h_so_far = max_s_so_far = page_count = 0;
1369
1370 /* Calculate the file size of the DVI file */
1371 fseek(dvi_file, 0L, SEEK_END);
1372 dvi_fsize = ftell(dvi_file);
1373 rewind(dvi_file);
1374
1375 /* process the preamble */
1376 process_preamble();
1377
1378 /* reading the postamble */
1379 read_postamble();
1380
1381 /* process the font definitions of the postamble */
1382 process_fonts();
1383
1384 /* Find the post opcode */
1385 find_page_location();
1386
1387 dvi_clear_state(); clear_bbox(1);
1388
1389 if (bbxfp) {
1390 fprintf(bbxfp, "%%!! DVIpos, version (%s), output file\n", VERSION);
1391 fprintf(bbxfp, "%% This_position_filename: \"%s\"\n", bbxfname);
1392 fprintf(bbxfp, "%% Command_line_to_dvipos:\n");
1393 fprintf(bbxfp, "%%+ <THE_COMMAND_LINE>\n");
1394 fprintf(bbxfp, "%%+ <THE_COMMAND_LINE CONTINUED>\n");
1395 fprintf(bbxfp, "%% Processing_data_and_time: %s", ctime(&tm));
1396 fprintf(bbxfp, "%% Input_filename: \"%s\"\n", infname);
1397 if (frmfp)
1398 fprintf(bbxfp, "%% DVI_debug_output_filename: \"%s\"\n", frmfname);
1399 fprintf(bbxfp, "%% DVI_standard: %d\n", id);
1400 fprintf(bbxfp, "%% DVI_mag: %ld\n", dvi_mag);
1401 fprintf(bbxfp, "%% DVI_mag_requested: %ld\n", mag);
1402 }
1403
1404 if (frmfp) {
1405 int count = 15 + strlen(comment);
1406 char *buf = (char *)xmalloc(count);
1407 fseek(dvi_file, 0L, SEEK_SET);
1408 fread(buf, 1, count, dvi_file);
1409 sput_signed_quad(buf+10, mag);
1410 fwrite(buf, 1, count, frmfp);
1411 dbg_location += count;
1412 free(buf);
1413 }
1414 }
1415
dvi_close(void)1416 void dvi_close (void)
1417 {
1418 int i;
1419
1420 if (frmfp) {
1421 char *buf;
1422 int count = post_post_location - post_location - 29;
1423 SIGNED_QUAD new_post_location = dbg_location; /* new post_location */
1424 put_unsigned_byte(POST, frmfp);
1425 put_signed_quad(prev_page_location, frmfp);
1426 put_signed_quad(numerator, frmfp);
1427 put_signed_quad(denominator, frmfp);
1428 put_signed_quad(mag, frmfp);
1429 put_signed_quad(max_v_so_far, frmfp);
1430 put_signed_quad(max_h_so_far, frmfp);
1431 put_unsigned_pair(max_s, frmfp);
1432 put_unsigned_pair(new_dvi_pages, frmfp);
1433 buf = (char *)xmalloc(count);
1434 fseek(dvi_file, post_location + 29, SEEK_SET);
1435 fread(buf, 1, count, dvi_file);
1436 fwrite(buf, 1, count, frmfp);
1437 free(buf);
1438 dbg_location += count;
1439 put_unsigned_byte(POST_POST, frmfp);
1440 put_signed_quad(new_post_location, frmfp);
1441 put_unsigned_byte(id, frmfp);
1442 for (i = 0; i < 3; i++)
1443 put_unsigned_byte(223, frmfp);
1444 while (dbg_location % 4 != 3)
1445 put_unsigned_byte(223, frmfp);
1446 }
1447
1448 tfm_close_all();
1449 fclose(dvi_file);
1450 free(page_location);
1451 for (i = 0; i < num_dvi_fonts; i++) free(dvi_fonts[i].name);
1452 if (dvi_fonts) free(dvi_fonts);
1453 }
1454
1455 /* 79. Here is the overall setup. */
dvi_do_page(int n)1456 void dvi_do_page (int n)
1457 {
1458 dvi_location = page_location[n-1] - 1;
1459 current_page = n;
1460 new_dvi_pages++;
1461
1462 /* Position to beginning of page */
1463 fseek(dvi_file, page_location[n-1], SEEK_SET);
1464
1465 /* set current font undefined; initialize the state variables */
1466 dvi_clear_state();
1467
1468 /* 80. Translate the next command in the DVI file until finding EOP. */
1469 for (;;) {
1470 UNSIGNED_BYTE opcode = dvi_unsigned_byte();
1471
1472 if (frmfp && opcode != EOP) put_unsigned_byte(opcode, frmfp);
1473
1474 /* SET_CHAR_0 - SET_CHAR_127 */
1475 if (opcode >= SET_CHAR_0 && opcode <= SET_CHAR_127) {
1476 do_setchar(opcode);
1477 continue;
1478 }
1479
1480 /* FNT_NUM_0 - FNT_NUM_63 */
1481 if (opcode >= FNT_NUM_0 && opcode <= FNT_NUM_63) {
1482 do_fnt_num(opcode);
1483 continue;
1484 }
1485
1486 switch (opcode) {
1487 case SET1:
1488 case SET2:
1489 case SET3:
1490 case SET4: do_set(opcode); break;
1491 case PUT1:
1492 case PUT2:
1493 case PUT3:
1494 case PUT4: do_put(opcode); break;
1495 case SET_RULE:
1496 case PUT_RULE: do_rule(opcode); break;
1497 case NOP: msg_out(M_DEBUG, "%ld: nop \n", dvi_location); break;
1498 case BOP: do_bop(); break;
1499 case EOP: do_eop(); return;
1500 case PUSH: do_push(); break;
1501 case POP: do_pop(); break;
1502 case RIGHT1:
1503 case RIGHT2:
1504 case RIGHT3:
1505 case RIGHT4:
1506 case W0:
1507 case W1:
1508 case W2:
1509 case W3:
1510 case W4:
1511 case X0:
1512 case X1:
1513 case X2:
1514 case X3:
1515 case X4: do_space(opcode); break;
1516 case DOWN1:
1517 case DOWN2:
1518 case DOWN3:
1519 case DOWN4:
1520 case Y0:
1521 case Y1:
1522 case Y2:
1523 case Y3:
1524 case Y4:
1525 case Z0:
1526 case Z1:
1527 case Z2:
1528 case Z3:
1529 case Z4: do_vmove(opcode); break;
1530 case FNT1:
1531 case FNT2:
1532 case FNT3:
1533 case FNT4: do_fnt_num(opcode); break;
1534 case XXX1:
1535 case XXX2: /* Not used in general */
1536 case XXX3: /* Not used in general */
1537 case XXX4: do_xxx(opcode); break;
1538 case FNT_DEF1:
1539 case FNT_DEF2:
1540 case FNT_DEF3:
1541 case FNT_DEF4: do_fnt_def(opcode); break;
1542 case DIR: do_dir(); break;
1543 case PRE:
1544 case POST:
1545 case POST_POST:
1546 default:
1547 msg_out(M_FAIL, "[fatal] Unexpected opcode (%d).", opcode);
1548 }
1549 }
1550 }
1551