Upload tizen 2.0 beta source
[framework/graphics/freetype.git] / src / bdf / bdflib.c
index 21b8d9d..b7b6857 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2000 Computing Research Labs, New Mexico State University
- * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010
+ * Copyright 2001-2012
  *   Francesco Zappa Nardelli
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
                         sizeof ( _bdf_properties[0] );
 
 
+  /* Auto correction messages. */
+#define ACMSG1   "FONT_ASCENT property missing.  " \
+                 "Added `FONT_ASCENT %hd'.\n"
+#define ACMSG2   "FONT_DESCENT property missing.  " \
+                 "Added `FONT_DESCENT %hd'.\n"
+#define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
+#define ACMSG4   "Font left bearing != actual left bearing.  " \
+                 "Old: %hd New: %hd.\n"
+#define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
+#define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
+#define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
+#define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
+#define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
+#define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
+#define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
+#define ACMSG12  "Duplicate encoding %ld (%s) changed to unencoded.\n"
+#define ACMSG13  "Glyph %ld extra rows removed.\n"
+#define ACMSG14  "Glyph %ld extra columns removed.\n"
+#define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
+#define ACMSG16  "Glyph %ld missing columns padded with zero bits.\n"
+
+  /* Error messages. */
+#define ERRMSG1  "[line %ld] Missing `%s' line.\n"
+#define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
+#define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
+#define ERRMSG4  "[line %ld] BBX too big.\n"
+#define ERRMSG5  "[line %ld] `%s' value too big.\n"
+#define ERRMSG6  "[line %ld] Input line too long.\n"
+#define ERRMSG7  "[line %ld] Font name too long.\n"
+#define ERRMSG8  "[line %ld] Invalid `%s' value.\n"
+#define ERRMSG9  "[line %ld] Invalid keyword.\n"
+
+  /* Debug messages. */
+#define DBGMSG1  "  [%6ld] %s" /* no \n */
+#define DBGMSG2  " (0x%lX)\n"
+
+
   /*************************************************************************/
   /*                                                                       */
   /* Hash table utilities for the properties.                              */
     bdf_font_t*     font;
     bdf_options_t*  opts;
 
-    unsigned long   have[2048];
+    unsigned long   have[34816]; /* must be in sync with `nmod' and `umod' */
+                                 /* arrays from `bdf_font_t' structure     */
     _bdf_list_t     list;
 
     FT_Memory       memory;
     if ( num_items > list->size )
     {
       unsigned long  oldsize = list->size; /* same as _bdf_list_t.size */
-      unsigned long  newsize = oldsize + ( oldsize >> 1 ) + 4;
+      unsigned long  newsize = oldsize + ( oldsize >> 1 ) + 5;
       unsigned long  bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
       FT_Memory      memory  = list->memory;
 
   }
 
 
+  /* The code below ensures that we have at least 4 + 1 `field' */
+  /* elements in `list' (which are possibly NULL) so that we    */
+  /* don't have to check the number of fields in most cases.    */
+
   static FT_Error
   _bdf_list_split( _bdf_list_t*   list,
                    char*          separators,
 
     /* Initialize the list. */
     list->used = 0;
+    if ( list->size )
+    {
+      list->field[0] = (char*)empty;
+      list->field[1] = (char*)empty;
+      list->field[2] = (char*)empty;
+      list->field[3] = (char*)empty;
+    }
 
     /* If the line is empty, then simply return. */
     if ( linelen == 0 || line[0] == 0 )
 
           if ( buf_size >= 65536UL )  /* limit ourselves to 64KByte */
           {
+            FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
             error = BDF_Err_Invalid_Argument;
             goto Exit;
           }
     FT_Error         error = BDF_Err_Ok;
 
 
-    /* First check to see if the property has      */
+    /* First check whether the property has        */
     /* already been added or not.  If it has, then */
     /* simply ignore it.                           */
     if ( hash_lookup( name, &(font->proptbl) ) )
 #define _BDF_GLYPH_HEIGHT_CHECK  0x80000000UL
 
 
-  /* Auto correction messages. */
-#define ACMSG1   "FONT_ASCENT property missing.  " \
-                 "Added \"FONT_ASCENT %hd\".\n"
-#define ACMSG2   "FONT_DESCENT property missing.  " \
-                 "Added \"FONT_DESCENT %hd\".\n"
-#define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
-#define ACMSG4   "Font left bearing != actual left bearing.  " \
-                 "Old: %hd New: %hd.\n"
-#define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
-#define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
-#define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
-#define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
-#define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
-#define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
-#define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
-#define ACMSG12  "Duplicate encoding %ld (%s) changed to unencoded.\n"
-#define ACMSG13  "Glyph %ld extra rows removed.\n"
-#define ACMSG14  "Glyph %ld extra columns removed.\n"
-#define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
-
-  /* Error messages. */
-#define ERRMSG1  "[line %ld] Missing \"%s\" line.\n"
-#define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
-#define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
-#define ERRMSG4  "[line %ld] BBX too big.\n"
-
-
   static FT_Error
   _bdf_add_comment( bdf_font_t*    font,
                     char*          comment,
   /* default specified in the options.                                 */
   static FT_Error
   _bdf_set_default_spacing( bdf_font_t*     font,
-                            bdf_options_t*  opts )
+                            bdf_options_t*  opts,
+                            unsigned long   lineno )
   {
     size_t       len;
     char         name[256];
     /* Limit ourselves to 256 characters in the font name. */
     if ( len >= 256 )
     {
+      FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
       error = BDF_Err_Invalid_Argument;
       goto Exit;
     }
     ep = line + linelen;
 
     /* Trim the leading whitespace if it exists. */
-    *sp++ = 0;
+    if ( *sp )
+      *sp++ = 0;
     while ( *sp                           &&
             ( *sp == ' ' || *sp == '\t' ) )
       sp++;
 
 
   static FT_Error
-  _bdf_add_property( bdf_font_t*  font,
-                     char*        name,
-                     char*        value )
+  _bdf_add_property( bdf_font_t*    font,
+                     char*          name,
+                     char*          value,
+                     unsigned long  lineno )
   {
     size_t          propid;
     hashnode        hn;
     FT_Error        error = BDF_Err_Ok;
 
 
-    /* First, check to see if the property already exists in the font. */
+    /* First, check whether the property already exists in the font. */
     if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
     {
       /* The property already exists in the font, so simply replace */
     {
       if ( !fp->value.atom )
       {
+        FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
         error = BDF_Err_Invalid_File_Format;
         goto Exit;
       }
 
       /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
       /* number of code points available in Unicode).                 */
-      if ( p->cnt >= 1114112UL )
+      if ( p->cnt >= 0x110000UL )
       {
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
         error = BDF_Err_Invalid_Argument;
         goto Exit;
       }
       goto Exit;
     }
 
-    /* Check to see whether a glyph is being scanned but should be */
-    /* ignored because it is an unencoded glyph.                   */
+    /* Check whether a glyph is being scanned but should be */
+    /* ignored because it is an unencoded glyph.            */
     if ( ( p->flags & _BDF_GLYPH )     &&
          p->glyph_enc            == -1 &&
          p->opts->keep_unencoded == 0  )
 
       if ( !s )
       {
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
         error = BDF_Err_Invalid_File_Format;
         goto Exit;
       }
 
       p->flags |= _BDF_GLYPH;
 
+      FT_TRACE4(( DBGMSG1, lineno, s ));
+
       goto Exit;
     }
 
 
       p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
 
-      /* Check that the encoding is in the range [0,65536] because        */
-      /* otherwise p->have (a bitmap with static size) overflows.         */
-      if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
+      /* Normalize negative encoding values.  The specification only */
+      /* allows -1, but we can be more generous here.                */
+      if ( p->glyph_enc < -1 )
+        p->glyph_enc = -1;
+
+      /* Check for alternative encoding format. */
+      if ( p->glyph_enc == -1 && p->list.used > 2 )
+        p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
+
+      FT_TRACE4(( DBGMSG2, p->glyph_enc ));
+
+      /* Check that the encoding is in the Unicode range because  */
+      /* otherwise p->have (a bitmap with static size) overflows. */
+      if ( p->glyph_enc > 0                               &&
+           (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
       {
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
         error = BDF_Err_Invalid_File_Format;
         goto Exit;
       }
 
-      /* Check to see whether this encoding has already been encountered. */
-      /* If it has then change it to unencoded so it gets added if        */
-      /* indicated.                                                       */
+      /* Check whether this encoding has already been encountered. */
+      /* If it has then change it to unencoded so it gets added if */
+      /* indicated.                                                */
       if ( p->glyph_enc >= 0 )
       {
         if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
       }
       else
       {
-        /* Unencoded glyph.  Check to see whether it should */
-        /* be added or not.                                 */
+        /* Unencoded glyph.  Check whether it should */
+        /* be added or not.                          */
         if ( p->opts->keep_unencoded != 0 )
         {
           /* Allocate the next unencoded glyph. */
     else
       glyph = font->glyphs + ( font->glyphs_used - 1 );
 
-    /* Check to see whether a bitmap is being constructed. */
+    /* Check whether a bitmap is being constructed. */
     if ( p->flags & _BDF_BITMAP )
     {
       /* If there are more rows than are specified in the glyph metrics, */
       for ( i = 0; i < nibbles; i++ )
       {
         c = line[i];
+        if ( !isdigok( hdigits, c ) )
+          break;
         *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
         if ( i + 1 < nibbles && ( i & 1 ) )
           *++bp = 0;
       }
 
+      /* If any line has not enough columns,            */
+      /* indicate they have been padded with zero bits. */
+      if ( i < nibbles                            &&
+           !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
+      {
+        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
+        p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
+        font->modified  = 1;
+      }
+
       /* Remove possible garbage at the right. */
       mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
       if ( glyph->bbx.width )
         *bp &= nibble_mask[mask_index];
 
       /* If any line has extra columns, indicate they have been removed. */
-      if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
-           !( p->flags & _BDF_GLYPH_WIDTH_CHECK )                   )
+      if ( i == nibbles                           &&
+           isdigok( hdigits, line[nibbles] )      &&
+           !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
       {
         FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
         p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
     if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
     {
       if ( !( p->flags & _BDF_ENCODING ) )
-      {
-        /* Missing ENCODING field. */
-        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
-        error = BDF_Err_Missing_Encoding_Field;
-        goto Exit;
-      }
+        goto Missing_Encoding;
 
       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
       if ( error )
     /* Expect the DWIDTH (scalable width) field next. */
     if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
     {
+      if ( !( p->flags & _BDF_ENCODING ) )
+        goto Missing_Encoding;
+
       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
       if ( error )
         goto Exit;
     /* Expect the BBX field next. */
     if ( ft_memcmp( line, "BBX", 3 ) == 0 )
     {
+      if ( !( p->flags & _BDF_ENCODING ) )
+        goto Missing_Encoding;
+
       error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
       if ( error )
         goto Exit;
       }
 
       /* Allocate enough space for the bitmap. */
-      glyph->bpr   = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
+      glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
 
       bitmap_size = glyph->bpr * glyph->bbx.height;
-      if ( bitmap_size > 0xFFFFU )
+      if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
       {
         FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
         error = BDF_Err_Bbx_Too_Big;
       goto Exit;
     }
 
+    FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
     error = BDF_Err_Invalid_File_Format;
+    goto Exit;
+
+  Missing_Encoding:
+    /* Missing ENCODING field. */
+    FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
+    error = BDF_Err_Missing_Encoding_Field;
 
   Exit:
     if ( error && ( p->flags & _BDF_GLYPH ) )
       {
         p->font->font_ascent = p->font->bbx.ascent;
         ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
-        error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
+        error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
+                                   nbuf, lineno );
         if ( error )
           goto Exit;
 
       {
         p->font->font_descent = p->font->bbx.descent;
         ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
-        error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
+        error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
+                                   nbuf, lineno );
         if ( error )
           goto Exit;
 
       value += 7;
       if ( *value )
         *value++ = 0;
-      error = _bdf_add_property( p->font, name, value );
+      error = _bdf_add_property( p->font, name, value, lineno );
       if ( error )
         goto Exit;
     }
     else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
     {
-      error = _bdf_add_property( p->font, name, value );
+      error = _bdf_add_property( p->font, name, value, lineno );
       if ( error )
         goto Exit;
     }
       _bdf_list_shift( &p->list, 1 );
       value = _bdf_list_join( &p->list, ' ', &vlen );
 
-      error = _bdf_add_property( p->font, name, value );
+      error = _bdf_add_property( p->font, name, value, lineno );
       if ( error )
         goto Exit;
     }
 
       if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
       {
-        /* No STARTFONT field is a good indication of a problem. */
+        /* we don't emit an error message since this code gets */
+        /* explicitly caught one level higher                  */
         error = BDF_Err_Missing_Startfont_Field;
         goto Exit;
       }
 
       if ( !s )
       {
+        FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
         error = BDF_Err_Invalid_File_Format;
         goto Exit;
       }
 
       /* If the font name is an XLFD name, set the spacing to the one in  */
       /* the font name.  If there is no spacing fall back on the default. */
-      error = _bdf_set_default_spacing( p->font, p->opts );
+      error = _bdf_set_default_spacing( p->font, p->opts, lineno );
       if ( error )
         goto Exit;
 
       /* for compiling fonts.                                   */
       p->font->font_ascent = p->font->bbx.ascent;
       ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
-      error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
+      error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
+                                 nbuf, lineno );
       if ( error )
         goto Exit;
       FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
 
       p->font->font_descent = p->font->bbx.descent;
       ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
-      error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
+      error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
+                                 nbuf, lineno );
       if ( error )
         goto Exit;
       FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
       goto Exit;
     }
 
+    FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
     error = BDF_Err_Invalid_File_Format;
 
   Exit:
 
     if ( p->flags & _BDF_START )
     {
+      /* The ENDFONT field was never reached or did not exist. */
+      if ( !( p->flags & _BDF_GLYPHS ) )
       {
-        /* The ENDFONT field was never reached or did not exist. */
-        if ( !( p->flags & _BDF_GLYPHS ) )
-        {
-          /* Error happened while parsing header. */
-          FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
-          error = BDF_Err_Corrupted_Font_Header;
-          goto Exit;
-        }
-        else
-        {
-          /* Error happened when parsing glyphs. */
-          FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
-          error = BDF_Err_Corrupted_Font_Glyphs;
-          goto Exit;
-        }
+        /* Error happened while parsing header. */
+        FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
+        error = BDF_Err_Corrupted_Font_Header;
+        goto Exit;
+      }
+      else
+      {
+        /* Error happened when parsing glyphs. */
+        FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
+        error = BDF_Err_Corrupted_Font_Glyphs;
+        goto Exit;
       }
     }