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