Back to index

tetex-bin  3.0
dvi.c
Go to the documentation of this file.
00001 /*  $Header$
00002 
00003     This is dvipdfm, a DVI to PDF translator.
00004     Copyright (C) 1998, 1999 by Mark A. Wicks
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019     
00020     The author may be contacted via the e-mail address
00021 
00022        mwicks@kettering.edu
00023 */
00024 
00025 #include <sys/types.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <ctype.h>
00029 #include "system.h"
00030 #include "mem.h"
00031 #include "error.h"
00032 #include "mfileio.h"
00033 #include "numbers.h"
00034 #include "dvi.h"
00035 #include "dvicodes.h"
00036 #include "pdflimits.h"
00037 #include "pdfdev.h"
00038 #include "pdfdoc.h"
00039 #include "tfm.h"
00040 #include "vf.h"
00041 
00042 
00043 /* Interal Variables */
00044 
00045 static FILE *dvi_file;
00046 static char debug = 0;
00047 static unsigned num_loaded_fonts = 0, max_loaded_fonts = 0, stackdepth;
00048 static unsigned long *page_loc = NULL;
00049 static unsigned long post_location, dvi_file_size;
00050 static UNSIGNED_PAIR num_pages = 0;
00051 static UNSIGNED_QUAD media_width, media_height;
00052 static UNSIGNED_QUAD dvi_unit_num, dvi_unit_den, dvi_mag;
00053 
00054 
00055 #define PHYSICAL 1
00056 #define VIRTUAL 2
00057 #define DVI 1
00058 #define VF 2
00059 
00060 struct loaded_font {
00061   int type;  /* Type is physical or virtual */
00062   int font_id;  /* id returned by dev (for PHYSICAL fonts)
00063                  or by vf module for (VIRTUAL fonts) */
00064   int tfm_id;
00065   spt_t size;
00066   int source;  /* Source is either DVI or VF */
00067 } *loaded_fonts = NULL;
00068 
00069 static void need_more_fonts (unsigned n) 
00070 {
00071   if (num_loaded_fonts+n > max_loaded_fonts) {
00072     max_loaded_fonts += MAX_FONTS;
00073     loaded_fonts = RENEW (loaded_fonts, max_loaded_fonts, struct
00074                        loaded_font);
00075   }
00076 }
00077 
00078 struct font_def
00079 {
00080   spt_t size;
00081   char *name;
00082   signed long tex_id;
00083   int font_id; /* index of _loaded_ font in loaded_fonts array */
00084   int used;
00085 } *def_fonts = NULL;
00086 
00087 static unsigned num_def_fonts = 0, max_def_fonts = 0;
00088 
00089 static unsigned char verbose = 0;
00090 
00091 static unsigned char compute_boxes = 0;
00092 
00093 void dvi_set_verbose(void)
00094 {
00095   if (verbose < 255) {
00096   verbose += 1;
00097   }
00098 }
00099 
00100 void dvi_compute_boxes (unsigned char boxes)
00101 {
00102   compute_boxes = boxes;
00103 }
00104 
00105 void dvi_set_debug(void)
00106 {
00107   debug = 1;
00108 }
00109 
00110 unsigned dvi_npages (void)
00111 {
00112   return num_pages;
00113 }
00114 
00115 static void invalid_signature()
00116 {
00117   ERROR ("dvi_init:  Something is wrong.  Are you sure this is a DVI file?\n");
00118 }
00119 
00120 #define range_check_loc(loc) {if ((loc) > dvi_file_size) invalid_signature();}
00121 
00122 
00123 static void find_post (void)
00124 {
00125   long current;
00126   int read_byte;
00127 
00128   /* First find end of file */  
00129   dvi_file_size = file_size (dvi_file);
00130   current = dvi_file_size;
00131  
00132   /* Scan backwards through PADDING */  
00133   do {
00134      current -= 1;
00135      seek_absolute (dvi_file, current);
00136 
00137   } while ((read_byte = fgetc(dvi_file)) == PADDING &&
00138           current > 0);
00139 
00140   /* file_position now points to last non padding character or beginning of file */
00141   if (dvi_file_size - current < 4 ||
00142       current == 0 || read_byte != DVI_ID) {
00143     fprintf (stderr, "DVI ID = %d\n", read_byte);
00144     invalid_signature();
00145   } 
00146 
00147   /* Make sure post_post is really there */
00148   current = current - 5;
00149   seek_absolute (dvi_file, current);
00150   if ((read_byte = fgetc(dvi_file)) != POST_POST) {
00151      fprintf (stderr, "Found %d where post_post opcode should be\n", read_byte);
00152      invalid_signature();
00153   }
00154   current = get_signed_quad (dvi_file);
00155   seek_absolute (dvi_file, current);
00156   if ((read_byte = fgetc(dvi_file)) != POST) {
00157      fprintf (stderr, "Found %d where post_post opcode should be\n", read_byte);
00158      invalid_signature();
00159   }
00160   post_location = current;
00161 }
00162 
00163 static void get_page_info (void) 
00164 {
00165   int i;
00166   seek_absolute (dvi_file, post_location+27);
00167   num_pages = get_unsigned_pair (dvi_file);
00168   if (verbose > 2) {
00169     fprintf (stderr, "Page count:\t %4d\n", num_pages);
00170   }
00171   if (num_pages == 0) {
00172     ERROR ("dvi_init:  Page count is 0!");
00173   }
00174   page_loc = NEW (num_pages, unsigned long);
00175   seek_absolute (dvi_file, post_location+1);
00176   page_loc[num_pages-1] = get_unsigned_quad(dvi_file);
00177   range_check_loc(page_loc[num_pages-1]+41);
00178   for (i=num_pages-2; i>=0; i--) {
00179     seek_absolute (dvi_file, page_loc[i+1]+41);
00180     page_loc[i] = get_unsigned_quad(dvi_file);
00181     range_check_loc(page_loc[num_pages-1]+41);
00182   }
00183 }
00184 
00185 /* Following are computed "constants" used for unit conversion */
00186 static double dvi2pts = 0.0, total_mag = 1.0;
00187 
00188 double dvi_tell_mag (void)
00189 {
00190   return total_mag;
00191 }
00192 
00193 static void do_scales (double mag)
00194 {
00195   total_mag = (double) dvi_mag / 1000.0 * mag;
00196   dvi2pts = (double) dvi_unit_num / (double) dvi_unit_den;
00197   dvi2pts *= (72.0)/(254000.0);
00198 }
00199 
00200 
00201 static void get_dvi_info (void)
00202 {
00203   seek_absolute (dvi_file, post_location+5);
00204   dvi_unit_num = get_unsigned_quad(dvi_file);
00205   dvi_unit_den = get_unsigned_quad(dvi_file);
00206   dvi_mag = get_unsigned_quad(dvi_file);
00207   media_height = get_unsigned_quad(dvi_file);
00208   media_width = get_unsigned_quad(dvi_file);
00209   stackdepth = get_unsigned_pair(dvi_file);
00210   if (stackdepth > DVI_MAX_STACK_DEPTH) {
00211     fprintf (stderr, "DVI needs stack depth of %d,", stackdepth);
00212     fprintf (stderr, "but MAX_DVI_STACK_DEPTH is %d", DVI_MAX_STACK_DEPTH);
00213     ERROR ("Capacity exceeded.");
00214   }
00215 
00216   if (verbose > 2) {
00217     fprintf (stderr, "DVI File Info\n");
00218     fprintf (stderr, "Unit: %ld / %ld\n", dvi_unit_num, dvi_unit_den);
00219     fprintf (stderr, "Mag: %ld\n", dvi_mag);
00220     fprintf (stderr, "Media Height: %ld\n", media_height);
00221     fprintf (stderr, "Media Width: %ld\n", media_width);
00222     fprintf (stderr, "Stack Depth: %d\n", stackdepth);
00223   }
00224   
00225 }
00226 
00227 static void dump_font_info (void)
00228 {
00229   unsigned i;
00230   fprintf (stderr, "\nDVI file font info\n");
00231   for (i=0; i<num_def_fonts; i++) {
00232     fprintf (stderr, "name: %10s, ", def_fonts[i].name);
00233     fprintf (stderr, "TeX/DVI ID: %5ld, ", def_fonts[i].tex_id);
00234     fprintf (stderr, "size: %5.2f pt, ", def_fonts[i].size*dvi2pts);
00235     fprintf (stderr, "\n");
00236   }
00237 }
00238 
00239 static void get_a_font_record (SIGNED_QUAD tex_id)
00240 {
00241   UNSIGNED_BYTE dir_length, name_length;
00242   UNSIGNED_QUAD checksum, size, design_size;
00243   char *directory, *name;
00244   if (debug) {
00245     fprintf (stderr, "get_a_font_record: tex_id = %ld\n", tex_id);
00246   }
00247   if (num_def_fonts >= max_def_fonts) {
00248     max_def_fonts += MAX_FONTS;
00249     def_fonts = RENEW (def_fonts, max_def_fonts, struct font_def);
00250   }
00251   checksum = get_unsigned_quad (dvi_file);
00252   size = get_unsigned_quad (dvi_file);
00253   design_size = get_unsigned_quad (dvi_file);
00254   dir_length = get_unsigned_byte (dvi_file);
00255   name_length = get_unsigned_byte (dvi_file);
00256   directory = NEW (dir_length+1, char);
00257   if (fread (directory, 1, dir_length, dvi_file) !=
00258       dir_length) {
00259     invalid_signature();
00260   }
00261   name = NEW (name_length+1, char);
00262   if (fread (name, 1, name_length, dvi_file) !=
00263       name_length) {
00264     invalid_signature();
00265   }
00266   directory[dir_length] = 0;
00267   RELEASE (directory);
00268   name[name_length] = 0;
00269   def_fonts[num_def_fonts].name = name;
00270   def_fonts[num_def_fonts].size = size;
00271   def_fonts[num_def_fonts].tex_id = tex_id;
00272   def_fonts[num_def_fonts].used = 0;
00273   num_def_fonts +=1;
00274   return;
00275 }
00276 
00277 static void get_dvi_fonts (void)
00278 {
00279   UNSIGNED_BYTE code;
00280   SIGNED_QUAD tex_id;
00281   seek_absolute (dvi_file, post_location+29);
00282   while ((code = get_unsigned_byte(dvi_file)) != POST_POST) {
00283     switch (code)
00284       {
00285       case FNT_DEF1:
00286        tex_id = get_unsigned_byte (dvi_file);
00287        break;
00288       case FNT_DEF2:
00289        tex_id = get_unsigned_pair (dvi_file);
00290        break;
00291       case FNT_DEF3:
00292        tex_id = get_unsigned_triple (dvi_file);
00293        break;
00294       case FNT_DEF4:
00295        tex_id = get_signed_quad (dvi_file);
00296        break;
00297       default:
00298        fprintf (stderr, "Unexpected op code: %3d\n", code);
00299        invalid_signature();
00300       }
00301     get_a_font_record(tex_id);
00302   }
00303   if (verbose>2) {
00304     dump_font_info();
00305   }
00306 }
00307 
00308 
00309 void get_comment(void)
00310 {
00311   UNSIGNED_BYTE length;
00312   static char dvi_comment[257];
00313   seek_absolute (dvi_file, 14);
00314   length = get_unsigned_byte(dvi_file);
00315   if (fread (dvi_comment, 1, length, dvi_file) != length) {
00316     invalid_signature();
00317   }
00318   dvi_comment[length] = 0;
00319   if (verbose) {
00320     fprintf (stderr, "DVI Comment: %s\n", dvi_comment);
00321   }
00322   dev_add_comment (dvi_comment);
00323 }
00324 
00325 
00326 /* The section below this line deals with the actual processing of the
00327    dvi file.
00328 
00329    The dvi file processor state is contained in the following
00330    variables: */
00331 
00332 struct dvi_registers {
00333   SIGNED_QUAD h, v, w, x, y, z;
00334 };
00335 
00336 static struct dvi_registers dvi_state;
00337 static struct dvi_registers dvi_stack[DVI_MAX_STACK_DEPTH];
00338 static int current_font;
00339 static unsigned dvi_stack_depth = 0;  
00340 static int processing_page = 0;
00341 
00342 static void clear_state (void)
00343 {
00344   dvi_state.h = 0; dvi_state.v = 0; dvi_state.w = 0;
00345   dvi_state.x = 0; dvi_state.y = 0; dvi_state.z = 0;
00346   dvi_stack_depth = 0;
00347   current_font = -1;
00348 }
00349 
00350 
00351 double dvi_unit_size(void)
00352 {
00353   return dvi2pts;
00354 }
00355 
00356 int dvi_locate_font (char *tex_name, spt_t ptsize)
00357 {
00358   int thisfont;
00359   int font_id;
00360   if (debug) {
00361     fprintf (stderr, "dvi_locate_font: fontname: (%s) ptsize: %ld, dvi_id: %d\n",
00362             tex_name, ptsize, num_loaded_fonts);
00363   }
00364   if (verbose)
00365     fprintf (stderr, "<%s@%.2fpt", tex_name, ptsize*dvi2pts);
00366   need_more_fonts (1);
00367   /* This routine needs to be recursive/reentrant.  Load current high water
00368      mark into an automatic variable  */
00369   thisfont = num_loaded_fonts++;
00370   loaded_fonts[thisfont].tfm_id = tfm_open (tex_name);
00371   loaded_fonts[thisfont].source = VF; /* This will be reset later if 
00372                                  it was really generated by the
00373                                  dvi file */
00374   font_id = vf_locate_font (tex_name, ptsize);
00375   loaded_fonts[thisfont].font_id = font_id;
00376   if (loaded_fonts[thisfont].font_id >= 0) {
00377     if (verbose)
00378       fprintf (stderr, "(VF)");
00379     loaded_fonts[thisfont].type = VIRTUAL;
00380   } else {
00381     loaded_fonts[thisfont].type = PHYSICAL;
00382     font_id = dev_locate_font (tex_name, ptsize);
00383     loaded_fonts[thisfont].font_id = font_id;
00384     if (loaded_fonts[thisfont].font_id < 0) {
00385       fprintf (stderr, "%s: Can't locate a Type 1, TTF, PK, or virtual font file\n", tex_name);
00386       ERROR ("Not sure how to proceed.  For now this is fatal\n\
00387 Maybe in the future, I'll substitute some other font.");
00388     }
00389   }
00390   loaded_fonts[thisfont].size = ptsize;
00391   if (verbose)
00392     fprintf (stderr, ">");
00393   return (thisfont);
00394 }
00395 
00396 double dvi_dev_xpos(void) {
00397   return dvi_state.h*dvi2pts;
00398 }
00399 
00400 double dvi_dev_ypos (void)
00401 {
00402   return -(dvi_state.v*dvi2pts);
00403 }
00404 
00405 static void do_moveto (SIGNED_QUAD x, SIGNED_QUAD y)
00406 {
00407   dvi_state.h = x;
00408   dvi_state.v = y;
00409 }
00410 
00411 void dvi_right (SIGNED_QUAD x)
00412 {
00413   dvi_state.h += x;
00414 }
00415 
00416 void dvi_down (SIGNED_QUAD y)
00417 {
00418   dvi_state.v += y;
00419 }
00420 
00421 static void do_string (unsigned char *s, int len)
00422 {
00423   spt_t width = 0, height = 0, depth = 0;
00424   int i;
00425   struct loaded_font *p;
00426   if (debug) {
00427     int i;
00428     fprintf (stderr, "do_string: (font: %d)\n", current_font);
00429     for (i=0; i<len; i++) fputc (s[i], stderr);
00430     fputc ('\n', stderr);
00431   }
00432   
00433   if (current_font < 0) {
00434     ERROR ("do_string:  No font selected");
00435   }
00436   p = loaded_fonts+current_font;
00437   width = tfm_string_width (p->tfm_id, s, len);
00438   width = sqxfw (p->size, width);
00439   switch (p->type) {
00440   case PHYSICAL:
00441     dev_set_string (dvi_state.h, -dvi_state.v, s, len,
00442                   width, p->font_id);
00443     if (compute_boxes) {
00444       height = tfm_string_height (p->tfm_id, s, len);
00445       depth = tfm_string_depth (p->tfm_id, s, len);
00446       height = sqxfw (p->size, height);
00447       depth = sqxfw (p->size, depth);
00448       dev_expand_box (width, height, depth);
00449     }
00450     break;
00451   case VIRTUAL:
00452     dvi_push();
00453     for (i=0; i<len; i++) {
00454       dvi_set (s[i]);
00455     }
00456     dvi_pop();
00457   }
00458   dvi_state.h += width;
00459 }
00460 
00461 void dvi_set (SIGNED_QUAD ch)
00462 {
00463   spt_t width, height = 0, depth = 0;
00464   struct loaded_font *p;
00465   unsigned char lch;
00466   if (current_font < 0) {
00467     ERROR ("dvi_set:  No font selected");
00468   }
00469   /* The division by dvi2pts seems strange since we actually know the
00470      "dvi" size of the fonts contained in the DVI file.  In other
00471      words, we converted from DVI units to pts and back again!
00472      The problem comes from fonts defined in VF files where we don't know the DVI
00473      size.  It's keeping me sane to keep *point sizes* of *all* fonts in
00474      the dev.c file and convert them back if necessary */ 
00475   p = loaded_fonts+current_font;
00476   width = tfm_get_fw_width (p->tfm_id, ch);
00477   width = sqxfw (p->size, width);
00478   switch (p->type) {
00479   case PHYSICAL:
00480     if (ch > 255) {
00481       ERROR ("Tried to set a multibyte character in a non-virtual font");
00482     }
00483     lch = (unsigned char) ch;
00484     dev_set_string (dvi_state.h, -dvi_state.v, &lch, 1, width, p->font_id);
00485     if (compute_boxes) {
00486       height = tfm_get_fw_height (p->tfm_id, ch);
00487       depth = tfm_get_fw_depth (p->tfm_id, ch);
00488       height = sqxfw (p->size, height);
00489       depth = sqxfw (p->size, depth);
00490       dev_expand_box (width, height, depth);
00491     }
00492     break;
00493   case VIRTUAL:
00494     {
00495       vf_set_char (ch, p->font_id);
00496       break;
00497     }
00498   }
00499   dvi_state.h += width;
00500 }
00501 
00502 void dvi_put (SIGNED_QUAD ch)
00503 {
00504   spt_t width, height = 0, depth = 0;
00505   struct loaded_font *p;
00506   unsigned char lch;
00507   if (current_font < 0) {
00508     ERROR ("dvi_put:  No font selected");
00509   }
00510   p = loaded_fonts+current_font;
00511   switch (p->type) {
00512   case PHYSICAL:
00513     width = tfm_get_fw_width (p->tfm_id, ch);
00514     width = sqxfw (p->size, width);
00515     /* Treat a single character as a one byte string and use the
00516        string routine.  The possibly multi-byte character must
00517        be converted to a single-byte string */
00518     if (ch > 255) {
00519       ERROR ("Tried to set a multibyte character in a non-virtual font");
00520     }
00521     lch = (unsigned char) ch;
00522     dev_set_string (dvi_state.h, -dvi_state.v, &lch, 1, width, p->font_id);
00523     if (compute_boxes) {
00524       height = tfm_get_fw_height (p->tfm_id, ch);
00525       depth = tfm_get_fw_depth (p->tfm_id, ch);
00526       height = sqxfw (p->size, height);
00527       depth = sqxfw (p->size, depth);
00528       dev_expand_box (width, height, depth);
00529     }
00530     break;
00531   case VIRTUAL:    
00532     vf_set_char (ch, p->font_id);
00533     break;
00534   }
00535   return;
00536 }
00537 
00538 
00539 void dvi_rule (SIGNED_QUAD width, SIGNED_QUAD height)
00540 {
00541   do_moveto (dvi_state.h, dvi_state.v);
00542   dev_rule (dvi_state.h, -dvi_state.v,
00543            width, height);
00544 }
00545 
00546 static void do_set1(void)
00547 {
00548   dvi_set (get_unsigned_byte(dvi_file));
00549 }
00550 
00551 static void do_set2(void)
00552 {
00553   dvi_set (get_unsigned_pair(dvi_file));
00554 }
00555 
00556 static void do_setrule(void)
00557 {
00558   SIGNED_QUAD width, height;
00559   height = get_signed_quad (dvi_file);
00560   width = get_signed_quad (dvi_file);
00561   if (width > 0 && height > 0) {
00562     dvi_rule (width, height);
00563   }
00564   dvi_right (width);
00565 }
00566 
00567 static void do_putrule(void)
00568 {
00569   SIGNED_QUAD width, height;
00570   height = get_signed_quad (dvi_file);
00571   width = get_signed_quad (dvi_file);
00572   if (width > 0 && height > 0) {
00573     dvi_rule (width, height);
00574   }
00575 }
00576 
00577 static void do_put1(void)
00578 {
00579   dvi_put (get_unsigned_byte(dvi_file));
00580 }
00581 
00582 static void do_put2(void)
00583 {
00584   dvi_put (get_unsigned_pair(dvi_file));
00585 }
00586 
00587 void dvi_push (void) 
00588 {
00589   if (debug) {
00590     fprintf (stderr, "Pushing onto stack of depth %d\n",
00591             dvi_stack_depth);
00592   }
00593   if (dvi_stack_depth < DVI_MAX_STACK_DEPTH) {
00594     dvi_stack[dvi_stack_depth++] = dvi_state;
00595   }
00596   else
00597     ERROR ("DVI stack exceeded");
00598 }
00599 
00600 void dvi_pop (void)
00601 {
00602   if (debug) {
00603     fprintf (stderr, "Popping off stack of depth %d\n",
00604             dvi_stack_depth);
00605   }
00606   if (dvi_stack_depth > 0) {
00607     dvi_state = dvi_stack[--dvi_stack_depth];
00608   } else
00609     ERROR ("dvi_pop: Tried to pop an empty stack");
00610   do_moveto (dvi_state.h, dvi_state.v);
00611 }
00612 
00613 
00614 static void do_right1(void)
00615 {
00616   dvi_right (get_signed_byte(dvi_file));
00617 }
00618 
00619 static void do_right2(void)
00620 {
00621   dvi_right (get_signed_pair(dvi_file));
00622 }
00623 
00624 static void do_right3(void)
00625 {
00626   dvi_right (get_signed_triple(dvi_file));
00627 }
00628 
00629 static void do_right4(void)
00630 {
00631   dvi_right (get_signed_quad(dvi_file));
00632 }
00633 
00634 void dvi_w (SIGNED_QUAD ch)
00635 {
00636   dvi_state.w = ch;
00637   dvi_right (ch);
00638 }
00639 
00640 void dvi_w0(void)
00641 {
00642   dvi_right (dvi_state.w);
00643 }
00644 
00645 static void do_w1(void)
00646 {
00647   dvi_w (get_signed_byte(dvi_file));
00648 }
00649 
00650 static void do_w2(void)
00651 {
00652   dvi_w (get_signed_pair(dvi_file));
00653 }
00654 
00655 static void do_w3(void)
00656 {
00657   dvi_w (get_signed_triple(dvi_file));
00658 }
00659 
00660 static void do_w4(void)
00661 {
00662   dvi_w (get_signed_quad(dvi_file));
00663 }
00664 
00665 void dvi_x (SIGNED_QUAD ch)
00666 {
00667   dvi_state.x = ch;
00668   dvi_right (ch);
00669 }
00670 
00671 void dvi_x0(void)
00672 {
00673   dvi_right (dvi_state.x);
00674 }
00675 
00676 static void do_x1(void)
00677 {
00678   dvi_x (get_signed_byte(dvi_file));
00679 }
00680 
00681 static void do_x2(void)
00682 {
00683   dvi_x (get_signed_pair(dvi_file));
00684 }
00685 
00686 static void do_x3(void)
00687 {
00688   dvi_x (get_signed_triple(dvi_file));
00689 }
00690 
00691 static void do_x4(void)
00692 {
00693   dvi_x (get_signed_quad(dvi_file));
00694 }
00695 
00696 static void do_down1(void)
00697 {
00698   dvi_down (get_signed_byte(dvi_file));
00699 }
00700 
00701 static void do_down2(void)
00702 {
00703   dvi_down (get_signed_pair(dvi_file));
00704 }
00705 
00706 static void do_down3(void)
00707 {
00708   dvi_down (get_signed_triple(dvi_file));
00709 }
00710 
00711 static void do_down4(void)
00712 {
00713   dvi_down (get_signed_quad(dvi_file));
00714 }
00715 
00716 void dvi_y (SIGNED_QUAD ch)
00717 {
00718   dvi_state.y = ch;
00719   dvi_down (ch);
00720 }
00721 
00722 void dvi_y0(void)
00723 {
00724   dvi_down (dvi_state.y);
00725 }
00726 
00727 static void do_y1(void)
00728 {
00729   dvi_y (get_signed_byte(dvi_file));
00730 }
00731 
00732 static void do_y2(void)
00733 {
00734   dvi_y (get_signed_pair(dvi_file));
00735 }
00736 
00737 static void do_y3(void)
00738 {
00739   dvi_y (get_signed_triple(dvi_file));
00740 }
00741 
00742 static void do_y4(void)
00743 {
00744   dvi_y (get_signed_quad(dvi_file));
00745 }
00746 
00747 void dvi_z (SIGNED_QUAD ch)
00748 {
00749   dvi_state.z = ch;
00750   dvi_down (ch);
00751 }
00752 
00753 void dvi_z0(void)
00754 {
00755   dvi_down (dvi_state.z);
00756 }
00757 
00758 static void do_z1(void)
00759 {
00760   dvi_z (get_signed_byte(dvi_file));
00761 }
00762 
00763 static void do_z2(void)
00764 {
00765   dvi_z (get_signed_pair(dvi_file));
00766 }
00767 
00768 static void do_z3(void)
00769 {
00770   dvi_z (get_signed_triple(dvi_file));
00771 }
00772 
00773 static void do_z4(void)
00774 {
00775   dvi_z (get_signed_quad(dvi_file));
00776 }
00777 
00778 static void do_fntdef(void)
00779 {
00780   int area_len, name_len, i;
00781   get_signed_quad(dvi_file);
00782   get_signed_quad(dvi_file);
00783   get_signed_quad(dvi_file);
00784   area_len = get_unsigned_byte(dvi_file);
00785   name_len = get_unsigned_byte(dvi_file);
00786   for (i=0; i<area_len+name_len; i++) {
00787     get_unsigned_byte (dvi_file);
00788   }
00789 }
00790 
00791 static void do_fntdef1(void)
00792 {
00793   get_unsigned_byte(dvi_file);
00794   do_fntdef();
00795 }
00796 
00797 static void do_fntdef2(void)
00798 {
00799   get_unsigned_pair(dvi_file);
00800   do_fntdef();
00801 }
00802 
00803 static void do_fntdef3(void)
00804 {
00805   get_unsigned_triple(dvi_file);
00806   do_fntdef();
00807 }
00808 
00809 static void do_fntdef4(void)
00810 {
00811   get_signed_quad(dvi_file);
00812   do_fntdef();
00813 }
00814 
00815 
00816 void dvi_set_font (int font_id)
00817 {
00818   current_font = font_id;
00819 }
00820 
00821 static void do_fnt (SIGNED_QUAD tex_id)
00822 {
00823   int i;
00824   for (i=0; i<num_def_fonts; i++) {
00825     if (def_fonts[i].tex_id == tex_id)
00826       break;
00827   }
00828   if (i == num_def_fonts) {
00829     fprintf (stderr, "fontid: %ld\n", tex_id);
00830     ERROR ("dvi_do_fnt:  Tried to select a font that hasn't been defined");
00831   }
00832   if (!def_fonts[i].used) {
00833     int font_id;
00834     font_id = dvi_locate_font (def_fonts[i].name, def_fonts[i].size);
00835     loaded_fonts[font_id].source = DVI;
00836     def_fonts[i].used = 1;
00837     def_fonts[i].font_id = font_id;
00838   }
00839   current_font = def_fonts[i].font_id;
00840 }
00841 
00842 static void do_fnt1(void)
00843 {
00844   SIGNED_QUAD font;
00845   font = get_unsigned_byte(dvi_file);
00846   do_fnt(font);
00847 }
00848 
00849 static void do_fnt2(void)
00850 {
00851   SIGNED_QUAD font;
00852   font = get_unsigned_pair(dvi_file);
00853   do_fnt(font);
00854 }
00855 
00856 static void do_fnt3(void)
00857 {
00858   SIGNED_QUAD font;
00859   font = get_unsigned_triple(dvi_file);
00860   do_fnt(font);
00861 }
00862 
00863 static void do_fnt4(void)
00864 {
00865   SIGNED_QUAD font;
00866   font = get_signed_quad(dvi_file);
00867   do_fnt(font);
00868 }
00869 
00870 static void do_xxx(UNSIGNED_QUAD size) 
00871 {
00872   UNSIGNED_QUAD i;
00873   Ubyte *buffer;
00874   buffer = NEW (size+1, Ubyte);
00875   for (i=0; i<size; i++) {
00876     buffer[i] = get_unsigned_byte(dvi_file);
00877   }
00878   if (debug)
00879     fprintf (stderr, "Special: %s\n", buffer);
00880   dev_do_special (buffer, size, dvi_state.h, dvi_state.v);
00881   RELEASE (buffer);
00882 }
00883 
00884 static void do_xxx1(void)
00885 {
00886   SIGNED_QUAD size;
00887   if (debug)
00888     fprintf (stderr, "(xxx1)");
00889   size = get_unsigned_byte(dvi_file);
00890   do_xxx(size);
00891 }
00892 
00893 static void do_xxx2(void)
00894 {
00895   SIGNED_QUAD size;
00896   size = get_unsigned_pair(dvi_file);
00897   do_xxx(size);
00898 }
00899 
00900 static void do_xxx3(void)
00901 {
00902   SIGNED_QUAD size;
00903   size = get_unsigned_triple(dvi_file);
00904   do_xxx(size);
00905 }
00906 
00907 static void do_xxx4(void)
00908 {
00909   SIGNED_QUAD size;
00910   size = get_unsigned_quad(dvi_file);
00911   do_xxx(size);
00912 }
00913 
00914 static void do_bop(void)
00915 {
00916   int i;
00917   if (processing_page) 
00918     ERROR ("dvi_do_bop:  Got a bop inthe middle of a page");
00919   /* For now, ignore TeX's count registers */
00920   for (i=0; i<10; i++) {
00921     get_signed_quad (dvi_file);
00922   }
00923 /*  Ignore previous page pointer since we have already saved this
00924     information */
00925   get_signed_quad (dvi_file);
00926   clear_state();
00927   processing_page = 1;
00928   dev_bop();
00929 }
00930 
00931 static void do_eop(void)
00932 {
00933   processing_page = 0;
00934   if (dvi_stack_depth != 0) {
00935     ERROR ("do_eop:  stack_depth is not zero at end of page");
00936   }
00937   dev_eop();
00938 }
00939 /* Note to be absolutely certain that the string escape buffer doesn't
00940    hit its limit, FORMAT_BUF_SIZE should set to 4 times S_BUFFER_SIZE
00941    in pdfobj.c.  Is there any application that genenerate words with
00942    1k characters? */
00943 
00944 #define S_BUFFER_SIZE 1024
00945 static unsigned char s_buffer[S_BUFFER_SIZE];
00946 static unsigned s_len = 0;
00947 
00948 void dvi_do_page(unsigned n)  /* Most of the work of actually interpreting
00949                          the dvi file is here. */
00950 {
00951   unsigned char opcode;
00952   /* Position to beginning of page */
00953   if (debug) fprintf (stderr, "Seeking to page %d @ %ld\n", n,
00954                        page_loc[n]);
00955   seek_absolute (dvi_file, page_loc[n]);
00956   dvi_stack_depth = 0;
00957   for (;;) {
00958     /* The most likely opcodes are individual setchars.  These are
00959        buffered for speed */
00960     s_len = 0;
00961     while ((opcode = fgetc (dvi_file)) <= SET_CHAR_127 &&
00962           s_len < S_BUFFER_SIZE) {
00963       s_buffer[s_len++] = opcode;
00964     }
00965     if (s_len > 0) {
00966       do_string (s_buffer, s_len);
00967     }
00968     if (s_len == S_BUFFER_SIZE)
00969       continue;
00970     /* If we are here, we have an opcode that is something
00971        other than SET_CHAR */
00972     if (opcode >= FNT_NUM_0 && opcode <= FNT_NUM_63) {
00973       do_fnt (opcode - FNT_NUM_0);
00974       continue;
00975     }
00976     switch (opcode)
00977       {
00978       case SET1:
00979        do_set1();
00980        break;
00981       case SET2:
00982        do_set2();
00983        break;
00984       case SET3:
00985       case SET4:
00986        ERROR ("Multibyte (>16 bits) character in DVI file.  I can't handle this!");
00987        break;
00988       case SET_RULE:
00989        do_setrule();
00990        break;
00991       case PUT1:
00992        do_put1();
00993        break;
00994       case PUT2:
00995        do_put2();
00996        break;
00997       case PUT3:
00998       case PUT4:
00999        ERROR ("Multibyte character (>16 bits) in DVI file.  I can't handle this!");
01000        break;
01001       case PUT_RULE:
01002        do_putrule();
01003        break;
01004       case NOP:
01005        break;
01006       case BOP:
01007        do_bop();
01008        break;
01009       case EOP:
01010        do_eop();
01011        return;
01012       case PUSH:
01013        dvi_push();
01014        /* The following line needs to go here instead of in
01015           dvi_push() since logical structure of document is
01016           oblivous to virtual fonts. For example the last line on a
01017           page could be at stack level 3 and the page footer should
01018           be at stack level 3.  However, if the page footer contains
01019           virtual fonts (or other nested constructions), it could
01020           fool the link breaker into thinking it was a continuation
01021           of the link */
01022        dev_stack_depth (dvi_stack_depth);
01023        break;
01024       case POP:
01025        dvi_pop();
01026        /* Above explanation holds for following line too */
01027        dev_stack_depth (dvi_stack_depth);
01028        break;
01029       case RIGHT1:
01030        do_right1();
01031        break;
01032       case RIGHT2:
01033        do_right2();
01034        break;
01035       case RIGHT3:
01036        do_right3();
01037        break;
01038       case RIGHT4:
01039        do_right4();
01040        break;
01041       case W0:
01042        dvi_w0();
01043        break;
01044       case W1:
01045        do_w1();
01046        break;
01047       case W2:
01048        do_w2();
01049        break;
01050       case W3:
01051        do_w3();
01052        break;
01053       case W4:
01054        do_w4();
01055        break;
01056       case X0:
01057        dvi_x0();
01058        break;
01059       case X1:
01060        do_x1();
01061        break;
01062       case X2:
01063        do_x2();
01064        break;
01065       case X3:
01066        do_x3();
01067        break;
01068       case X4:
01069        do_x4();
01070        break;
01071       case DOWN1:
01072        do_down1();
01073        break;
01074       case DOWN2:
01075        do_down2();
01076        break;
01077       case DOWN3:
01078        do_down3();
01079        break;
01080       case DOWN4:
01081        do_down4();
01082        break;
01083       case Y0:
01084        dvi_y0();
01085        break;
01086       case Y1:
01087        do_y1();
01088        break;
01089       case Y2:
01090        do_y2();
01091        break;
01092       case Y3:
01093        do_y3();
01094        break;
01095       case Y4:
01096        do_y4();
01097        break;
01098       case Z0:
01099        dvi_z0();
01100        break;
01101       case Z1:
01102        do_z1();
01103        break;
01104       case Z2:
01105        do_z2();
01106        break;
01107       case Z3:
01108        do_z3();
01109        break;
01110       case Z4:
01111        do_z4();
01112        break;
01113       case FNT1:
01114        do_fnt1();
01115        break;
01116       case FNT2:
01117        do_fnt2();
01118        break;
01119       case FNT3:
01120        do_fnt3();
01121        break;
01122       case FNT4:
01123        do_fnt4();
01124        break;
01125       case XXX1:
01126        do_xxx1();
01127        break;
01128       case XXX2:
01129        do_xxx2();
01130        break;
01131       case XXX3:
01132        do_xxx3();
01133        break;
01134       case XXX4:
01135        do_xxx4();
01136        break;
01137       case FNT_DEF1:
01138        do_fntdef1();
01139        break;
01140       case FNT_DEF2:
01141        do_fntdef2();
01142        break;
01143       case FNT_DEF3:
01144        do_fntdef3();
01145        break;
01146       case FNT_DEF4:
01147        do_fntdef4();
01148        break;
01149       case PRE:
01150       case POST:
01151       case POST_POST:
01152        ERROR("Unexpected preamble or postamble in dvi file");
01153        break;
01154       default:
01155        ERROR("Unexpected opcode or DVI file ended prematurely");
01156       }
01157   }
01158 }
01159 
01160 error_t dvi_init (char *dvi_filename, char *pdf_filename, double mag, double x_offset, double
01161                 y_offset)
01162 {
01163   if (!(dvi_file = MFOPEN (dvi_filename, FOPEN_RBIN_MODE))) {
01164     ERROR ("dvi_init:  Specified DVI file doesn't exist");
01165     return (FATAL_ERROR);
01166   }
01167   /* DVI files are most easily read backwards by searching
01168      for post_post and then post opcode */
01169   find_post ();
01170   get_dvi_info();
01171   do_scales(mag);
01172   dev_init(dvi2pts, x_offset, y_offset);
01173   get_page_info();
01174   pdf_doc_init (pdf_filename);
01175   get_comment();
01176   get_dvi_fonts();
01177   clear_state();
01178   return (NO_ERROR);
01179 }
01180 
01181 void dvi_close (void)
01182 {
01183   int i;
01184   /* We add comment in dvi_close instead of dvi_init so user has
01185      a change to overwrite it.  The docinfo dictionary is
01186      treated as a write-once record */
01187 
01188   /* Do some house cleaning */
01189   MFCLOSE (dvi_file);
01190   for (i=0; i<num_def_fonts; i++) {
01191     RELEASE (def_fonts[i].name);
01192   }
01193   if (def_fonts)
01194     RELEASE (def_fonts);
01195   RELEASE (page_loc);
01196   num_loaded_fonts = 0;
01197   if (loaded_fonts)
01198     RELEASE (loaded_fonts);
01199   num_pages = 0;
01200   dvi_file = NULL;
01201   dev_close_all_fonts();
01202   vf_close_all_fonts();
01203   tfm_close_all();
01204   dev_close();
01205   pdf_doc_close();
01206 }
01207 
01208 /* The following are need to implement virtual fonts
01209    According to documentation, the vf "subroutine"
01210    must have state pushed and must have
01211    w,v,y, and z set to zero.  The current font
01212    is determined by the virtual font header, which
01213    may be undefined */
01214 
01215 static int saved_dvi_font[MAX_VF_NESTING];
01216 static int num_saved_fonts = 0;
01217 
01218 void dvi_vf_init (int dev_font_id)
01219 {
01220   dvi_push ();
01221   dvi_state.w = 0; dvi_state.x = 0;
01222   dvi_state.y = 0; dvi_state.z = 0;
01223   if (num_saved_fonts < MAX_VF_NESTING) {
01224     saved_dvi_font[num_saved_fonts++] = current_font;
01225   } else
01226     ERROR ("Virtual fonts nested too deeply!");
01227   current_font = dev_font_id;
01228 }
01229 
01230 /* After VF subroutine is finished, we simply pop the DVI stack */
01231 void dvi_vf_finish (void)
01232 {
01233   dvi_pop();
01234   if (num_saved_fonts > 0) 
01235     current_font = saved_dvi_font[--num_saved_fonts];
01236   else
01237     ERROR ("Tried to pop an empty font stack");
01238 }