Back to index

tetex-bin  3.0
dvi.c
Go to the documentation of this file.
00001 /* dvi.c */
00002 
00003 /************************************************************************
00004 
00005   Part of the dvipng distribution
00006 
00007   This program is free software; you can redistribute it and/or modify
00008   it under the terms of the GNU General Public License as published by
00009   the Free Software Foundation; either version 2 of the License, or
00010   (at your option) any later version.
00011 
00012   This program is distributed in the hope that it will be useful, but
00013   WITHOUT ANY WARRANTY; without even the implied warranty of
00014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015   General Public License for more details.
00016 
00017   You should have received a copy of the GNU General Public License
00018   along with this program; if not, write to the Free Software
00019   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00020   02111-1307, USA.
00021 
00022   Copyright (C) 2002-2005 Jan-Åke Larsson
00023 
00024 ************************************************************************/
00025 
00026 #include "dvipng.h"
00027 #ifdef MIKTEX
00028 # include <gnu-miktex.h>
00029 # define SLEEP    Sleep(1000)
00030 #else  /* MIKTEX */
00031 # ifdef HAVE_LIBGEN_H
00032 #  include <libgen.h>
00033 # else
00034 # define basename xbasename
00035 #endif
00036 # define SLEEP    sleep(1)
00037 #endif /* MIKTEX */
00038 #include <sys/stat.h>
00039 
00040 bool followmode=0;
00041 
00042 bool DVIFollowToggle()
00043 {
00044   return followmode = ! followmode;
00045 }
00046 
00047 static unsigned char fgetc_follow(FILE* fp)
00048 {
00049   int got=fgetc(fp);
00050 
00051   while(followmode && got==EOF) {
00052     SLEEP;
00053     got=fgetc(fp);
00054   }
00055   if (got==EOF)
00056     Fatal("DVI file ends prematurely");
00057   return (unsigned char)got;
00058 }
00059 
00060 void DVIInit(struct dvi_data* dvi)
00061 {
00062   int     k;
00063   unsigned char* pre;
00064   struct stat stat;
00065 
00066   fseek(dvi->filep,0,SEEK_SET);
00067   pre=DVIGetCommand(dvi);
00068   if (*pre != PRE) {
00069     Fatal("PRE doesn't occur first--are you sure this is a DVI file?\n\n");
00070   }
00071   k = UNumRead(pre+1,1);
00072   DEBUG_PRINT(DEBUG_DVI,("DVI START:\tPRE %d",k));
00073   if (k != DVIFORMAT) {
00074     Fatal("DVI format = %d, can only process DVI format %d files\n\n",
00075          k, DVIFORMAT);
00076   }
00077   dvi->num = UNumRead(pre+2, 4);
00078   dvi->den = UNumRead(pre+6, 4);
00079   DEBUG_PRINT(DEBUG_DVI,(" %d/%d",dvi->num,dvi->den));
00080   dvi->mag = UNumRead(pre+10, 4); /*FIXME, see font.c*/
00081   DEBUG_PRINT(DEBUG_DVI,(" %d",dvi->mag));
00082   if ( usermag > 0 && usermag != dvi->mag ) {
00083     Warning("DVI magnification of %d over-ridden by user (%ld)",
00084            (long)dvi->mag, usermag );
00085     dvi->mag = usermag;
00086   }
00087   dvi->conv = (1.0/(((double)dvi->num / (double)dvi->den) *
00088                   ((double)dvi->mag / 1000.0) *
00089                   ((double)dpi*shrinkfactor/254000.0)))+0.5;
00090   DEBUG_PRINT(DEBUG_DVI,(" (%d)",dvi->conv));
00091   k = UNumRead(pre+14,1);
00092   DEBUG_PRINT(DEBUG_DVI,(" '%.*s'",k,pre+15));
00093   Message(BE_VERBOSE,"'%.*s' -> %s\n",k,pre+15,dvi->outname);
00094   fstat(fileno(dvi->filep), &stat);
00095   dvi->mtime = stat.st_mtime;
00096   dvi->pagelistp=NULL;
00097 }
00098 
00099 struct dvi_data* DVIOpen(char* dviname,char* outname)
00100 {
00101   char* tmpstring;
00102   struct dvi_data* dvi;
00103 
00104   if ((dvi = calloc(1,sizeof(struct dvi_data)))==NULL)
00105     Fatal("cannot allocate memory for dvi struct");
00106 
00107   dvi->type = DVI_TYPE;
00108   dvi->fontnump=NULL;
00109 
00110   dvi->name = malloc(strlen(dviname)+5);
00111   if (dvi->name==NULL)
00112     Fatal("cannot allocate space for DVI filename");
00113   strcpy(dvi->name, dviname);
00114   tmpstring = strrchr(dvi->name, '.');
00115   if (tmpstring == NULL || strcmp(tmpstring,".dvi") != 0) 
00116     strcat(dvi->name, ".dvi");
00117   
00118   if (outname==NULL) { 
00119     dvi->outname = malloc(strlen(basename(dviname))+7);
00120     if (dvi->outname==NULL) {
00121       free(dvi->name);
00122       free(dvi);
00123       Fatal("cannot allocate space for output filename");
00124     }
00125     strcpy(dvi->outname,basename(dviname));
00126     tmpstring = strrchr(dvi->outname, '.');
00127     if (tmpstring != NULL) 
00128       *tmpstring = '\0';
00129     strcat(dvi->outname, "%d.png");
00130   } else {
00131     dvi->outname = malloc(strlen(outname)+1);
00132     if (dvi->outname==NULL) {
00133       free(dvi->name);
00134       free(dvi);
00135       Fatal("cannot allocate space for output filename");
00136     }
00137     strcpy(dvi->outname,outname);
00138   }
00139 
00140   if ((dvi->filep = fopen(dvi->name,"rb")) == NULL) {
00141     /* do not insist on .dvi */
00142     tmpstring = strrchr(dvi->name, '.');
00143     *tmpstring='\0';
00144     dvi->filep = fopen(dvi->name,"rb");
00145   }
00146   while((dvi->filep == NULL) && followmode) {
00147     SLEEP;
00148     *tmpstring='.';
00149     if ((dvi->filep = fopen(dvi->name,"rb")) == NULL) {
00150       /* do not insist on .dvi */
00151       *tmpstring='\0';
00152       dvi->filep = fopen(dvi->name,"rb");
00153     }
00154   }
00155   if (dvi->filep == NULL) {
00156     free(dvi->name);
00157     free(dvi->outname);
00158     free(dvi);
00159     perror(dviname);
00160     exit (EXIT_FAILURE);
00161   }
00162   DEBUG_PRINT(DEBUG_DVI,("OPEN FILE\t%s", dvi->name));
00163   DVIInit(dvi);
00164   return(dvi);
00165 }
00166 
00167 unsigned char* DVIGetCommand(struct dvi_data* dvi)
00168      /* This function reads in and stores the next dvi command. */
00169      /* Mmap is not appropriate here, we may want to read from
00170        half-written files. */
00171 { 
00172   static unsigned char command[STRSIZE];
00173   static unsigned char* lcommand = command;
00174   unsigned char *current = command;
00175   int length;
00176   uint32_t strlength=0;
00177 
00178   DEBUG_PRINT(DEBUG_DVI,("\n@%ld ", ftell(dvi->filep)));
00179   *(current++) = fgetc_follow(dvi->filep);
00180   length = dvi_commandlength[*command];
00181   if (length < 0)
00182     Fatal("undefined DVI op-code %d",*command);
00183   while(current < command+length) 
00184     *(current++) = fgetc_follow(dvi->filep);
00185   switch (*command)  {
00186   case XXX4:
00187     strlength =                   *(current - 4);
00188   case XXX3:
00189     strlength = strlength * 256 + *(current - 3);
00190   case XXX2: 
00191     strlength = strlength * 256 + *(current - 2);
00192   case XXX1:
00193     strlength = strlength * 256 + *(current - 1);
00194     break;
00195   case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4:
00196     strlength = *(current - 1) + *(current - 2);
00197     break;
00198   case PRE: 
00199     strlength = *(current - 1);
00200     break;
00201   }
00202   if (strlength > 0) { /* Read string */
00203     if (lcommand!=command) {
00204       free(lcommand);
00205       lcommand=command;
00206     }
00207     if (strlength + (uint32_t)length >  (uint32_t)STRSIZE) {
00208       /* string + command length exceeds that of buffer */
00209       if ((lcommand=malloc(length+strlength+1))==NULL) 
00210        Fatal("cannot allocate memory for DVI command");
00211       memcpy(lcommand,command,length);
00212       current = lcommand + length;
00213     }
00214     while(current < lcommand+length+strlength) 
00215       *(current++) = fgetc_follow(dvi->filep);
00216     return(lcommand);
00217   } else
00218     return(command);
00219 }
00220 
00221 
00222 uint32_t CommandLength(unsigned char* command)
00223 { 
00224   /* generally 2^32+5 bytes max, but in practice 32 bit numbers suffice */
00225   uint32_t length=0;
00226 
00227   length = dvi_commandlength[*command];
00228   switch (*command)  {
00229   case XXX1: case XXX2: case XXX3: case XXX4: 
00230     length += UNumRead(command + 1,length - 1);
00231     break;
00232   case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4: 
00233     length += *(command + length - 1) + *(command + length - 2);
00234     break;
00235   case PRE: 
00236     length += *(command + length - 1);
00237     break;
00238   }
00239   return(length);
00240 }
00241 
00242 void SkipPage(struct dvi_data* dvi)
00243 { 
00244   /* Skip present page */
00245   unsigned char* command;           
00246 
00247   command=DVIGetCommand(dvi);
00248   while (*command != EOP)  {
00249     switch (*command)  {
00250     case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4:
00251       DEBUG_PRINT(DEBUG_DVI,("NOSKIP CMD:\t%s", dvi_commands[*command]));
00252       FontDef(command,dvi);
00253       break;
00254     case XXX1: case XXX2: case XXX3: case XXX4:
00255       DEBUG_PRINT(DEBUG_DVI,("NOSKIP CMD:\t%s %d", dvi_commands[*command],
00256                           UNumRead(command+1, dvi_commandlength[*command]-1)));
00257       SetSpecial((char*)command + dvi_commandlength[*command], 
00258                UNumRead(command+1, dvi_commandlength[*command]-1),
00259                0,0);
00260       break;
00261     case BOP: case PRE: case POST: case POST_POST:
00262       Fatal("%s occurs within page", dvi_commands[*command]);
00263       break;
00264 #ifdef DEBUG
00265     default:
00266       DEBUG_PRINT(DEBUG_DVI,("SKIP CMD:\t%s", dvi_commands[*command]));
00267 #endif
00268     }
00269     command=DVIGetCommand(dvi);
00270   } /* while */
00271   DEBUG_PRINT(DEBUG_DVI,("SKIP CMD:\t%s", dvi_commands[*command]));
00272 }
00273 
00274 struct page_list* InitPage(struct dvi_data* dvi)
00275 {
00276   /* Find page start, return pointer to page_list entry if found */
00277   struct page_list* tpagelistp=NULL;
00278   unsigned char* command;           
00279 
00280   command=DVIGetCommand(dvi);
00281   /* Skip until page start or postamble */
00282   while((*command != BOP) && (*command != POST)) {
00283     switch(*command) {
00284     case FNT_DEF1: case FNT_DEF2: case FNT_DEF3: case FNT_DEF4:
00285       DEBUG_PRINT(DEBUG_DVI,("NOPAGE CMD:\t%s", dvi_commands[*command]));
00286       FontDef(command,dvi);
00287       break;
00288     case NOP:
00289       DEBUG_PRINT(DEBUG_DVI,("NOPAGE CMD:\tNOP"));
00290       break;
00291     default:
00292       Fatal("%s occurs outside page", dvi_commands[*command]);
00293     }
00294     command=DVIGetCommand(dvi);
00295   }
00296   if ((tpagelistp = 
00297        malloc(sizeof(struct page_list)+(csp+1-2)*sizeof(struct dvi_color)))==NULL)
00298     Fatal("cannot allocate memory for new page entry");
00299   tpagelistp->next = NULL;
00300   if ( *command == BOP ) {  /*  Init page */
00301     int i;
00302     DEBUG_PRINT(DEBUG_DVI,("PAGE START:\tBOP"));
00303     StoreColorStack(tpagelistp);
00304     tpagelistp->offset = ftell(dvi->filep)-45;
00305     for (i = 0; i <= 9; i++) {
00306       tpagelistp->count[i] = UNumRead(command + 1 + i*4, 4);
00307       DEBUG_PRINT(DEBUG_DVI,(" %d",tpagelistp->count[i]));
00308     }
00309     if (dvi->pagelistp==NULL) 
00310       tpagelistp->count[10] = 1;
00311     else
00312       tpagelistp->count[10] = dvi->pagelistp->count[10]+1;
00313     DEBUG_PRINT(DEBUG_DVI,(" (%d)", tpagelistp->count[10]));
00314   } else {
00315     DEBUG_PRINT(DEBUG_DVI,("DVI END:\tPOST"));
00316     tpagelistp->offset = ftell(dvi->filep)-1;
00317     tpagelistp->count[0] = PAGE_POST; /* POST */
00318     tpagelistp->count[10] = PAGE_POST; /* POST */
00319   }
00320   return(tpagelistp);
00321 }
00322 
00323 int SeekPage(struct dvi_data* dvi, struct page_list* page)
00324 {
00325   ReadColorStack(page);
00326   return(fseek(dvi->filep, 
00327               page->offset+((page->count[0]==PAGE_POST) ? 1L : 45L),
00328               SEEK_SET));
00329 }
00330 
00331 struct page_list* NextPage(struct dvi_data* dvi, struct page_list* page)
00332 {
00333   struct page_list* tpagelistp;
00334 
00335   /* if page points to POST there is no next page */
00336   if (page!=NULL && page->count[0]==PAGE_POST) 
00337     return(NULL);
00338 
00339   /* If we have read past the last page in our current list or the
00340    *  list is empty, sneak a look at the next page
00341    */
00342   if (dvi->pagelistp==NULL
00343       || dvi->pagelistp->offset+45L < ftell(dvi->filep)) {
00344     tpagelistp=dvi->pagelistp;
00345     dvi->pagelistp=InitPage(dvi);
00346     dvi->pagelistp->next=tpagelistp;
00347   }
00348 
00349   if (page!=dvi->pagelistp) {
00350     /* also works if page==NULL, we'll get the first page then */
00351     tpagelistp=dvi->pagelistp;
00352     while(tpagelistp!=NULL && tpagelistp->next!=page)
00353       tpagelistp=tpagelistp->next;
00354   } else {
00355     /* dvi->pagelistp points to the last page we've read so far,
00356      * the last page that we know where it is, so to speak
00357      * So look at the next
00358      */
00359     (void)SeekPage(dvi,dvi->pagelistp);
00360     SkipPage(dvi);
00361     tpagelistp=dvi->pagelistp;
00362     dvi->pagelistp=InitPage(dvi);
00363     dvi->pagelistp->next=tpagelistp;
00364     tpagelistp=dvi->pagelistp;
00365   }
00366   return(tpagelistp);
00367 }
00368 
00369 struct page_list* PrevPage(struct dvi_data* dvi, struct page_list* page)
00370 {
00371   return(page->next);
00372 }
00373 
00374 
00375 struct page_list* FindPage(struct dvi_data* dvi, int32_t pagenum, bool abspage)
00376      /* Find first page of certain number, 
00377        absolute number if abspage is set */
00378 {
00379   struct page_list* page=NextPage(dvi, NULL);
00380   
00381   if (pagenum==PAGE_LASTPAGE || pagenum==PAGE_POST) {
00382     while(page!=NULL && page->count[0]!=PAGE_POST)
00383       page=NextPage(dvi,page);
00384     if (pagenum==PAGE_LASTPAGE)
00385       page=PrevPage(dvi,page);
00386   } else
00387     if (pagenum!=PAGE_FIRSTPAGE) 
00388       while(page != NULL && pagenum != page->count[abspage ? 0 : 10])
00389        page=NextPage(dvi,page);
00390   return(page);
00391 }
00392 
00393 
00394 void DelPageList(struct dvi_data* dvi)
00395 {
00396   struct page_list* temp;
00397   
00398   /* Delete the page list */
00399 
00400   temp=dvi->pagelistp;
00401   while(temp!=NULL) {
00402     dvi->pagelistp=dvi->pagelistp->next;
00403     free(temp);
00404     temp=dvi->pagelistp;
00405   }
00406 }
00407 
00408 void DVIClose(struct dvi_data* dvi)
00409 {
00410   if (dvi!=NULL) {
00411     fclose(dvi->filep);
00412     DelPageList(dvi);
00413     free(dvi->outname);
00414     free(dvi->name);
00415     free(dvi);
00416   }
00417 }
00418 
00419 bool DVIReOpen(struct dvi_data* dvi)
00420 {
00421   struct stat stat;
00422   fstat(fileno(dvi->filep), &stat);
00423   if (dvi->mtime != stat.st_mtime) {
00424     fclose(dvi->filep);
00425     dvi->filep=NULL;
00426     DelPageList(dvi);
00427     while(((dvi->filep = fopen(dvi->name,"rb")) == NULL) && followmode) {
00428       SLEEP;
00429     }
00430     if (dvi->filep == NULL) {
00431       perror(dvi->name);
00432       exit(EXIT_FAILURE);
00433     }
00434     Message(PARSE_STDIN,"Reopened file\n");
00435     DEBUG_PRINT(DEBUG_DVI,("\nREOPEN FILE\t%s", dvi->name));
00436     DVIInit(dvi);
00437     return(true);
00438   }
00439   return(false);
00440 }