1 /*****************************************************************************/
2 /*                                                                           */
3 /*   disdvi  ---  disassembles TeX dvi files.                                */
4 /*                                                                           */
5 /*                                                                           */
6 /*   2.26 23oct2010  TexLivel    support pTex and XeTex                      */
7 /*   2.25 23jan2003  M.J.E. Mol  fixed bug in copying font name (name[i])    */
8 /*   2.24 27may96 M.J.E. Mol     A few typecasts added                       */
9 /*   2.23 23jul95 M.J.E. Mol     Cleanups from duz@roxi.ez.fht-mannheim.de   */
10 /*   2.22 13dec90 M.J.E. Mol     Fixed bug in num(). Cleaned up code.        */
11 /*   2.21 03may90 M.J.E. Mol     Created usage().                            */
12 /*    2.2 02may90 M.J.E. Mol     Included port to VAX/VMS VAXC by            */
13 /*                               Robert Schneider.                           */
14 /*    2.1 19jan90 M.J.E. Mol     Maintain a list of fonts and                */
15 /*                               show fontnames in font changes.             */
16 /*                               Show character code when printing ligatures */
17 /*    2.0 23jan89 M.J.E. Mol (c) 1989                                        */
18 /*                                               marcel@mesa.nl              */
19 /*                                                                           */
20 /*****************************************************************************/
21 
22 /*
23  * dvi2tty
24  * Copyright (C) 2003 Marcel J.E. Mol <marcel@mesa.nl>
25  *
26  * This program is free software; you can redistribute it and/or
27  * modify it under the terms of the GNU General Public License
28  * as published by the Free Software Foundation; either version 2
29  * of the License, or (at your option) any later version.
30  *
31  * This program is distributed in the hope that it will be useful,
32  * but WITHOUT ANY WARRANTY; without even the implied warranty of
33  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  * GNU General Public License for more details.
35  *
36  * You should have received a copy of the GNU General Public License
37  * along with this program; if not, write to the Free Software
38  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
39  *
40  */
41 
42 const char *disdvi = "@(#) disdvi.c  2.26 20101027 M.J.E. Mol (c) 1989-2010, marcel@mesa.nl";
43 
44 /*
45  * Include files
46  */
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #if defined(MSDOS) || defined(WIN32)
51 # include <fcntl.h>
52 #else
53 # if !defined(THINK_C)          /* Macintosh */
54 # include <unistd.h>
55 # endif
56 #endif
57 #include <ctype.h>
58 #include <string.h>
59 #include "commands.h"
60 #if defined(THINK_C)
61 # include "macintosh.h"
62 #endif
63 
64 #if defined(KPATHSEA)
65 # define NO_DEBUG 1
66 # include <kpathsea/config.h>
67 # include <kpathsea/lib.h>
68 #endif
69 
70 
71 /*
72  * Constant definitions
73  */
74 
75 #define LASTCHAR        127    /* max dvi character, above are commands    */
76 
77 #define get1()           num(1)
78 #define get2()           num(2)
79 #define get3()           num(3)
80 #define get4()           num(4)
81 #define sget1()         snum(1)
82 #define sget2()         snum(2)
83 #define sget3()         snum(3)
84 #define sget4()         snum(4)
85 
86 
87 
88 /*
89  * Type definitions
90  */
91 
92 typedef struct _font {
93     long    num;
94     struct _font * next;
95     char  * name;
96 } font;
97 
98 
99 
100 /*
101  * Variable declarations
102  */
103 
104 font * fonts = NULL;
105 FILE * dvifp;
106 char * dvi_name;
107 long   pc = 0;
108 
109 char * progname;
110 
111 int is_ptex = 0;
112 int is_xetex = 0;
113 const char * dvi_ext = ".dvi";
114 
115 /*
116  * Function declarations
117  */
118 
119 #if defined(VMS)
120                 main            (int argc, char ** argv);
121 #endif
122 void            bop             (void);
123 void            preamble        (void);
124 void            postamble       (void);
125 void            postpostamble   (void);
126 void            fontdef         (int x);
127 const char *    fontname        (unsigned long fntnum);
128 void            special         (int x);
129 void            printnonprint   (int ch);
130 unsigned long   num             (int size);
131 long            snum            (int size);
132 void            usage           (void);
133 void            picfile         (int opcode);
134 void            natfontdef      (int opcode);
135 void            glyphs          (int opcode);
136 void            dvidir          (int opcode);
137 void            invalid         (int opcode);
138 
139 
140 
141 
142 /*
143  * MAIN --
144  */
145 
146 #if defined(VMS)
main(int argc,char ** argv)147      main(int argc, char **argv)
148 #else
149 int main(int argc, char **argv)
150 #endif
151 {
152     register int opcode;                /* dvi opcode */
153     register int i;
154     unsigned long fontnum;
155 
156 #if defined(THINK_C)
157     argc = process_disdvi_command_line(&argv);
158 #endif
159 
160     progname = *argv++;
161 
162     if ((argc > 1) && (*argv[0] == '-')) {
163         if (!strcmp(*argv, "-h")) {
164             usage();
165             exit(0);
166         }
167         if (!strcmp(*argv, "-p"))
168             is_ptex = 1;
169         else if (!strcmp(*argv, "-x")) {
170             is_xetex = 1;
171             dvi_ext = ".xdv";
172         } else {
173             fprintf(stderr, "Invalid option `%s'\n", *argv);
174             usage();
175             exit(3);
176         }
177         argv++;
178         argc--;
179     }
180 
181     if (argc > 2) {
182         fprintf(stderr, "To many arguments\n");
183         usage();
184         exit(1);
185     }
186 
187     if (argc == 2) {
188         if ((i = strlen(*argv)) == 0) {
189             fprintf(stderr, "Illegal empty filename\n");
190             usage();
191             exit(2);
192         }
193         if ((i >= 5) && (!strcmp(*argv+i-4, dvi_ext)))
194             dvi_name = *argv;
195         else {
196             dvi_name = malloc((i+5) * sizeof(char));
197             strcpy(dvi_name, *argv);
198             strcat(dvi_name, dvi_ext);
199         }
200         if ((dvifp = fopen(dvi_name, "r")) == NULL) {
201             perror(dvi_name);
202             exit(3);
203         }
204     }
205     else
206         dvifp = stdin;
207 
208 #if defined(MSDOS) || defined(WIN32)
209     setmode(fileno(dvifp), O_BINARY);
210 #endif
211 
212     while ((opcode = (int) get1()) != EOF) {    /* process until end of file */
213         printf("%06ld: ", pc - 1);
214         if ((opcode <= LASTCHAR) && isprint(opcode)) {
215             printf("Char:     ");
216             while ((opcode <= LASTCHAR) && isprint(opcode)) {
217                 putchar(opcode);
218                 opcode = (int) get1();
219             }
220             putchar('\n');
221             printf("%06ld: ", pc - 1);
222         }
223 
224         if (opcode <= LASTCHAR)
225             printnonprint(opcode);              /* it must be a non-printable */
226         else if ((opcode >= FONT_00) && (opcode <= FONT_63))
227             printf("FONT_%02d              /* %s */\n", opcode - FONT_00,
228                                     fontname((unsigned long) opcode - FONT_00));
229         else
230             switch (opcode) {
231                 case SET1     :
232                 case SET2     :
233                 case SET3     :
234                 case SET4     : printf("SET%d:    %ld\n", opcode - SET1 + 1,
235                                                        num(opcode - SET1 + 1));
236                                 break;
237                 case SET_RULE : printf("SET_RULE: height: %ld\n", sget4());
238                                 printf("%06ld: ", pc);
239                                 printf("          length: %ld\n", sget4());
240                                 break;
241                 case PUT1     :
242                 case PUT2     :
243                 case PUT3     :
244                 case PUT4     : printf("PUT%d:     %ld\n", opcode - PUT1 + 1,
245                                                        num(opcode - PUT1 + 1));
246                                 break;
247                 case PUT_RULE : printf("PUT_RULE: height: %ld\n", sget4());
248                                 printf("%06ld: ", pc);
249                                 printf("          length: %ld\n", sget4());
250                                 break;
251                 case NOP      : printf("NOP\n");  break;
252                 case BOP      : bop();            break;
253                 case EOP      : printf("EOP\n");  break;
254                 case PUSH     : printf("PUSH\n"); break;
255                 case POP      : printf("POP\n");  break;
256                 case RIGHT1   :
257                 case RIGHT2   :
258                 case RIGHT3   :
259                 case RIGHT4   : printf("RIGHT%d:   %ld\n", opcode - RIGHT1 + 1,
260                                                      snum(opcode - RIGHT1 + 1));
261                                 break;
262                 case W0       : printf("W0\n");   break;
263                 case W1       :
264                 case W2       :
265                 case W3       :
266                 case W4       : printf("W%d:       %ld\n", opcode - W0,
267                                                       snum(opcode - W0));
268                                 break;
269                 case X0       : printf("X0\n");   break;
270                 case X1       :
271                 case X2       :
272                 case X3       :
273                 case X4       : printf("X%d:       %ld\n", opcode - X0,
274                                                       snum(opcode - X0));
275                                 break;
276                 case DOWN1    :
277                 case DOWN2    :
278                 case DOWN3    :
279                 case DOWN4    : printf("DOWN%d:    %ld\n", opcode - DOWN1 + 1,
280                                                       snum(opcode - DOWN1 + 1));
281                                 break;
282                 case Y0       : printf("Y0\n");   break;
283                 case Y1       :
284                 case Y2       :
285                 case Y3       :
286                 case Y4       : printf("Y%d:       %ld\n", opcode - Y0,
287                                                       snum(opcode - Y0));
288                                 break;
289                 case Z0       : printf("Z0\n");   break;
290                 case Z1       :
291                 case Z2       :
292                 case Z3       :
293                 case Z4       : printf("Z%d:       %ld\n", opcode - Z0,
294                                                       snum(opcode - Z0));
295                                 break;
296                 case FNT1     :
297                 case FNT2     :
298                 case FNT3     :
299                 case FNT4     : fontnum = num(opcode -FNT1 + 1);
300                                 printf("FNT%d:     %ld    /* %s */\n",
301                                        opcode - FNT1 + 1, fontnum,
302                                        fontname(fontnum));
303                                 break;
304                 case XXX1     :
305                 case XXX2     :
306                 case XXX3     :
307                 case XXX4     : special(opcode - XXX1 + 1);     break;
308                 case FNT_DEF1 :
309                 case FNT_DEF2 :
310                 case FNT_DEF3 :
311                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1); break;
312                 case PRE      : preamble();                     break;
313                 case POST     : postamble();                    break;
314                 case POST_POST: postpostamble();                break;
315                 case PIC_FILE : picfile(opcode);                break;
316                 case NAT_FNT  : natfontdef(opcode);             break;
317                 case SET_GL_AR:
318                 case SET_GL_ST: glyphs(opcode);                 break;
319                 case DVI_DIR  : dvidir(opcode);                 break;
320                 default       : invalid(opcode);
321             }
322     }
323 
324     exit(0);
325 
326 } /* main */
327 
328 
329 
330 /*
331  * BOP -- Process beginning of page.
332  */
333 
bop(void)334 void bop(void)
335 {
336     int i;
337 
338     printf("BOP       page number      : %ld", sget4());
339     for (i=9; i > 0; i--) {
340         if (i % 3 == 0)
341             printf("\n%06ld:         ", pc);
342         printf("  %6ld", sget4());
343     }
344     printf("\n%06ld: ", pc);
345     printf("          prev page offset : %06ld\n", sget4());
346 
347     return;
348 
349 } /* bop */
350 
351 
352 
353 /*
354  * POSTAMBLE -- Process post amble.
355  */
356 
postamble(void)357 void postamble(void)
358 {
359 
360     printf("POST      last page offset : %06ld\n", sget4());
361     printf("%06ld: ", pc);
362     printf("          numerator        : %ld\n", get4());
363     printf("%06ld: ", pc);
364     printf("          denominator      : %ld\n", get4());
365     printf("%06ld: ", pc);
366     printf("          magnification    : %ld\n", get4());
367     printf("%06ld: ", pc);
368     printf("          max page height  : %ld\n", get4());
369     printf("%06ld: ", pc);
370     printf("          max page width   : %ld\n", get4());
371     printf("%06ld: ", pc);
372     printf("          stack size needed: %d\n", (int) get2());
373     printf("%06ld: ", pc);
374     printf("          number of pages  : %d\n", (int) get2());
375 
376     return;
377 
378 } /* postamble */
379 
380 
381 
382 /*
383  * PREAMBLE -- Process pre amble.
384  */
385 
preamble(void)386 void preamble(void)
387 {
388     register int i;
389 
390     printf("PRE       version          : %d\n", (int) get1());
391     printf("%06ld: ", pc);
392     printf("          numerator        : %ld\n", get4());
393     printf("%06ld: ", pc);
394     printf("          denominator      : %ld\n", get4());
395     printf("%06ld: ", pc);
396     printf("          magnification    : %ld\n", get4());
397     printf("%06ld: ", pc);
398     i = (int) get1();
399     printf("          job name (%3d)   :", i);
400     while (i-- > 0)
401         putchar((int) get1());
402     putchar('\n');
403 
404     return;
405 
406 } /* preamble */
407 
408 
409 
410 /*
411  * POSTPOSTAMBLE -- Process post post amble.
412  */
413 
postpostamble(void)414 void postpostamble(void)
415 {
416     register int i;
417 
418     printf("POSTPOST  postamble offset : %06ld\n", get4());
419     printf("%06ld: ", pc);
420     printf("          version          : %d\n", (int) get1());
421     while ((i = (int) get1()) == TRAILER) {
422         printf("%06ld: ", pc - 1);
423         printf("TRAILER\n");
424     }
425     while (i != EOF) {
426         printf("%06ld: ", pc - 1);
427         printf("BAD DVI FILE END: 0x%02X\n", i);
428         i = (int) get1();
429     }
430 
431     return;
432 
433 } /* postpostamble */
434 
435 
436 
437 /*
438  * SPECIAL -- Process special opcode.
439  */
440 
special(int x)441 void special(int x)
442 {
443     register long len;
444 
445     len = num(x);
446     printf("XXX%d:     %ld bytes\n", x, len);
447     printf("%06ld: ", pc);
448     for (; len>0; len--)           /* a bit dangerous ... */
449         putchar((int) get1());     /*   can be non-printables */
450     putchar('\n');
451 
452     return;
453 
454 } /* special */
455 
456 
457 
458 /*
459  * FONTDEF -- Process a font definition.
460  */
461 
fontdef(int x)462 void fontdef(int x)
463 {
464     register int i;
465     char * name;
466     font * fnt;
467     int namelen;
468     unsigned long fntnum;
469     int new = 0;
470 
471     fntnum = num(x);
472     printf("FNT_DEF%d: %ld\n", x, fntnum);
473     printf("%06ld: ", pc);           /* avoid side-effect on pc in get4() */
474     printf("          checksum         : %ld\n", get4());
475     printf("%06ld: ", pc);
476     printf("          scale            : %ld\n", get4());
477     printf("%06ld: ", pc);
478     printf("          design           : %ld\n", get4());
479     printf("%06ld: ", pc);
480     printf("          name             : ");
481     namelen = (int) get1() + (int) get1();
482     fnt = fonts;
483     while (fnt != NULL && fnt->num != fntnum)
484         fnt = fnt->next;
485     if (fnt == NULL) {
486         if ((fnt = (font *) malloc(sizeof(font))) == NULL) {
487             perror("fontdef");
488             exit(1);
489         }
490         fnt->num = fntnum;
491         new = 1;
492     }
493     else
494         free(fnt->name);    /* free old name */
495     if ((name = (char *) malloc((namelen+1) * sizeof(char))) == NULL) {
496         perror("fontdef");
497         exit(1);
498     }
499 
500     for (i = 0; i < namelen; i++)
501         name[i] = get1();
502     name[i] = '\0';
503     fnt->name = name;
504     if (new) {
505         fnt->next = fonts;
506         fonts = fnt;
507     }
508 
509     printf("%s\n", name);
510 
511     return;
512 
513 } /* fontdef */
514 
515 
516 
517 /*
518  * FONTNAME -- Return font name.
519  */
520 
fontname(unsigned long fntnum)521 const char * fontname(unsigned long fntnum)
522 {
523     font * fnt;
524 
525     fnt = fonts;
526     while (fnt != NULL && fnt->num != fntnum)
527         fnt = fnt->next;
528     if (fnt != NULL)
529         return fnt->name;
530 
531     return "unknown fontname";
532 
533 } /* fontname */
534 
535 
536 
537 /*
538  * PRINTNONPRINT -- Translate non-printable characters.
539  */
540 
printnonprint(int ch)541 void printnonprint(int ch)
542 {
543 
544     printf("Char:     ");
545     switch (ch) {
546         case 11  :  printf("ff         /* ligature (non-printing) 0x%02X */",
547                            ch);
548                     break;
549         case 12  :  printf("fi         /* ligature (non-printing) 0x%02X */",
550                            ch);
551                     break;
552         case 13  :  printf("fl         /* ligature (non-printing) 0x%02X */",
553                            ch);
554                     break;
555         case 14  :  printf("ffi        /* ligature (non-printing) 0x%02X */",
556                            ch);
557                     break;
558         case 15  :  printf("ffl        /* ligature (non-printing) 0x%02X */",
559                            ch);
560                     break;
561         case 16  :  printf("i          /* (non-printing) 0x%02X */", ch);
562                     break;
563         case 17  :  printf("j          /* (non-printing) 0x%02X */", ch);
564                     break;
565         case 25  :  printf("ss         /* german (non-printing) 0x%02X */", ch);
566                     break;
567         case 26  :  printf("ae         /* scandinavian (non-printing) 0x%02X */",
568                            ch);
569                     break;
570         case 27  :  printf("oe         /* scandinavian (non-printing) 0x%02X */",
571                            ch);
572                     break;
573         case 28  :  printf("o          /* scandinavian (non-printing) 0x%02X */",
574                            ch);
575                     break;
576         case 29  :  printf("AE         /* scandinavian (non-printing) 0x%02X */",
577                            ch);
578                     break;
579         case 30  :  printf("OE         /* scandinavian (non-printing) 0x%02X */",
580                            ch);
581                     break;
582         case 31  :  printf("O          /* scandinavian (non-printing) 0x%02X */",
583                            ch);
584                     break;
585         default  :  printf("0x%02X", ch); break;
586     }
587     putchar('\n');
588 
589     return;
590 
591 } /* printnonprint */
592 
593 
594 
595 /*
596  * NUM --
597  */
598 
num(int size)599 unsigned long num(int size)
600 {
601     register int i;
602     register unsigned long x = 0;
603 
604     pc += size;
605     for (i = size; i > 0; i--)
606         x = (x << 8) + (unsigned) getc(dvifp);
607 
608     return x;
609 
610 } /* num */
611 
612 
613 
614 /*
615  * SNUM --
616  */
617 
snum(int size)618 long snum(int size)
619 {
620     register int i;
621     register long x;
622 
623     pc += size;
624     x = getc(dvifp);
625     if (x & 0x80)
626         x -= 0x100;
627     for (i = size - 1; i > 0; i--)
628         x = (x << 8) + (unsigned) getc(dvifp);
629 
630     return x;
631 
632 } /* snum */
633 
634 
635 
636 /*
637  * USAGE --
638  */
639 
usage(void)640 void usage(void)
641 {
642 
643     fprintf(stderr, "\n%s\n\n", disdvi);
644     fprintf(stderr, "    disassembles (p)TeX dvi and XeTeX xdv files\n");
645     fprintf(stderr, "Usage: %s [-h | [-p] [dvi_file[.dvi]]\n", progname);
646     fprintf(stderr, "              | -x [xdv_file[.xdv]]]\n");
647     fprintf(stderr, "\n If you like this code and want to support is feel free\n to donate at Paypal marcel@mesa.nl. Thanks.\n\n");
648 
649 
650     return;
651 
652 } /* usage */
653 
654 
655 
picfile(int opcode)656 void picfile(int opcode)
657 {
658     int i;
659 
660     if (!is_xetex) {
661         invalid(opcode);
662         return;
663     }
664 
665     printf("PIC_FILE  flags            : %ld\n", get1());
666     printf("%06ld:           trans :", pc);
667     for (i=0; i<6; i++)
668         printf(" %ld", sget4());
669     printf("\n%06ld: ", pc);
670     printf("          page              : %ld\n", get2());
671     printf("%06ld: ", pc);
672     i = (int) get1();
673     printf("          path name (%3d)   :", i);
674     while (i-- > 0)
675         putchar((int) get1());
676     putchar('\n');
677 } /* picfile */
678 
679 
680 
natfontdef(int opcode)681 void natfontdef(int opcode)
682 {
683     register int i;
684     char * name;
685     font * fnt;
686     int flags, namelen, famlen, stylen;
687     long fntnum;
688     int new = 0;
689 
690     if (!is_xetex) {
691         invalid(opcode);
692         return;
693     }
694 
695     fntnum = num(4);
696     printf("NAT_FNT:  %ld\n", fntnum);
697     printf("%06ld: ", pc);
698     printf("          scale            : %ld\n", get4());
699     printf("%06ld: ", pc);
700     flags = get2();
701     printf("          flags            : %d\n", flags);
702     printf("%06ld: ", pc);
703     printf("          name             : ");
704     namelen = (int) get1();
705     famlen = (int) get1();
706     stylen = (int) get1();
707     fnt = fonts;
708     while (fnt != NULL && fnt->num != fntnum)
709         fnt = fnt->next;
710     if (fnt == NULL) {
711         if ((fnt = (font *) malloc(sizeof(font))) == NULL) {
712             perror("fontdef");
713             exit(1);
714         }
715         fnt->num = fntnum;
716         new = 1;
717     }
718     else
719         free(fnt->name);    /* free old name */
720     if ((name = (char *) malloc((namelen+1) * sizeof(char))) == NULL) {
721         perror("fontdef");
722         exit(1);
723     }
724 
725     for (i = 0; i < namelen; i++)
726         name[i] = get1();
727     name[namelen] = '\0';
728     fnt->name = name;
729     if (new) {
730         fnt->next = fonts;
731         fonts = fnt;
732     }
733 
734     printf("%s\n", name);
735 
736     if (famlen) {
737         printf("                  family           : ");
738         while (famlen-- > 0)
739             putchar((int) get1());
740         putchar('\n');
741     }
742 
743     if (stylen) {
744         printf("                  style            : ");
745         while (stylen-- > 0)
746             putchar((int) get1());
747         putchar('\n');
748     }
749 } /* fontdef */
750 
751 
752 
glyphs(int opcode)753 void glyphs(int opcode)
754 {
755     long width;
756     int x, n, i, j;
757     long * xy;
758 
759     if (!is_xetex) {
760         invalid(opcode);
761         return;
762     }
763 
764     x = SET_GL_ST - opcode + 1;
765     width = sget4();
766     n = get2();
767     printf("GLYPH_%s width            : %ld\n", x == 2 ? "ARR" : "STR", width);
768     if ((xy = (long *) malloc(n * x * sizeof(long))) == NULL) {
769         perror("glyphs");
770         exit(1);
771     }
772     for (j=0; j < n * x; j++)
773         xy[j] = sget4();
774     for (i=0, j=0; i < n; i++) {
775         printf("           x: %ld", xy[j++]);
776         if (x == 2)
777             printf("    y: %ld", xy[j++]);
778         printf("    g: %ld\n", get2());
779     }
780 } /* glyphs */
781 
782 
783 
dvidir(int opcode)784 void dvidir(int opcode)
785 {
786     if (!is_ptex) {
787         invalid(opcode);
788         return;
789     }
790 
791     printf("DVI_DIR:  %ld\n", get1());
792 } /* dvidir */
793 
794 
795 
invalid(int opcode)796 void invalid(int opcode)
797 {
798     printf("INVALID   %d\n", opcode);
799 } /* invalid */
800