Back to index

tetex-bin  3.0
t1subset.c
Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002   ----- File:        t1subset.c 
00003   ----- Author:      Rainer Menzner (Rainer.Menzner@web.de)
00004   ----- Date:        2002-12-08
00005   ----- Description: This file is part of the t1-library. It contains
00006                      functions for subsetting type 1 fonts.
00007   ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2002. 
00008                      As of version 0.5, t1lib is distributed under the
00009                    GNU General Public Library Lincense. The
00010                    conditions can be found in the files LICENSE and
00011                    LGPL, which should reside in the toplevel
00012                    directory of the distribution.  Please note that 
00013                    there are parts of t1lib that are subject to
00014                    other licenses:
00015                    The parseAFM-package is copyrighted by Adobe Systems
00016                    Inc.
00017                    The type1 rasterizer is copyrighted by IBM and the
00018                    X11-consortium.
00019   ----- Warranties:  Of course, there's NO WARRANTY OF ANY KIND :-)
00020   ----- Credits:     I want to thank IBM and the X11-consortium for making
00021                      their rasterizer freely available.
00022                    Also thanks to Piet Tutelaers for his ps2pk, from
00023                    which I took the rasterizer sources in a format
00024                    independent from X11.
00025                      Thanks to all people who make free software living!
00026 --------------------------------------------------------------------------*/
00027   
00028 #define T1SUBSET_C
00029 
00030 
00031 #include <stdio.h>
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <fcntl.h>
00035 #if defined(_MSC_VER)
00036 # include <io.h>
00037 # include <sys/types.h>
00038 # include <sys/stat.h>
00039 #else
00040 # include <unistd.h>
00041 #endif
00042 #include <stdlib.h>
00043 #include <math.h>
00044 #include <string.h>
00045 
00046 #include "../type1/ffilest.h" 
00047 #include "../type1/types.h"
00048 #include "parseAFM.h" 
00049 #include "../type1/objects.h"
00050 #include "../type1/spaces.h"
00051 #include "../type1/util.h"
00052 #include "../type1/fontfcn.h"
00053 #include "../type1/regions.h"
00054 
00055 
00056 #include "t1types.h"
00057 #include "t1extern.h"
00058 #include "t1finfo.h"
00059 #include "t1misc.h"
00060 #include "t1base.h"
00061 #include "t1delete.h"
00062 #include "t1subset.h"
00063 
00064 /* Segment header for pfb-files (reminder):
00065 
00066    Segment-header:
00067 
00068    Byte 1:    always 128 (0x80)
00069    
00070    Byte 2:    1 = ASCII text
00071               2 = Binary text
00072              3 = End of file indicator (EOF)
00073    
00074    Byte 3:    least significant byte \
00075    Byte 4:                            \   Length of 
00076    Byte 5:                            /   data segment in bytes
00077    Byte 6:    most significant byte  /
00078   
00079  */
00080 #define SEGMENT_ASCII       1
00081 #define SEGMENT_BINARY      2
00082 #define SEGMENT_EOF         3
00083 
00084 
00085 
00086 static char *charstringP;
00087 static int  charstringL;
00088 
00089 
00090 /* We define two lookup tables to make a fast conversion from
00091    binary bytes to ASCII-hex bytes. */
00092 static unsigned char highHexByte[256]={
00093   0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
00094   0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,
00095   0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,0x32,
00096   0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
00097   0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,
00098   0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,
00099   0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
00100   0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,0x37,
00101   0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,
00102   0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,
00103   0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
00104   0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
00105   0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,
00106   0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
00107   0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,
00108   0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46
00109 };
00110 static unsigned char lowHexByte[256]={
00111   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00112   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00113   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00114   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00115   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00116   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00117   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00118   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00119   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00120   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00121   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00122   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00123   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00124   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00125   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,
00126   0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46
00127 };
00128   
00129 
00130 /* parameters for eexec encryption */
00131 static unsigned short int eexec_r;
00132 static unsigned short int eexec_c1=52845;
00133 static unsigned short int eexec_c2=22719;
00134 
00135 /* Eexec-encrption according to the Adobe Black Book */
00136 static unsigned char EexecEncrypt( unsigned char plain) 
00137 {
00138   
00139   unsigned char cipher;
00140   
00141   cipher = (plain ^ (eexec_r>>8));
00142   eexec_r = (cipher + eexec_r) * eexec_c1 + eexec_c2;
00143   return( cipher);
00144 }
00145 
00146 
00147 
00148 static int locateCharString( int FontID, char *charname) 
00149 {
00150 
00151   int namelen;
00152   int dictlen;
00153   int i;
00154   psdict *CharStringsP;
00155   
00156 
00157   namelen=strlen( charname);
00158 
00159   CharStringsP=pFontBase->pFontArray[FontID].pType1Data->CharStringsP;
00160   
00161   dictlen=CharStringsP[0].key.len;
00162   for ( i=1; i<=dictlen; i++) {
00163     if (namelen==CharStringsP[i].key.len) {
00164       /* This could be the charstring in question */
00165       if (strncmp( charname,
00166                  CharStringsP[i].key.data.nameP,
00167                  namelen)==0) {
00168        /* It is the the desired charstring */
00169        charstringP=CharStringsP[i].value.data.valueP;
00170        charstringL=CharStringsP[i].value.len;
00171        return( i);
00172       }
00173     }
00174   }
00175   /* charstring not found ??? */
00176   return( 0);
00177   
00178 }
00179 
00180 
00181 
00182 static int make_pfb_segment_header( char *ptr, int type, unsigned long size) 
00183 {
00184   ptr[0]=(char) 0x80;
00185   ptr[1]=type;
00186   if (type==3)
00187     return( 2);
00188   ptr[2]=(char)(size & 0xFF);
00189   ptr[3]=(char)((size>>8) & 0xFF);
00190   ptr[4]=(char)((size>>16) & 0xFF);
00191   ptr[5]=(char)((size>>24) & 0xFF);
00192   return( 6);
00193 }
00194 
00195 
00196 
00197 
00198 /* A function for reading a Type 1 font file. eexec-decryption
00199    is done on the fly.  */
00200 char *T1_SubsetFont( int FontID,
00201                    char *mask,
00202                    unsigned int flags,
00203                    int linewidth,
00204                    unsigned long maxblocksize,
00205                    unsigned long *bufsize)
00206 {
00207   
00208   FILE *ifp;
00209   static char *filebuf=NULL;
00210   unsigned long filesize=0;
00211   int filesegs=0;
00212   
00213   char *outbuf=NULL;
00214   unsigned long outsize=0;
00215   char *encryptbuf=NULL;
00216   unsigned long encryptsize=0;
00217   int encryptsegs=0;
00218   char *trailerbuf=NULL;
00219   unsigned long trailersize=0;
00220   int trailersegs=0;
00221   char linebuf[1025];
00222   
00223   char *csdone;  /* stores which charstrings already have been written */
00224   int currstring_no=0;
00225   char *charnameP;
00226   unsigned char cipher;
00227   char rdstring[3];
00228   char ndstring[3];
00229 
00230   int retval=1;
00231 
00232   /* Indices. Could save a few but debugging becomes easier this way */
00233   int i=0;
00234   int j=0;
00235   int k=0;
00236   int l=0;
00237   int m=0;
00238   int n=0;
00239   int o=0;
00240   int p=0;
00241   
00242   
00243   int notdefencoded=0;
00244   int stdenc=0;
00245   int reencode=0;
00246   int colcount=0;
00247   int tr_len=-1;
00248   int encrypt=1;      /* 1=ASCII-hex, 2=Binary, 0=None (for debugging) */
00249   int dindex=0;
00250   int nocharstrings=0;
00251   char encmask[256];  /* Mask after resolving composite characters */
00252   T1_COMP_CHAR_INFO* cci = NULL;
00253   
00254   
00255   /* Otherwise we would get invalid accesses later */
00256   if (T1_CheckForFontID(FontID)!=1) {
00257     T1_errno=T1ERR_INVALID_FONTID;
00258     return(NULL);
00259   } 
00260 
00261 
00262   /* Check parameters */
00263   if ( (mask==NULL) || (bufsize==NULL) || (linewidth < 8) ||
00264        (linewidth > 1024) || (maxblocksize < 4) ) {
00265     T1_errno=T1ERR_INVALID_PARAMETER;
00266     return(NULL);
00267   } 
00268 
00269 
00270   /* First, we check how many characters have to find their way into the
00271      subsetted file. We take possibly existing composite character
00272      definitions by the user into account. */
00273   for ( j=0; j<256; j++) {
00274     if ( mask[j] != 0 ) {
00275       /* check whether addressed character is an internal character of
00276         the font */
00277       if ( cci != NULL )
00278        T1_FreeCompCharData( cci);
00279       
00280       cci = T1_GetCompCharData( FontID, j);
00281       
00282       if ( cci != NULL ) {
00283        nocharstrings += cci->numPieces;
00284       }
00285       else {
00286        ++nocharstrings;
00287       }
00288     }
00289   }
00290   
00291 
00292   /* adjust encrypting type according to flags. Default is ASCII-hex
00293      encryption because the output may be verbatim inserted into a
00294      PostScript-file. */
00295   if (flags & T1_SUBSET_ENCRYPT_BINARY)
00296     encrypt=2;
00297   else if (flags & T1_SUBSET_ENCRYPT_NONE)
00298     encrypt=0;
00299   
00300   /* Open and initialize scanning machinery */
00301   T1io_reset();
00302   if ((ifp = (FILE *)T1Open(T1_GetFontFilePath( FontID), "rb"))==NULL) {
00303     T1_errno=T1ERR_FILE_OPEN_ERR;
00304     return(NULL);
00305   }
00306 
00307   if (encrypt==0)
00308     sprintf( err_warn_msg_buf, "Subsetting Font %d, flags=0x%X, non-encrypted debug output",
00309             FontID, flags);
00310   else if (encrypt==1)
00311     sprintf( err_warn_msg_buf, "Subsetting Font %d, flags=0x%X, ASCII-hex output with linelength %d",
00312             FontID, flags, linewidth);
00313   else if (encrypt==2)
00314     sprintf( err_warn_msg_buf, "Subsetting Font %d, flags=0x%X, Binary output with maximum blocksize %lu",
00315             FontID, flags, maxblocksize);
00316   T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00317               T1LOG_DEBUG);
00318   
00319   /* Get size of file */
00320   filesize=T1GetFileSize( ifp);
00321   sprintf( err_warn_msg_buf, "Source file %s is %lu bytes long",
00322           T1_GetFontFilePath( FontID), filesize);
00323   T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00324               T1LOG_DEBUG);
00325   if ((filebuf=(char *)calloc( filesize, sizeof(char)))==NULL) {
00326     T1_errno=T1ERR_ALLOC_MEM;
00327     return( NULL);
00328   }
00329 
00330   while (retval>0) {
00331     /* get a line from the file. We have to read enough characters to
00332        ensure that "eexec" does not get split between two reads.
00333        Otherwise, decryption would not be started. */
00334     retval=T1Gets(&(filebuf[i]), 1025, ifp);
00335     
00336     i+=retval;
00337     if ( (dindex==0) && (T1GetDecrypt()>0) ) {
00338       dindex=i-retval; /* from this point on we have decrypted bytes */
00339       sprintf( err_warn_msg_buf, "Human-readable header finished (%d data bytes)",
00340               dindex);
00341       T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00342                  T1LOG_DEBUG);
00343     }
00344     
00345     /* Encoding handling */
00346     if (strstr( &(filebuf[i-retval]), "/Encoding")!=NULL) {
00347       if (strstr( &(filebuf[i-retval]), "StandardEncoding")!=NULL) {
00348        stdenc=1;
00349        if ((flags & T1_SUBSET_FORCE_REENCODE)!=0) {
00350          /* we ignore the current line ... */
00351          i-=retval;
00352          /* and put the encoding header into the buffer */
00353          i+=sprintf( &(filebuf[i]),
00354                     "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"
00355                     );
00356          reencode=1;
00357        }
00358        else {
00359          T1_PrintLog( "T1_SubsetFont()", "Leaving StandardEncoding untouched",
00360                      T1LOG_DEBUG);
00361          reencode=0;
00362        }
00363       }
00364       else {
00365        /* The encoding is explicitly defined in the font file. We skip the
00366           whole definition unless reencoding should be skipped. */
00367        stdenc=0;
00368        retval=T1Gets(&(filebuf[i]), 1025, ifp);
00369        i+=retval;
00370        while (retval>0) {
00371          /* get a line and check for end of encoding definition. */
00372          retval=T1Gets(&(filebuf[i]), 1025, ifp);
00373          if ((flags & T1_SUBSET_SKIP_REENCODE)!=0) { /* we store the encoding
00374                                                   defined here */
00375            i+=retval;
00376            reencode=0;
00377          }
00378          else {
00379            reencode=1;
00380          }
00381          if ( (dindex==0) && (T1GetDecrypt()>0) ) {
00382            dindex=i; /* from this point we have decrypted bytes */
00383          }  
00384          if (strstr( &(filebuf[i-retval]), "readonly def")!=NULL) {
00385            break;
00386          }
00387        }
00388        if (reencode==0)
00389          T1_PrintLog( "T1_SubsetFont()", "Preserving FontSpecific Encoding",
00390                      T1LOG_DEBUG);
00391       }
00392       
00393       /* At this point, if required, the actual encoding definition
00394         follows. */
00395       if ( reencode!=0) {
00396        k=0;
00397 
00398        /* Reset resulting encoding mask */ 
00399        for ( j=0; j<256; j++) {
00400          encmask[j] = 0;
00401        }
00402 
00403        /* Resolve composite characters and their components */
00404        for ( j=0; j<256; j++) {
00405          if (mask[j]!=0) {
00406            if ( cci != NULL)
00407              T1_FreeCompCharData( cci);
00408            cci = T1_GetCompCharData( FontID, j);
00409            if ( (cci != NULL) && (cci->numPieces > 1) ) {
00410              /* Tag all components that are required to construct
00411                the composite character j. */
00412              for ( p=0; p<cci->numPieces; p++) {
00413               encmask[cci->pieces[p].piece] = 1;
00414              }
00415            }
00416            /* Tag character j in encoding definition */
00417            encmask[j] = 1;
00418          }
00419        }
00420 
00421        /* Write actually required encoding slots */
00422        for ( j=0; j<256; j++) {
00423          if (encmask[j]!=0) {
00424            charnameP=T1_GetCharName( FontID, j);
00425            i+=sprintf( &(filebuf[i]), "dup %d /%s put\n", j,
00426                      charnameP);
00427            k++;
00428            if (strcmp(charnameP, ".notdef")==0)
00429              notdefencoded=1;
00430          }
00431        }
00432 
00433        /* finish encoding definition */
00434        i+=sprintf( &(filebuf[i]), "readonly def\n");
00435        sprintf( err_warn_msg_buf, "Encoded %d characters",
00436                k);
00437        T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00438                    T1LOG_DEBUG);
00439        k=0;
00440       }
00441       
00442     } /* end of    if (...encoding handling...)    */
00443 
00444     /* Extract the names are used for the charstring definitions.
00445        We will later need them! */
00446     if (strstr( &(filebuf[i-retval]), "/RD")!=NULL) {
00447       sprintf( rdstring, "RD");
00448     }
00449     if (strstr( &(filebuf[i-retval]), "/ND")!=NULL) {
00450       sprintf( ndstring, "ND");
00451     }
00452     if (strstr( &(filebuf[i-retval]), "/-|")!=NULL) {
00453       sprintf( rdstring, "-|");
00454     }
00455     if (strstr( &(filebuf[i-retval]), "/|-")!=NULL) {
00456       sprintf( ndstring, "|-");
00457     }
00458       
00459     if (strstr( &(filebuf[i-retval]), "/CharStrings")!=NULL) {
00460       /* replace dictionary with one of an appropriate size: */
00461       i -=retval;
00462       sprintf( err_warn_msg_buf, "Private dictionary finished (%u data bytes)",
00463               i-dindex);
00464       T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00465                  T1LOG_DEBUG);
00466       /* if .notdef is not in the encoding mask, we have to reserve
00467         room for the additional charstring .notdef. Note that still
00468         nocharstrings is an upper bound estimation, which is reached
00469         in cases where no characters are encoded more than one time. */
00470       if (notdefencoded==0)
00471        nocharstrings++;
00472       
00473       i+=sprintf( &(filebuf[i]), "2 index /CharStrings %d dict dup begin\n",
00474                 nocharstrings);
00475       break;
00476     }
00477   } /* the portion until Charstrings-dict is now read in */
00478   
00479   
00480   /* We now have to write the CharStrings.
00481      Each charstring must be written once, even if the respective 
00482      character appears more than once in the encoding. So we set up
00483      table to remember which charstrings already have been written.
00484 
00485      Note: The indices returned by locateCharString() range from 1 to n, so that
00486      we have to decrement the index when filling the csdone array!
00487   */
00488   if (( csdone=(char *)calloc( pFontBase->pFontArray[FontID].pType1Data->CharStringsP[0].key.len,
00489                             sizeof(char)))==NULL) {
00490     T1_errno=T1ERR_ALLOC_MEM;
00491     free( filebuf);
00492     T1Close( ifp);
00493     return( NULL);
00494   }
00495   
00496   /* The .notdef character is in force! */
00497   if ((currstring_no=locateCharString( FontID, ".notdef"))==0) {
00498     T1_errno=T1ERR_UNSPECIFIED;
00499     free( csdone);
00500     T1Close( ifp);
00501     return( NULL);
00502   }
00503   i+=sprintf( &(filebuf[i]), "/.notdef %d %s ", charstringL, rdstring);
00504   memcpy(&(filebuf[i]), charstringP, charstringL);
00505   i+=charstringL;
00506   i+=sprintf( &(filebuf[i]), " %s\n", ndstring);
00507   csdone[currstring_no-1]=1;
00508   /* Now, step through the specifier matrix and write only the
00509      necessary charstrings. */
00510   for ( j=0; j<256; j++) {
00511     if (mask[j]!=0) {
00512       charnameP=T1_GetCharName( FontID, j);
00513       if ((currstring_no=locateCharString( FontID, charnameP))==0) {
00514        /* This might be a composite character, check and handle this case ... */
00515        if ( cci != NULL )
00516          T1_FreeCompCharData( cci);
00517        
00518        cci = T1_GetCompCharData( FontID, j);
00519        if ( (cci != NULL) && (cci->numPieces > 1) ) {
00520          /* composite character, loop through pieces and look for the components */
00521          for ( p=0; p<cci->numPieces; p++) {
00522            
00523            charnameP=T1_GetCharName( FontID, cci->pieces[p].piece);
00524            if ((currstring_no=locateCharString( FontID, charnameP))==0) {
00525              /* Character component not found. Try next ... */
00526              T1_PrintLog( "T1_SubsetFont()", "Could not locate component CS ""%s"" for index %d",
00527                         T1LOG_WARNING, charnameP, cci->pieces[p].piece);
00528            }
00529            else {
00530              /* Add component to subset and process charstring only if it has not
00531                already been done */
00532              if (csdone[currstring_no-1]==0) {
00533               k=i;
00534               i+=sprintf( &(filebuf[i]), "/%s %d %s ", charnameP, charstringL, rdstring);
00535               memcpy(&(filebuf[i]), charstringP, charstringL);
00536               i+=charstringL;
00537               i+=sprintf( &(filebuf[i]), " %s\n", ndstring);
00538               csdone[currstring_no-1]=1;
00539               T1_PrintLog( "T1_SubsetFont()",
00540                           "Processing of component CS ""%s"" for index %d successful (len=%d bytes, line=%d bytes)",
00541                           T1LOG_DEBUG, charnameP, cci->pieces[p].piece, charstringL, i-k);
00542              }
00543              else {
00544               sprintf( err_warn_msg_buf, "Skipped multiple processing of component CS ""%s"" (index %d)",
00545                       charnameP, cci->pieces[p].piece);
00546               T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00547                           T1LOG_DEBUG);
00548              }
00549            }
00550          }
00551          continue;
00552        }
00553        else {
00554          /* Character not found and no composite. This is mysterious, but causes no harm
00555             because .notdef will be substituted */
00556          sprintf( err_warn_msg_buf, "Could not locate CS ""%s"" for index %d",
00557                  charnameP, j);
00558          T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00559                      T1LOG_WARNING);
00560          continue;
00561        }
00562        
00563       }
00564       /* Process charstring only if it has not already been done */
00565       if (csdone[currstring_no-1]==0) {
00566        k=i;
00567        i+=sprintf( &(filebuf[i]), "/%s %d %s ", charnameP, charstringL, rdstring);
00568        memcpy(&(filebuf[i]), charstringP, charstringL);
00569        i+=charstringL;
00570        i+=sprintf( &(filebuf[i]), " %s\n", ndstring);
00571        csdone[currstring_no-1]=1;
00572        sprintf( err_warn_msg_buf,
00573                "Processing of CS ""%s"" for index %d successful (len=%d bytes, line=%d bytes)",
00574                charnameP, j, charstringL, i-k);
00575        T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00576                    T1LOG_DEBUG);
00577       }
00578       else {
00579        sprintf( err_warn_msg_buf, "Skipped multiple processing of CS ""%s"" (index %d)",
00580                charnameP, j);
00581        T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00582                    T1LOG_DEBUG);
00583       }
00584     }
00585   }
00586 
00587   /* Get rid of temporary data */
00588   if (csdone!=NULL) {
00589     free( csdone);
00590     csdone = NULL;
00591   }
00592   if ( cci != NULL ) {
00593     free( cci);
00594     cci = NULL;
00595   }
00596 
00597   /* All charstrings are written. Some PostScript code follows */
00598   i+=sprintf( &(filebuf[i]),
00599              "end\nend\nreadonly put\nnoaccess put\ndup /FontName get exch definefont pop\nmark currentfile closefile\n");
00600   sprintf( err_warn_msg_buf,
00601           "Charstrings and Font definition finished (%d data bytes, from which %d bytes will be encrypted)",
00602           i, i-dindex);
00603   T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00604               T1LOG_DEBUG);
00605   
00606   /* we compute the size of the encrypted area. */
00607   if (encrypt==1) {
00608     encryptsize=i-dindex;
00609     encryptsize+=4;       /* the four random bytes */
00610     encryptsize*=2;       /* since we use ASCII-hex output */
00611     encryptsize+=(int)ceil((double)encryptsize/linewidth); /* we need a few newline characters
00612                                         to adjust the output format */
00613   }
00614   else if (encrypt==2) { /* binary encryption. The whole data is contiguous
00615                          and only at the end of the data a newline is
00616                          added. */
00617     encryptsize=i-dindex+1;
00618     encryptsize+=4;       /* the four random bytes */
00619   }
00620   else { /*The case of no encryption does not produce
00621           valid fonts, it is for debugging purposes only */
00622     encryptsize=i-dindex+1;
00623   }
00624   
00625   
00626   /* we add the size of the 512 zeros and the cleartomark */
00627   trailersize+=ZEROS;
00628   trailersize+=(int)ceil((double)ZEROS/linewidth);
00629   trailersize+=12;                /* cleartomark */
00630 
00631   /* Search for remaining PostScript code in the last 1024 bytes. This
00632      should suffice for any font. */
00633   tr_len=T1GetTrailer( linebuf, 1025, ifp);
00634   T1Close(ifp);  /* we do not need the file any longer */
00635   
00636   /* And we add the size of the trailer. A trailer only consisting of
00637      a newline is ignored because the newline has already been included
00638      in the cleartomark-string. */
00639   if ( !((tr_len==1) && ((linebuf[0]=='\n') || (linebuf[0]=='\r')) ) ) {
00640     trailersize+=tr_len;
00641   }
00642   
00643   
00644   if ((encryptbuf=(char *)calloc( encryptsize, 1))==NULL) {
00645     T1_errno=T1ERR_ALLOC_MEM;
00646     free( filebuf);
00647     return( NULL);
00648   }
00649   
00650   /* Allocate one byte in orer to be able to use sprintf() (which appends
00651      an ASCII-\0).*/
00652   if ((trailerbuf=(char *)calloc( trailersize+1, 1))==NULL) {
00653     T1_errno=T1ERR_ALLOC_MEM;
00654     free( filebuf);
00655     free( encryptbuf);
00656     return( NULL);
00657   }
00658   
00659   k=0;
00660   colcount=0;
00661 
00662   /* perform eexec-encryption */
00663   eexec_r=55665;
00664   if (encrypt==0) {
00665     for (j=dindex; j<i; j++) {
00666       encryptbuf[k++]=filebuf[j];
00667     }
00668   }
00669   else if ( encrypt==1) {
00670     /* consume four random bytes. We take the numbers '0', '1', '2'
00671        and '3'. The first cipher then is 217-dec (0xD9-hex), i.e., it
00672        is no white space character. The resulting font can thus be
00673        converted to pfb-format without the risk violating the Adobe spec.*/
00674     for (j=0; j<4; j++) { 
00675       cipher=EexecEncrypt( (unsigned char) j);  
00676       encryptbuf[k++]=highHexByte[cipher];
00677       if (++colcount==linewidth) {
00678        colcount=0;
00679        encryptbuf[k++]='\n';
00680       }
00681       encryptbuf[k++]=lowHexByte[cipher];
00682       if (++colcount==linewidth) {
00683        colcount=0;
00684        encryptbuf[k++]='\n';
00685       }
00686     }
00687     for (j=dindex; j<i; j++) {
00688       cipher=EexecEncrypt( (unsigned char) filebuf[j]);
00689       encryptbuf[k++]=highHexByte[cipher];
00690       if (++colcount==linewidth) {
00691        colcount=0;
00692        encryptbuf[k++]='\n';
00693       }
00694       encryptbuf[k++]=lowHexByte[cipher];
00695       if (++colcount==linewidth) {
00696        colcount=0;
00697        encryptbuf[k++]='\n';
00698       }
00699     }
00700     /* If necessary, append newline char */
00701     if (encryptbuf[k-1]!='\n') {
00702       encryptbuf[k++]='\n';
00703     }
00704   } /* if encrypt==1 */
00705   else { /* four random bytes ... */
00706     for (j=0; j<4; j++) { 
00707       encryptbuf[k++]=EexecEncrypt( (unsigned char) j);  
00708     }
00709     for (j=dindex; j<i; j++) { /* and encrypted charstrings */
00710       encryptbuf[k++]=EexecEncrypt( (unsigned char) filebuf[j]);  
00711     }
00712   } /* encrypt == 2 */
00713   /* Encryption finished */
00714   
00715   /* If necessary, append newline char */
00716   if (encryptbuf[k-1]!='\n') {
00717     encryptbuf[k++]='\n';
00718   }
00719 
00720   colcount=0;
00721   /* Append zeroes and cleartomark */
00722   for (j=0; j<ZEROS; j++) {
00723     trailerbuf[l++]='0';
00724     if (++colcount==linewidth) {
00725       colcount=0;
00726       trailerbuf[l++]='\n';
00727     }
00728   }
00729   /* If necessary, append newline char */
00730   if (trailerbuf[l-1]!='\n') {
00731     trailerbuf[l++]='\n';
00732   }
00733   l+=sprintf( &(trailerbuf[l]), "cleartomark\n");
00734   if ( !((tr_len==1) && ((linebuf[0]=='\n') || (linebuf[0]=='\r')) ) ) {
00735     sprintf( err_warn_msg_buf,
00736             "Including additional PostScript trailer (%d bytes)",
00737             tr_len);
00738     T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00739                T1LOG_DEBUG);
00740     l+=sprintf( &(trailerbuf[l]), linebuf); /* contains the PostScript trailer */
00741   }
00742   
00743   /* compute size of output file */
00744   outsize=0;
00745   if (encrypt==2) { /* binary encryption, take care about pfb-blocks */ 
00746     /* each segment requires 6 bytes for the header */
00747     filesegs=(int)(ceil((double)dindex/maxblocksize));
00748     encryptsegs=(int)(ceil((double)k/maxblocksize));
00749     trailersegs=(int)(ceil((double)l/maxblocksize));
00750     /* trainling ASCII-part: */
00751     outsize +=dindex;
00752     /* binary encrypted data */
00753     outsize +=k;
00754     /* leading ASCII-part: */
00755     outsize +=l;
00756     /* segment headers */
00757     outsize +=6*(filesegs+encryptsegs+trailersegs);
00758     outsize +=2;  /* the EOF-marker segment */
00759   }
00760   else { /* ASCII-hex encryption or no encryption: no segmentation */
00761     outsize=dindex+k+l;
00762   }
00763   
00764   if ((outbuf=(char *)calloc( outsize, 1))==NULL) {
00765     T1_errno=T1ERR_ALLOC_MEM;
00766     free( filebuf);
00767     free( encryptbuf);
00768     free( trailerbuf);
00769     return( NULL);
00770   }
00771 
00772 
00773 
00774   /* The full bufsize is given as the unencrypted portion plus size
00775      of encryptbuf (which also inccorporates an unencrypted trailer).
00776      In addition, the segment headers have to be taken into account for
00777      pfb-format. */
00778   i=0;
00779   if (encrypt==2) { /* we have to add segment headers */
00780     T1_PrintLog( "T1_SubsetFont()", "Setting up segmented binary buffer (pfb-format)",
00781                T1LOG_DEBUG);
00782     /* Clear text header */
00783     m=0;
00784     for ( j=0; j<filesegs; j++) {
00785       if (j==filesegs-1)
00786        n=dindex % maxblocksize;
00787       else
00788        n=maxblocksize;
00789       i +=make_pfb_segment_header( &(outbuf[i]), SEGMENT_ASCII, n);
00790       memcpy( &(outbuf[i]), &(filebuf[m]), n);
00791       i +=n;
00792       m +=n;
00793     }
00794     sprintf( err_warn_msg_buf,
00795             "    Readable header (%d bytes: %d data bytes in %d ASCII-segments of maximum size %lu bytes)",
00796             i, dindex, filesegs, maxblocksize);
00797     T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00798                T1LOG_DEBUG);
00799     /* Binary data */
00800     m=0;
00801     o=i;
00802     for ( j=0; j<encryptsegs; j++) {
00803       if (j==encryptsegs-1)
00804        n=k % maxblocksize;
00805       else
00806        n=maxblocksize;
00807       i +=make_pfb_segment_header( &(outbuf[i]), SEGMENT_BINARY, n);
00808       memcpy( &(outbuf[i]), &(encryptbuf[m]), n);
00809       i +=n;
00810       m +=n;
00811     }
00812     sprintf( err_warn_msg_buf,
00813             "    Binary data (%d bytes: %d data bytes in %d binary segments of maximum size %lu bytes)",
00814             i-o, k, encryptsegs, maxblocksize);
00815     T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00816                T1LOG_DEBUG);
00817     /* Readable ASCII-trailer */
00818     m=0;
00819     o=i;
00820     for ( j=0; j<trailersegs; j++) {
00821       if (j==trailersegs-1)
00822        n=l % maxblocksize;
00823       else
00824        n=maxblocksize;
00825       i +=make_pfb_segment_header( &(outbuf[i]), SEGMENT_ASCII, n);
00826       memcpy( &(outbuf[i]), &(trailerbuf[m]), n);
00827       i +=n;
00828       m +=n;
00829     }
00830     sprintf( err_warn_msg_buf,
00831             "    Readable trailer (%d bytes: %d data bytes in %d ASCII-segments of maximum size %lu bytes)",
00832             i-o, l, trailersegs, maxblocksize);
00833     T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00834                T1LOG_DEBUG);
00835     i +=make_pfb_segment_header( &(outbuf[i]), SEGMENT_EOF, 0);
00836     sprintf( err_warn_msg_buf,
00837             "    EOF-segment marker (2 bytes)");
00838     T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00839                T1LOG_DEBUG);
00840     *bufsize=i;
00841   } /* end of pfb-setup */
00842   else { /* we continuously copy the data */
00843     if (encrypt==1)
00844       sprintf( err_warn_msg_buf,
00845               "Dumping output buffer (%d bytes: %d readable ASCII, %d ASCII-hex in lines of width %d, %d readable ASCII)",
00846               dindex+k+l, dindex, k, linewidth, l);
00847     else 
00848       sprintf( err_warn_msg_buf,
00849               "Dumping output buffer (%d bytes: %d readable ASCII, %d non-encrypted binary, %d readable ASCII)",
00850               dindex+k+l, dindex, k, l);
00851     T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00852                T1LOG_DEBUG);
00853     memcpy( outbuf, filebuf, dindex);
00854     memcpy( &(outbuf[dindex]), encryptbuf, k);
00855     memcpy( &(outbuf[dindex+k]), trailerbuf, l);
00856     *bufsize=dindex+k+l;
00857   }
00858   
00859   sprintf( err_warn_msg_buf,
00860           "Output buffer is %ld bytes, original file size is %lu bytes",
00861           *bufsize, filesize);
00862   T1_PrintLog( "T1_SubsetFont()", err_warn_msg_buf,
00863               T1LOG_DEBUG);
00864   
00865   
00866   if (encryptbuf!=NULL)
00867     free(encryptbuf);
00868   if (trailerbuf!=NULL)
00869     free(trailerbuf);
00870   if (filebuf!=NULL)
00871     free( filebuf);
00872 
00873   return( outbuf);
00874   
00875 }
00876 
00877 
00878 
00879 /* This function returns the encrypted charstring of character
00880    charname of font FontID. The length is saved at len */
00881 char *T1_GetCharString( int FontID, char *charname, int *len)
00882 {
00883 
00884   static char *charstring=NULL;
00885   
00886   if (T1_CheckForFontID(FontID)!=1) {
00887     T1_errno=T1ERR_INVALID_FONTID;
00888     return(NULL);
00889   } 
00890   
00891   if ( (charname==NULL) || (len==0) ) {
00892     T1_errno=T1ERR_INVALID_PARAMETER;
00893     return(NULL);
00894   } 
00895 
00896   if ((locateCharString( FontID, charname))==0) {
00897     *len=0;
00898     T1_errno=T1ERR_UNSPECIFIED;
00899     return( NULL);
00900   }
00901   
00902   if (charstring!=NULL) {
00903     free( charstring);
00904     charstring=NULL;
00905   }
00906   if ((charstring=(char *)malloc( charstringL))==NULL) {
00907     *len=0;
00908     T1_errno=T1ERR_ALLOC_MEM;
00909     return( NULL);
00910   }
00911 
00912   memcpy( charstring, charstringP, charstringL);
00913   *len=charstringL;
00914   return( charstring);
00915   
00916 }
00917 
00918 
00919 
00920 /* For those who really need it, this function returns the value
00921    of lenIV from the Private dictionary. It specifies how many
00922    random leading bytes are used in Charstring encryption in the
00923    current font. */
00924 int T1_GetlenIV( int FontID)
00925 {
00926   
00927   if (T1_CheckForFontID(FontID)!=1) {
00928     T1_errno=T1ERR_INVALID_FONTID;
00929     return( -2);
00930   } 
00931   return( pFontBase->pFontArray[FontID].pType1Data->Private[LENIV].value.data.integer);
00932 
00933 }