a287d3afc4764227137e7d7d635a1999f0df41df
[platform/upstream/freetype2.git] / src / sfnt / ttbdf.c
1 /****************************************************************************
2  *
3  * ttbdf.c
4  *
5  *   TrueType and OpenType embedded BDF properties (body).
6  *
7  * Copyright (C) 2005-2020 by
8  * David Turner, Robert Wilhelm, and Werner Lemberg.
9  *
10  * This file is part of the FreeType project, and may only be used,
11  * modified, and distributed under the terms of the FreeType project
12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
13  * this file you indicate that you have read the license and
14  * understand and accept it fully.
15  *
16  */
17
18
19 #include <freetype/internal/ftdebug.h>
20 #include <freetype/internal/ftstream.h>
21 #include <freetype/tttags.h>
22 #include "ttbdf.h"
23
24 #include "sferrors.h"
25
26
27 #ifdef TT_CONFIG_OPTION_BDF
28
29   /**************************************************************************
30    *
31    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
32    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
33    * messages during execution.
34    */
35 #undef  FT_COMPONENT
36 #define FT_COMPONENT  ttbdf
37
38
39   FT_LOCAL_DEF( void )
40   tt_face_free_bdf_props( TT_Face  face )
41   {
42     TT_BDF  bdf = &face->bdf;
43
44
45     if ( bdf->loaded )
46     {
47       FT_Stream  stream = FT_FACE( face )->stream;
48
49
50       if ( bdf->table )
51         FT_FRAME_RELEASE( bdf->table );
52
53       bdf->table_end    = NULL;
54       bdf->strings      = NULL;
55       bdf->strings_size = 0;
56     }
57   }
58
59
60   static FT_Error
61   tt_face_load_bdf_props( TT_Face    face,
62                           FT_Stream  stream )
63   {
64     TT_BDF    bdf = &face->bdf;
65     FT_ULong  length;
66     FT_Error  error;
67
68
69     FT_ZERO( bdf );
70
71     error = tt_face_goto_table( face, TTAG_BDF, stream, &length );
72     if ( error                                  ||
73          length < 8                             ||
74          FT_FRAME_EXTRACT( length, bdf->table ) )
75     {
76       error = FT_THROW( Invalid_Table );
77       goto Exit;
78     }
79
80     bdf->table_end = bdf->table + length;
81
82     {
83       FT_Byte*   p           = bdf->table;
84       FT_UInt    version     = FT_NEXT_USHORT( p );
85       FT_UInt    num_strikes = FT_NEXT_USHORT( p );
86       FT_ULong   strings     = FT_NEXT_ULONG ( p );
87       FT_UInt    count;
88       FT_Byte*   strike;
89
90
91       if ( version != 0x0001                 ||
92            strings < 8                       ||
93            ( strings - 8 ) / 4 < num_strikes ||
94            strings + 1 > length              )
95       {
96         goto BadTable;
97       }
98
99       bdf->num_strikes  = num_strikes;
100       bdf->strings      = bdf->table + strings;
101       bdf->strings_size = length - strings;
102
103       count  = bdf->num_strikes;
104       p      = bdf->table + 8;
105       strike = p + count * 4;
106
107
108       for ( ; count > 0; count-- )
109       {
110         FT_UInt  num_items = FT_PEEK_USHORT( p + 2 );
111
112         /*
113          * We don't need to check the value sets themselves, since this
114          * is done later.
115          */
116         strike += 10 * num_items;
117
118         p += 4;
119       }
120
121       if ( strike > bdf->strings )
122         goto BadTable;
123     }
124
125     bdf->loaded = 1;
126
127   Exit:
128     return error;
129
130   BadTable:
131     FT_FRAME_RELEASE( bdf->table );
132     FT_ZERO( bdf );
133     error = FT_THROW( Invalid_Table );
134     goto Exit;
135   }
136
137
138   FT_LOCAL_DEF( FT_Error )
139   tt_face_find_bdf_prop( TT_Face           face,
140                          const char*       property_name,
141                          BDF_PropertyRec  *aprop )
142   {
143     TT_BDF     bdf   = &face->bdf;
144     FT_Size    size  = FT_FACE( face )->size;
145     FT_Error   error = FT_Err_Ok;
146     FT_Byte*   p;
147     FT_UInt    count;
148     FT_Byte*   strike;
149     FT_Offset  property_len;
150
151
152     aprop->type = BDF_PROPERTY_TYPE_NONE;
153
154     if ( bdf->loaded == 0 )
155     {
156       error = tt_face_load_bdf_props( face, FT_FACE( face )->stream );
157       if ( error )
158         goto Exit;
159     }
160
161     count  = bdf->num_strikes;
162     p      = bdf->table + 8;
163     strike = p + 4 * count;
164
165     error = FT_ERR( Invalid_Argument );
166
167     if ( !size || !property_name )
168       goto Exit;
169
170     property_len = ft_strlen( property_name );
171     if ( property_len == 0 )
172       goto Exit;
173
174     for ( ; count > 0; count-- )
175     {
176       FT_UInt  _ppem  = FT_NEXT_USHORT( p );
177       FT_UInt  _count = FT_NEXT_USHORT( p );
178
179
180       if ( _ppem == size->metrics.y_ppem )
181       {
182         count = _count;
183         goto FoundStrike;
184       }
185
186       strike += 10 * _count;
187     }
188     goto Exit;
189
190   FoundStrike:
191     p = strike;
192     for ( ; count > 0; count-- )
193     {
194       FT_UInt  type = FT_PEEK_USHORT( p + 4 );
195
196
197       if ( ( type & 0x10 ) != 0 )
198       {
199         FT_UInt32  name_offset = FT_PEEK_ULONG( p     );
200         FT_UInt32  value       = FT_PEEK_ULONG( p + 6 );
201
202         /* be a bit paranoid for invalid entries here */
203         if ( name_offset < bdf->strings_size                    &&
204              property_len < bdf->strings_size - name_offset     &&
205              ft_strncmp( property_name,
206                          (const char*)bdf->strings + name_offset,
207                          bdf->strings_size - name_offset ) == 0 )
208         {
209           switch ( type & 0x0F )
210           {
211           case 0x00:  /* string */
212           case 0x01:  /* atoms */
213             /* check that the content is really 0-terminated */
214             if ( value < bdf->strings_size &&
215                  ft_memchr( bdf->strings + value, 0, bdf->strings_size ) )
216             {
217               aprop->type   = BDF_PROPERTY_TYPE_ATOM;
218               aprop->u.atom = (const char*)bdf->strings + value;
219               error         = FT_Err_Ok;
220               goto Exit;
221             }
222             break;
223
224           case 0x02:
225             aprop->type      = BDF_PROPERTY_TYPE_INTEGER;
226             aprop->u.integer = (FT_Int32)value;
227             error            = FT_Err_Ok;
228             goto Exit;
229
230           case 0x03:
231             aprop->type       = BDF_PROPERTY_TYPE_CARDINAL;
232             aprop->u.cardinal = value;
233             error             = FT_Err_Ok;
234             goto Exit;
235
236           default:
237             ;
238           }
239         }
240       }
241       p += 10;
242     }
243
244   Exit:
245     return error;
246   }
247
248 #else /* !TT_CONFIG_OPTION_BDF */
249
250   /* ANSI C doesn't like empty source files */
251   typedef int  _tt_bdf_dummy;
252
253 #endif /* !TT_CONFIG_OPTION_BDF */
254
255
256 /* END */