Back to index

tetex-bin  3.0
t1enc.c
Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002   ----- File:        t1enc.c 
00003   ----- Author:      Rainer Menzner (Rainer.Menzner@web.de)
00004   ----- Date:        2003-01-05
00005   ----- Description: This file is part of the t1-library. It contains
00006                      functions encoding handling at runtime.
00007   ----- Copyright:   t1lib is copyrighted (c) Rainer Menzner, 1996-2003.
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                    independ from X11.
00025                      Thanks to all people who make free software living!
00026 --------------------------------------------------------------------------*/
00027   
00028 #define T1ENC_C
00029 
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #if defined(_MSC_VER)
00035 # include <io.h>
00036 # include <sys/types.h>
00037 # include <sys/stat.h>
00038 #else
00039 # include <unistd.h>
00040 #endif
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <ctype.h>
00044 
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 "t1enc.h"
00059 #include "t1env.h"
00060 #include "t1base.h"
00061 #include "t1finfo.h"
00062 
00063 
00064 static char defaultencodingname[]="Unspecified";
00065 
00066 /* This struct is retunred by the tokenizer. It contains indices
00067    in linebuf for the first and the last character in a token */ 
00068 typedef struct 
00069 {
00070   int first;
00071   int last;
00072 } CNTOKEN;
00073 
00074 
00075 
00076 /* ScanForWord(): Tokenizer for ScanEncodingFile.
00077 
00078    - and return the first and last index in linebuf of the token
00079    
00080    - skips whitespace and comments
00081 
00082    - the vector marks [ and ] are considered token-delimiters
00083      and also treated as independent tokens
00084 
00085    - the literal escape char "/" is also considered as a token
00086      delimiter but is not returned as a token.
00087 
00088    This function leaves linebuf unmodified so that in case of a
00089    failure, TryT1LibEncoding() will receive a clean buffer!  */
00090 static CNTOKEN *ScanForWord( char *lb, int size)
00091 {
00092   static int i=-1;
00093   int j;
00094   int comment;
00095   
00096   static CNTOKEN currtoken={-1,-1};
00097   
00098   /* Reset tokenizer */
00099   if (lb==NULL) {
00100     i=-1;
00101     currtoken.first=-1;
00102     currtoken.last=-1;
00103     return NULL;
00104   }
00105 
00106   comment=0;
00107   j=-1;
00108 
00109   while (++i<size) {
00110 
00111     /* Inside word */
00112     if (j!=-1) {
00113       /* Whitespace, comment, mark or literal ends word */
00114       if ( (lb[i]=='%') ||
00115           (lb[i]=='[') ||
00116           (lb[i]==']') ||
00117           (lb[i]=='/') ||
00118           isspace((int)lb[i]) ) {
00119        currtoken.last=i-1;
00120        if ( (lb[i]=='[') ||
00121             (lb[i]==']') ||
00122             (lb[i]=='/') ) {
00123          i--;
00124        }
00125        return &currtoken;
00126       }
00127       /* End not found, try next char */
00128       continue;
00129     }
00130     
00131     /* first, check for special tokens */
00132     if ( ( (lb[i]=='[') || (lb[i]==']')) ) {
00133       currtoken.first=i;
00134       currtoken.last=i;
00135       return &currtoken;
00136     }
00137 
00138     /* Inside coment */
00139     if (comment) {
00140       if (lb[i]=='\n')
00141        comment=0;
00142       continue;
00143     }
00144     if (lb[i]=='%') {
00145       comment=1;
00146       continue;
00147     }
00148 
00149     /* **Whitespace */
00150     if (isspace((int)lb[i]))
00151       continue;
00152 
00153     /* **Something else => word */
00154     if (j==-1) {
00155       j=i;
00156       currtoken.first=j;
00157       continue;
00158     }
00159   }
00160 
00161   /* We're at the end of the buffer. Do we have a word? */
00162   if (j!=-1) {
00163     currtoken.last=i-1;
00164     return &currtoken;
00165   }
00166 
00167   /* We have nothing */
00168   return NULL;
00169 }
00170 
00171 
00172 /* tokcpy(): Copy a token from linebuf and append \0 */
00173 static char *tokcpy( char *dest, const char *src,
00174                   int first, int last) 
00175 {
00176   /* we do not do any range or error checking in this function */
00177   memcpy( dest, &(src[first]), last-first+1);
00178   dest[last-first+1]='\0';
00179   return dest;
00180 }
00181 
00182 
00183 /* TryDVIPSEncoding(): Try to read an encoding file conforming to the
00184    dvips specification. The file's contents is expected in a buffer
00185    "linebuf" of size "filesize". Function returns the actual size of the
00186    charnames memory or -1. */
00187 static int TryDVIPSEncoding( char *linebuf, int filesize, char *charnames) 
00188 {
00189 
00190   char token[256];
00191   char *encname;
00192   int charname_count=0;
00193   int k=0;
00194   CNTOKEN *currtokenP;
00195   
00196   
00197   /* Initialize tokenizer */
00198   currtokenP=ScanForWord( NULL, filesize);
00199 
00200   
00201   currtokenP=ScanForWord(linebuf,filesize);
00202   if ( (currtokenP!=NULL) &&
00203        (linebuf[currtokenP->first]=='/')) { 
00204     /* / indicates start of postscript string literal, so this
00205        could be a postscript .enc file */
00206     if ((encname=(char *)malloc( (currtokenP->last - currtokenP->first + 1 + 1) *
00207                              sizeof( char)))==NULL) {
00208       T1_errno=T1ERR_ALLOC_MEM;
00209       return -1;
00210     }
00211     else {
00212       /* store encoding name */
00213       if (currtokenP->first==currtokenP->last) {
00214        /* PostScript encoding requires an identifier
00215           so this does not seem to be a valid encoding file */
00216        free( encname);
00217        return( -1);
00218       }
00219       tokcpy( encname, linebuf, currtokenP->first+1, currtokenP->last);
00220       
00221     }
00222     
00223     
00224     /* Next, the PostScript "mark" character is expected */
00225     if ( ((currtokenP=ScanForWord(linebuf,filesize))!=NULL) &&
00226         (currtokenP->first==currtokenP->last) &&
00227         (linebuf[currtokenP->first]!='[') ) {
00228       /* Since we got up to here, there is a certain probability that
00229         we have a PostScript encoding definition, but with invalid
00230         syntax. So put log message. */
00231       sprintf( err_warn_msg_buf,
00232               "Expected encoding definition after %s, but did not find \"[\"-character",
00233               encname);
00234       T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00235       if (encname!=NULL)
00236        free( encname);
00237       return( -1);
00238     }
00239 
00240     /* now, try to read 256 literal character names. We do not check
00241        for charname count because this would bypass error checking. */
00242     while((currtokenP=ScanForWord(linebuf,filesize))!=NULL) {
00243 
00244       /* End of vector operator? */
00245       if ( (currtokenP->first==currtokenP->last) && /* one character? */
00246           (linebuf[currtokenP->first]==']')) {
00247        break;
00248       }
00249       /* We drop the escape character if it is present. However,
00250         non-literal name specifications are not allowed in
00251         encoding vectors. */
00252       if (linebuf[currtokenP->first]!='/') {
00253        sprintf( err_warn_msg_buf,
00254                "Found non-literal name (c=%c (first=%d, last=%d)) at slot %d while scanning encoding vector %s.",
00255                linebuf[currtokenP->first],
00256                currtokenP->first, currtokenP->last,
00257                charname_count, encname);
00258        T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00259        if (encname!=NULL)
00260          free( encname);
00261        return( -1);
00262       }
00263       else {
00264        /* OK, first char in token is "/". Does there follow a name? */
00265        if ( currtokenP->first==currtokenP->last) {
00266          sprintf( err_warn_msg_buf,
00267                  "Empty literal name at slot %d while scanning encoding vector %s.",
00268                  charname_count, encname);
00269          T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00270          if (encname!=NULL)
00271            free( encname);
00272          return( -1);
00273        }
00274       }
00275       
00276       /* We seem to have a valid name -> copy name to *charnames-array */
00277       tokcpy( &(charnames[k]), linebuf,
00278              currtokenP->first+1, currtokenP->last);
00279       k+=currtokenP->last-currtokenP->first+1; /* note: we have omitted "/"! */
00280       /* Increment character counter */
00281       charname_count++;
00282       /* set index to start of next word/line */
00283     } /* end of loop scanning character names */
00284     
00285     if (currtokenP==NULL) {
00286       /* In this case loop has been stopped because buffer end has been
00287         reached. Since we did not alreay read the ]-character, this is
00288         an error condition. */
00289       sprintf( err_warn_msg_buf,
00290               "Premature end of encoding definition encountered." );
00291       T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00292       free(encname);
00293       return( -1);
00294     }
00295     /* Since the above loop has not been finished due to a NULL-ptr,
00296        the token ] must have been encountered. Thus, read ahead and look
00297        for def: */
00298     if ((currtokenP=ScanForWord(linebuf,filesize))==NULL) {
00299       sprintf( err_warn_msg_buf,
00300               "Premature end of encoding definition encountered.");
00301       T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00302       free(encname);
00303       return( -1);
00304     }
00305     
00306     if (strcmp(tokcpy( &(charnames[k]), linebuf,
00307                      currtokenP->first, currtokenP->last), "def")!=0) {
00308       /* we store the current token in charnames only temporarily, so we
00309         do not increment k! */   
00310       sprintf( err_warn_msg_buf,
00311               "Closing token \"def\" expected but found \"%s\".",
00312               &(charnames[k]));
00313       T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00314       free(encname);
00315       return( -1);
00316     }
00317     /* Encoding definition is complete. we do not allow any further tokens
00318        except comments. */
00319     if ((currtokenP=ScanForWord(linebuf,filesize))!=NULL) {
00320       tokcpy( token, linebuf, currtokenP->first, currtokenP->last);
00321       sprintf( err_warn_msg_buf,
00322               "Token \"%s\" after closing \"def\" in successfully scanned encoding file makes encoding definition file invalid", token);
00323       T1_PrintLog( "TryDVIPSEncoding()", err_warn_msg_buf, T1LOG_WARNING);
00324       free(encname);
00325       return( -1);
00326     }
00327 
00328     /* we allow less than 256 character names. The missing ones are filled
00329        now with .notdef */
00330     for ( ; charname_count<256; charname_count++) {
00331       tokcpy( &(charnames[k]), ".notdef", 0, 6);
00332       k+=8;
00333      }
00334     
00335     /* Append the string for the encoding's name */
00336     strcpy( &(charnames[k]), encname);
00337     k +=strlen(encname)+1;
00338     
00339     free(encname);
00340     
00341     return( k);
00342       
00343   } /* file does not start with / -> no dvips-encoding file */
00344 
00345   return( -1);
00346   
00347 }
00348 
00349 
00350 
00351 /* TryT1LibEncoding(): Try to read an encoding file conforming to the
00352    t1lib specification. The file's contents is expected in a buffer
00353    "linebuf" of size "filesize". Function returns the actual size of the
00354    charnames memory or -1. */
00355 static int TryT1LibEncoding( char *linebuf, int filesize, char *charnames) 
00356 {
00357   int i=0, j=0, k=0, l=0;
00358   
00359   char save_char;
00360   int charname_count=0;
00361 
00362   while(i<filesize){
00363     j=i;     /* Save index of beginning of line */
00364     while ( (i<filesize) &&
00365            (isspace((int)linebuf[i])==0) )
00366       i++;
00367     if (i==filesize)
00368       continue; /* this will leave this loop */
00369     save_char=linebuf[i];
00370     linebuf[i]=0;  /* replace ' ' by ASCII-0 */
00371     if (strncmp( "Encoding=", &linebuf[j], strlen("Encoding="))==0) {
00372       /* We save the current file position to read the encoding name
00373         later */
00374       l=j+strlen("Encoding=");
00375       /* set index to start of next line */
00376       if (save_char=='\n')
00377        i++;   
00378       else {
00379        while ( (i<filesize) &&
00380               (linebuf[i]!='\n') )
00381          i++;
00382        if (i==filesize)
00383          continue; /* this will leave this loop */
00384        i++;
00385       }
00386       /* keyword found => now, 256 lines should follow, each
00387         specifying a character name and optionally some comment
00388         to enhance readability: */
00389       break;
00390     }
00391     i++;
00392   }
00393 
00394   
00395   while((i<filesize) && (charname_count<256)){
00396     j=i;     /* Save index of beginning of line */
00397     while ( (i<filesize) &&
00398            (isspace((int)linebuf[i])==0))
00399       i++;
00400     if (i==filesize)
00401       continue; /* this will leave this loop */
00402     save_char=linebuf[i];
00403     linebuf[i]=0;  /* replace whitespace by ASCII-0 */
00404     /* Copy Name to *char_names-array */
00405     while (linebuf[j])
00406       charnames[k++]=linebuf[j++];
00407     /* Append ASCII-0 */
00408     charnames[k++]=linebuf[j++];
00409     /* set index to start of next line */
00410     if (save_char=='\n')
00411       i++;   
00412     else {
00413       while ( (i<filesize) &&
00414              (linebuf[i]!='\n'))
00415        i++;
00416       if (i==filesize)
00417        continue; /* this will leave this loop */
00418       i++;
00419     }
00420     /* Increment character counter */
00421     charname_count++;
00422   }
00423 
00424   /* Check if exactly 256 characters have been defined, if not,
00425      return NULL: */
00426   if (charname_count!=256){
00427     return( -1);
00428   }
00429 
00430   /* Append the string for the encoding's name */
00431   i=l;
00432   while (isspace((int)linebuf[i])==0 && linebuf[i]!='\0'){
00433     charnames[k++]=linebuf[i++];
00434   }
00435   
00436   if (i==l){
00437     strcpy(&(charnames[k]), defaultencodingname);
00438     k +=strlen(defaultencodingname+1);
00439     charnames[k++]='\0';
00440   }
00441   else{
00442     charnames[k++]='\0';
00443   }
00444 
00445   return( k);
00446   
00447 }
00448 
00449 
00450 
00451 /* ScanEncodingFile(): Read an encoding file of an appropriate format
00452    and prepare the read data for usage with the type1 rasterizer, i.e.
00453    generate an array char *enc[257]. Return the pointer to the data area
00454    or NULL in case of an error.
00455    */
00456 static char **ScanEncodingFile( char *FileName) 
00457 {
00458   
00459   char *linebuf;
00460   char **encoding;        /* charnames array */
00461   char *charnames=NULL;   /* charnames memory */
00462   
00463   int cnsize;             /* size of charnames memory, this will be
00464                           set from the Try...() function */
00465   
00466   FILE *enc_fp; 
00467   int filesize;
00468   int i=0, j=0;
00469   
00470   if ((enc_fp=fopen( FileName,"rb"))==NULL){
00471     T1_errno=T1ERR_FILE_OPEN_ERR;
00472     return(NULL);  /* file could not be opened 
00473                     => no encoding read */
00474   }
00475   
00476   
00477   /* enc_fp points now to a (hopefully) valid encoding file */
00478   /* Get the file size */
00479   fseek( enc_fp, 0, SEEK_END);
00480   filesize=ftell(enc_fp);
00481   /* Reset fileposition to start */
00482   fseek( enc_fp, 0, SEEK_SET);
00483   
00484   if ((linebuf=(char *)calloc( filesize,
00485                             sizeof(char)))==NULL){
00486     T1_errno=T1ERR_ALLOC_MEM;
00487     return(NULL);
00488   }
00489   
00490   /* Allocate space for character names, assume the worst case and realloc
00491      later. The DVIPS-parser requires one more char in order to work properly */
00492   if ((charnames=(char *)calloc( filesize + strlen(defaultencodingname+1),
00493                              sizeof(char)))==NULL){
00494     free( linebuf);
00495     T1_errno=T1ERR_ALLOC_MEM;
00496     return(NULL);
00497   }
00498   
00499   fread((char *)linebuf, sizeof(char), filesize, enc_fp);
00500   fclose(enc_fp);
00501 
00502 
00503   /* file is read. Operate now on the buffer. */
00504 
00505   
00506   /* try dvips encoding file */
00507   cnsize=TryDVIPSEncoding( linebuf, filesize, charnames);
00508   if ( cnsize>-1) {
00509     /* a debug message to log file */
00510     sprintf( err_warn_msg_buf,
00511             "Scanned file %s (%d bytes) as dvips-encoding file.",
00512             FileName, filesize);
00513     T1_PrintLog( "ScanEncodingFile()", err_warn_msg_buf, T1LOG_DEBUG);
00514   }
00515   else {
00516     /* try t1lib encoding file */
00517     cnsize=TryT1LibEncoding( linebuf, filesize, charnames);
00518     if ( cnsize>-1) {
00519       /* write a debug message to log file */
00520       sprintf( err_warn_msg_buf,
00521               "Scanned file %s (%d bytes) as t1lib-encoding file.",
00522               FileName, filesize);
00523       T1_PrintLog( "ScanEncodingFile()", err_warn_msg_buf, T1LOG_DEBUG);
00524     }
00525     else {
00526       /* write a warning message because loading encoding
00527         entirely failed */ 
00528       sprintf( err_warn_msg_buf,
00529               "Scanning file %s (%d bytes) as encoding file failed.",
00530               FileName, filesize);
00531       T1_PrintLog( "ScanEncodingFile()", err_warn_msg_buf, T1LOG_WARNING);
00532     }
00533   }
00534   
00535   if ( cnsize<0) {
00536     T1_errno=T1ERR_SCAN_ENCODING;
00537     if ( charnames!=NULL) {
00538       free(charnames); 
00539     }
00540     free(linebuf);
00541     return( NULL);
00542   }
00543   
00544   
00545   /* cnsize contains the size of the charnames' memory, so let's
00546      now realloc charnames */
00547   charnames=(char *)realloc( charnames, cnsize*sizeof(char));
00548   /* Now initialize the array with the start-addresses of the character
00549      name strings */
00550   /* We alloc 257 to save the encoding's name at the 257th entry */
00551   if ((encoding=(char **)malloc(257*sizeof(char *)))==NULL) {
00552     if ( charnames!=NULL) {
00553       free(charnames);
00554     }
00555     free(linebuf);
00556     T1_errno=T1ERR_ALLOC_MEM;
00557     return(NULL);
00558   }
00559   
00560   while (i<257) {
00561     encoding[i]=&charnames[j];
00562     while (charnames[j])
00563       j++;
00564     j++;
00565     i++;
00566   }
00567   
00568   free( linebuf);
00569   return(encoding);
00570 
00571 }
00572 
00573 
00574 
00575 /* T1_LoadEncoding(): Load an encoding file to have a new encoding
00576    available. If successful, the pointer to the encoding array is
00577    returned. In case of an error, the return value is NULL.
00578    */
00579 char **T1_LoadEncoding( char *FileName)
00580 {
00581   char **Encoding;
00582   char *EncFileName;
00583   
00584   if( FileName==NULL){
00585     T1_errno=T1ERR_INVALID_PARAMETER;
00586     return(NULL);
00587   }
00588   
00589   if ((EncFileName=intT1_Env_GetCompletePath( FileName, T1_ENC_ptr))==NULL){
00590     T1_errno=T1ERR_FILE_OPEN_ERR;
00591     return(NULL);
00592   }
00593   Encoding=ScanEncodingFile(EncFileName);
00594   free(EncFileName);
00595   
00596   return(Encoding);
00597 }
00598 
00599   
00600 
00601 /* T1_DeleteEncoding() free a previously loaded encoding */
00602 int T1_DeleteEncoding( char **encoding)
00603 {
00604   if (encoding){
00605     /* First free character names memory */
00606     free( encoding[0]);
00607     /* then, free pointer array */
00608     free( encoding);
00609   }
00610   return(0);
00611   
00612 }
00613 
00614 
00615 
00616 /* T1_ReencodeFont(): Assign a new encoding to an existent font. This is
00617    only allowed if no size dependent data exists for the font in question.
00618    Moreover, the font must be loaded already since must get the position
00619    of the space-character. Function returns 0 if successful, and -1 otherwise.
00620    */
00621 int T1_ReencodeFont( int FontID, char **Encoding)
00622 {
00623   int i, j, k, l, m;
00624   char *charname;
00625   PairKernData *pkd;
00626   METRICS_ENTRY *kern_tbl;
00627   int char1, char2;
00628   
00629   
00630   /* First, check for valid font ID residing in memory: */
00631   if (T1_CheckForFontID(FontID)!=1){
00632     T1_errno=T1ERR_INVALID_FONTID;
00633     return(-1);
00634   }
00635   
00636   /* Second, check whether size-dependent data exists: */
00637   if (pFontBase->pFontArray[FontID].pFontSizeDeps != NULL){
00638     T1_errno=T1ERR_OP_NOT_PERMITTED;
00639     return(-1);
00640   }
00641   
00642   pFontBase->pFontArray[FontID].pFontEnc=Encoding;
00643 
00644 
00645   /* We have to update the space_position-entry in the FONTPRIVATE. 
00646      If space is not found (not encoded), set it to -1: */
00647   pFontBase->pFontArray[FontID].space_position=-1;
00648   i=0;
00649   if (Encoding){ /* external encoding */
00650     while (i<256){
00651       if (strcmp( (char *)pFontBase->pFontArray[FontID].pFontEnc[i],
00652                 "space")==0){
00653        /* space found at position i: */
00654        pFontBase->pFontArray[FontID].space_position=i;
00655        break;
00656       }
00657       i++;
00658     }
00659   }
00660   else{ /* reencoding to internal encoding */
00661     while (i<256){
00662       if (strcmp( (char *)pFontBase->pFontArray[FontID].pType1Data->fontInfoP[ENCODING].value.data.arrayP[i].data.arrayP,
00663                 "space")==0){
00664        /* space found at position i: */
00665        pFontBase->pFontArray[FontID].space_position=i;
00666        break;
00667       }
00668       i++;
00669     }
00670   }
00671 
00672   /* Now update afm index mapping: */
00673   if (pFontBase->pFontArray[FontID].pAFMData != NULL){
00674     for (i=0; i<256; i++) {
00675       charname=T1_GetCharName( FontID, i);
00676       /* in a first loop check for ordinary characters */
00677       for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfChars; j++) {
00678        if (strcmp( charname,
00679                   pFontBase->pFontArray[FontID].pAFMData->cmi[j].name)==0) {
00680          pFontBase->pFontArray[FontID].pEncMap[i]=j+1; /* index 0 is reserved! */
00681          continue;
00682        }
00683       }
00684       /* if nothing has been found, check for composite characters */ 
00685       for ( j=0; j<pFontBase->pFontArray[FontID].pAFMData->numOfComps; j++) {
00686        if (strcmp( charname,
00687                   pFontBase->pFontArray[FontID].pAFMData->ccd[j].ccName)==0) {
00688          pFontBase->pFontArray[FontID].pEncMap[i]=-(j+1); /* index 0 is reserved! */
00689          /* Note: Metrics of composite characters already exist so that there is
00690             no need to recalculate them! */
00691          continue;
00692        }
00693       }
00694     }
00695     /* Update kerning table */
00696     pFontBase->pFontArray[FontID].KernMapSize=0;
00697     k=pFontBase->pFontArray[FontID].pAFMData->numOfPairs;
00698     if (k>0){ /* i.e., there are any pairs */
00699       /* OK, it does not suffice to alloc numOfPairs METRICS_ENTRYs, because
00700         a given character might be encoded at several locations and kerning
00701         should still work. As a worst case estimation, we allocate 256^2
00702         and realloc later. */ 
00703       if ((pFontBase->pFontArray[FontID].pKernMap=
00704           (METRICS_ENTRY *)malloc( (256*256) *sizeof( METRICS_ENTRY)))==NULL){
00705        sprintf( err_warn_msg_buf, "Error allocating memory for metrics map (FontID=%d)",
00706                FontID);
00707        T1_PrintLog( "T1_LoadFont()", err_warn_msg_buf,
00708                    T1LOG_WARNING);
00709        T1_errno=T1ERR_ALLOC_MEM;
00710        return(-1);
00711       }
00712       kern_tbl=pFontBase->pFontArray[FontID].pKernMap;
00713       pkd=pFontBase->pFontArray[FontID].pAFMData->pkd;
00714       j=0;
00715       for ( i=0; i<k; i++) {
00716        /* We do not check T1_GetEncodingIndices() against the return value
00717           NULL because we just loading the font in question: */
00718        l=0;
00719        while ((char1=(T1_GetEncodingIndices( FontID, pkd[i].name1))[l++])!=-1) {
00720          /* pair could be relevant in current encoding */
00721          m=0;
00722          while ((char2=(T1_GetEncodingIndices( FontID, pkd[i].name2))[m++])!=-1) {
00723            /* Since we get here we have a relevant pair -->
00724               Put char1 in higher byte and char2 in LSB: */
00725            kern_tbl[j].chars=(char1 << 8) | char2;
00726            /* We only make use of horizontal kerning */
00727            kern_tbl[j].hkern=pkd[i].xamt;
00728            j++;
00729          } /* while (char2) */
00730        } /* while (char1) */
00731       } /* for */
00732       /* We are done, realloc memory: */
00733       kern_tbl=(METRICS_ENTRY*) realloc( kern_tbl, j*sizeof(METRICS_ENTRY));
00734       /* We now sort the kerning array with respect to char indices */
00735       qsort( kern_tbl, (size_t) j, sizeof(METRICS_ENTRY),
00736             &cmp_METRICS_ENTRY );
00737       /* Finally write back pointer for the case that realloc changed the
00738         pointer */
00739       pFontBase->pFontArray[FontID].pKernMap=kern_tbl;
00740       pFontBase->pFontArray[FontID].KernMapSize=j;
00741     }
00742     else {
00743       pFontBase->pFontArray[FontID].pKernMap=NULL;
00744     }
00745   }
00746   return(0);
00747 }
00748 
00749 
00750 
00751 /* T1_SetDefaultEncoding(): Set the default encoding vector that's
00752    used when fonts are loaded.
00753    */
00754 int T1_SetDefaultEncoding( char **encoding)
00755 {
00756   
00757   if (T1_CheckForInit()){
00758     T1_errno=T1ERR_OP_NOT_PERMITTED;
00759     return(-1);
00760   }
00761   
00762   pFontBase->default_enc=encoding;
00763   return(0);
00764 }
00765 
00766 
00767 /* T1_GetEncodingScheme(): Get the name associated with the current
00768    encoding vector of font FontID */
00769 char *T1_GetEncodingScheme( int FontID)
00770 {
00771   
00772   static char enc_scheme[256];
00773   
00774   /* First, check for valid font ID residing in memory: */
00775   if (T1_CheckForFontID(FontID)!=1){
00776     T1_errno=T1ERR_INVALID_FONTID;
00777     return(NULL);
00778   }
00779 
00780   if (pFontBase->pFontArray[FontID].pFontEnc==NULL){
00781     if (pFontBase->pFontArray[FontID].info_flags & USES_STANDARD_ENCODING){
00782       strcpy( enc_scheme, "StandardEncoding");
00783     }
00784     else {
00785       strcpy( enc_scheme, "FontSpecific");
00786     }
00787   }
00788   else
00789     strcpy( enc_scheme, pFontBase->pFontArray[FontID].pFontEnc[256]);
00790   
00791   return(enc_scheme);
00792   
00793 }
00794 
00795 
00796 /* A function for comparing METRICS_ENTRY structs */
00797 static int cmp_METRICS_ENTRY( const void *entry1, const void *entry2)
00798 {
00799   if (((METRICS_ENTRY *)entry1)->chars <
00800       ((METRICS_ENTRY *)entry2)->chars)
00801     return(-1);
00802   if (((METRICS_ENTRY *)entry1)->chars >
00803       ((METRICS_ENTRY *)entry2)->chars)
00804     return(1);
00805   return(0); /* This should not happen */
00806 }
00807