1 /*  GRAPHITE2 LICENSING
2 
3     Copyright 2010, SIL International
4     All rights reserved.
5 
6     This library is free software; you can redistribute it and/or modify
7     it under the terms of the GNU Lesser General Public License as published
8     by the Free Software Foundation; either version 2.1 of License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14     Lesser General Public License for more details.
15 
16     You should also have received a copy of the GNU Lesser General Public
17     License along with this library in the file named "LICENSE".
18     If not, write to the Free Software Foundation, 51 Franklin Street,
19     Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
20     internet at http://www.fsf.org/licenses/lgpl.html.
21 
22 Alternatively, the contents of this file may be used under the terms of the
23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
24 License, as published by the Free Software Foundation, either version 2
25 of the License or (at your option) any later version.
26 */
27 #include <cstdlib>
28 #include "graphite2/Segment.h"
29 #include "inc/debug.h"
30 #include "inc/Endian.h"
31 #include "inc/Silf.h"
32 #include "inc/Segment.h"
33 #include "inc/Rule.h"
34 #include "inc/Error.h"
35 
36 
37 using namespace graphite2;
38 
39 namespace { static const uint32 ERROROFFSET = 0xFFFFFFFF; }
40 
Silf()41 Silf::Silf() throw()
42 : m_passes(0),
43   m_pseudos(0),
44   m_classOffsets(0),
45   m_classData(0),
46   m_justs(0),
47   m_numPasses(0),
48   m_numJusts(0),
49   m_sPass(0),
50   m_pPass(0),
51   m_jPass(0),
52   m_bPass(0),
53   m_flags(0),
54   m_dir(0),
55   m_aPseudo(0),
56   m_aBreak(0),
57   m_aUser(0),
58   m_aBidi(0),
59   m_aMirror(0),
60   m_aPassBits(0),
61   m_iMaxComp(0),
62   m_aCollision(0),
63   m_aLig(0),
64   m_numPseudo(0),
65   m_nClass(0),
66   m_nLinear(0),
67   m_gEndLine(0)
68 {
69     memset(&m_silfinfo, 0, sizeof m_silfinfo);
70 }
71 
~Silf()72 Silf::~Silf() throw()
73 {
74     releaseBuffers();
75 }
76 
releaseBuffers()77 void Silf::releaseBuffers() throw()
78 {
79     delete [] m_passes;
80     delete [] m_pseudos;
81     free(m_classOffsets);
82     free(m_classData);
83     free(m_justs);
84     m_passes= 0;
85     m_pseudos = 0;
86     m_classOffsets = 0;
87     m_classData = 0;
88     m_justs = 0;
89 }
90 
91 
readGraphite(const byte * const silf_start,size_t lSilf,Face & face,uint32 version)92 bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, uint32 version)
93 {
94     const byte * p = silf_start,
95                * const silf_end = p + lSilf;
96     Error e;
97 
98     if (e.test(version >= 0x00060000, E_BADSILFVERSION))
99     {
100         releaseBuffers(); return face.error(e);
101     }
102     if (version >= 0x00030000)
103     {
104         if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
105         be::skip<int32>(p);    // ruleVersion
106         be::skip<uint16>(p,2); // passOffset & pseudosOffset
107     }
108     else if (e.test(lSilf < 20, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
109     const uint16 maxGlyph = be::read<uint16>(p);
110     m_silfinfo.extra_ascent = be::read<uint16>(p);
111     m_silfinfo.extra_descent = be::read<uint16>(p);
112     m_numPasses = be::read<uint8>(p);
113     m_sPass     = be::read<uint8>(p);
114     m_pPass     = be::read<uint8>(p);
115     m_jPass     = be::read<uint8>(p);
116     m_bPass     = be::read<uint8>(p);
117     m_flags     = be::read<uint8>(p);
118     be::skip<uint8>(p,2); //  max{Pre,Post}Context.
119     m_aPseudo   = be::read<uint8>(p);
120     m_aBreak    = be::read<uint8>(p);
121     m_aBidi     = be::read<uint8>(p);
122     m_aMirror   = be::read<uint8>(p);
123     m_aPassBits = be::read<uint8>(p);
124 
125     // Read Justification levels.
126     m_numJusts  = be::read<uint8>(p);
127     if (e.test(maxGlyph >= face.glyphs().numGlyphs(), E_BADMAXGLYPH)
128         || e.test(p + m_numJusts * 8 >= silf_end, E_BADNUMJUSTS))
129     {
130         releaseBuffers(); return face.error(e);
131     }
132 
133     if (m_numJusts)
134     {
135         m_justs = gralloc<Justinfo>(m_numJusts);
136         if (e.test(!m_justs, E_OUTOFMEM)) return face.error(e);
137 
138         for (uint8 i = 0; i < m_numJusts; i++)
139         {
140             ::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
141             be::skip<byte>(p,8);
142         }
143     }
144 
145     if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
146     m_aLig       = be::read<uint16>(p);
147     m_aUser      = be::read<uint8>(p);
148     m_iMaxComp   = be::read<uint8>(p);
149     m_dir        = be::read<uint8>(p) - 1;
150     m_aCollision = be::read<uint8>(p);
151     be::skip<byte>(p,3);
152     be::skip<uint16>(p, be::read<uint8>(p));    // don't need critical features yet
153     be::skip<byte>(p);                          // reserved
154     if (e.test(p >= silf_end, E_BADCRITFEATURES))   { releaseBuffers(); return face.error(e); }
155     be::skip<uint32>(p, be::read<uint8>(p));    // don't use scriptTag array.
156     if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
157     m_gEndLine  = be::read<uint16>(p);          // lbGID
158     const byte * o_passes = p;
159     uint32 passes_start = be::read<uint32>(p);
160 
161     const size_t num_attrs = face.glyphs().numAttrs();
162     if (e.test(m_aPseudo   >= num_attrs, E_BADAPSEUDO)
163         || e.test(m_aBreak >= num_attrs, E_BADABREAK)
164         || e.test(m_aBidi  >= num_attrs, E_BADABIDI)
165         || e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
166         || e.test(m_aCollision && m_aCollision >= num_attrs - 5, E_BADACOLLISION)
167         || e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= lSilf, E_BADPASSESSTART)
168         || e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
169         || e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
170         || e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
171         || e.test(m_aLig > 127, E_BADALIG))
172     {
173         releaseBuffers();
174         return face.error(e);
175     }
176     be::skip<uint32>(p, m_numPasses);
177     if (e.test(unsigned(p - silf_start) + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
178     m_numPseudo = be::read<uint16>(p);
179     be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
180     m_pseudos = new Pseudo[m_numPseudo];
181     if (e.test(unsigned(p - silf_start) + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO)
182         || e.test(!m_pseudos, E_OUTOFMEM))
183     {
184         releaseBuffers(); return face.error(e);
185     }
186     for (int i = 0; i < m_numPseudo; i++)
187     {
188         m_pseudos[i].uid = be::read<uint32>(p);
189         m_pseudos[i].gid = be::read<uint16>(p);
190     }
191 
192     const size_t clen = readClassMap(p, passes_start + silf_start - p, version, e);
193     m_passes = new Pass[m_numPasses];
194     if (e || e.test(clen > unsigned(passes_start + silf_start - p), E_BADPASSESSTART)
195           || e.test(!m_passes, E_OUTOFMEM))
196     { releaseBuffers(); return face.error(e); }
197 
198     for (size_t i = 0; i < m_numPasses; ++i)
199     {
200         uint32 pass_start = be::read<uint32>(o_passes);
201         uint32 pass_end = be::peek<uint32>(o_passes);
202         face.error_context((face.error_context() & 0xFF00) + EC_ASILF + unsigned(i << 16));
203         if (e.test(pass_start > pass_end, E_BADPASSSTART)
204                 || e.test(pass_start < passes_start, E_BADPASSSTART)
205                 || e.test(pass_end > lSilf, E_BADPASSEND)) {
206             releaseBuffers(); return face.error(e);
207         }
208 
209         enum passtype pt = PASS_TYPE_UNKNOWN;
210         if (i >= m_jPass) pt = PASS_TYPE_JUSTIFICATION;
211         else if (i >= m_pPass) pt = PASS_TYPE_POSITIONING;
212         else if (i >= m_sPass) pt = PASS_TYPE_SUBSTITUTE;
213         else pt = PASS_TYPE_LINEBREAK;
214 
215         m_passes[i].init(this);
216         if (!m_passes[i].readPass(silf_start + pass_start, pass_end - pass_start, pass_start, face, pt,
217             version, e))
218         {
219             releaseBuffers();
220             return false;
221         }
222     }
223 
224     // fill in gr_faceinfo
225     m_silfinfo.upem = face.glyphs().unitsPerEm();
226     m_silfinfo.has_bidi_pass = (m_bPass != 0xFF);
227     m_silfinfo.justifies = (m_numJusts != 0) || (m_jPass < m_pPass);
228     m_silfinfo.line_ends = (m_flags & 1);
229     m_silfinfo.space_contextuals = gr_faceinfo::gr_space_contextuals((m_flags >> 2) & 0x7);
230     return true;
231 }
232 
readClassOffsets(const byte * & p,size_t data_len,Error & e)233 template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len, Error &e)
234 {
235     const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
236     const uint32 max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
237     // Check that the last+1 offset is less than or equal to the class map length.
238     if (e.test(be::peek<T>(p) != cls_off, E_MISALIGNEDCLASSES)
239             || e.test(max_off > (data_len - cls_off)/sizeof(uint16), E_HIGHCLASSOFFSET))
240         return ERROROFFSET;
241 
242     // Read in all the offsets.
243     m_classOffsets = gralloc<uint32>(m_nClass+1);
244     if (e.test(!m_classOffsets, E_OUTOFMEM)) return ERROROFFSET;
245     for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
246     {
247         *o = (be::read<T>(p) - cls_off)/sizeof(uint16);
248         if (e.test(*o > max_off, E_HIGHCLASSOFFSET))
249             return ERROROFFSET;
250     }
251     return max_off;
252 }
253 
readClassMap(const byte * p,size_t data_len,uint32 version,Error & e)254 size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error &e)
255 {
256     if (e.test(data_len < sizeof(uint16)*2, E_BADCLASSSIZE)) return ERROROFFSET;
257 
258     m_nClass  = be::read<uint16>(p);
259     m_nLinear = be::read<uint16>(p);
260 
261     // Check that numLinear < numClass,
262     // that there is at least enough data for numClasses offsets.
263     if (e.test(m_nLinear > m_nClass, E_TOOMANYLINEAR)
264      || e.test((m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16)) > (data_len - 4), E_CLASSESTOOBIG))
265         return ERROROFFSET;
266 
267     uint32 max_off;
268     if (version >= 0x00040000)
269         max_off = readClassOffsets<uint32>(p, data_len, e);
270     else
271         max_off = readClassOffsets<uint16>(p, data_len, e);
272 
273     if (max_off == ERROROFFSET) return ERROROFFSET;
274 
275     if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG))
276         return ERROROFFSET;
277 
278     // Check the linear offsets are sane, these must be monotonically increasing.
279     assert(m_nClass >= m_nLinear);
280     for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
281         if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
282             return ERROROFFSET;
283 
284     // Fortunately the class data is all uint16s so we can decode these now
285     m_classData = gralloc<uint16>(max_off);
286     if (e.test(!m_classData, E_OUTOFMEM)) return ERROROFFSET;
287     for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
288         *d = be::read<uint16>(p);
289 
290     // Check the lookup class invariants for each non-linear class
291     for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
292     {
293         const uint16 * lookup = m_classData + *o;
294         if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET)                        // LookupClass doesn't stretch over max_off
295          || e.test(lookup[0] == 0                                                   // A LookupClass with no looks is a suspicious thing ...
296                     || lookup[0] * 2 + *o + 4 > max_off                             // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
297                     || lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO)    // rangeShift:   numIDs  - searchRange
298          || e.test(((o[1] - *o) & 1) != 0, ERROROFFSET))                         // glyphs are in pairs so difference must be even.
299             return ERROROFFSET;
300     }
301 
302     return max_off;
303 }
304 
findPseudo(uint32 uid) const305 uint16 Silf::findPseudo(uint32 uid) const
306 {
307     for (int i = 0; i < m_numPseudo; i++)
308         if (m_pseudos[i].uid == uid) return m_pseudos[i].gid;
309     return 0;
310 }
311 
findClassIndex(uint16 cid,uint16 gid) const312 uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
313 {
314     if (cid > m_nClass) return -1;
315 
316     const uint16 * cls = m_classData + m_classOffsets[cid];
317     if (cid < m_nLinear)        // output class being used for input, shouldn't happen
318     {
319         for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls)
320             if (*cls == gid) return i;
321         return -1;
322     }
323     else
324     {
325         const uint16 *  min = cls + 4,      // lookups array
326                      *  max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
327         do
328         {
329             const uint16 * p = min + (-2 & ((max-min)/2));
330             if  (p[0] > gid)    max = p;
331             else                min = p;
332         }
333         while (max - min > 2);
334         return min[0] == gid ? min[1] : -1;
335     }
336 }
337 
getClassGlyph(uint16 cid,unsigned int index) const338 uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
339 {
340     if (cid > m_nClass) return 0;
341 
342     uint32 loc = m_classOffsets[cid];
343     if (cid < m_nLinear)
344     {
345         if (index < m_classOffsets[cid + 1] - loc)
346             return m_classData[index + loc];
347     }
348     else        // input class being used for output. Shouldn't happen
349     {
350         for (unsigned int i = loc + 4; i < m_classOffsets[cid + 1]; i += 2)
351             if (m_classData[i + 1] == index) return m_classData[i];
352     }
353     return 0;
354 }
355 
356 
runGraphite(Segment * seg,uint8 firstPass,uint8 lastPass,int dobidi) const357 bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
358 {
359     assert(seg != 0);
360     size_t             maxSize = seg->slotCount() * MAX_SEG_GROWTH_FACTOR;
361     SlotMap            map(*seg, m_dir, maxSize);
362     FiniteStateMachine fsm(map, seg->getFace()->logger());
363     vm::Machine        m(map);
364     uint8              lbidi = m_bPass;
365 #if !defined GRAPHITE2_NTRACING
366     json * const dbgout = seg->getFace()->logger();
367 #endif
368 
369     if (lastPass == 0)
370     {
371         if (firstPass == lastPass && lbidi == 0xFF)
372             return true;
373         lastPass = m_numPasses;
374     }
375     if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi)))
376         lastPass++;
377     else
378         lbidi = 0xFF;
379 
380     for (size_t i = firstPass; i < lastPass; ++i)
381     {
382         // bidi and mirroring
383         if (i == lbidi)
384         {
385 #if !defined GRAPHITE2_NTRACING
386             if (dbgout)
387             {
388                 *dbgout << json::item << json::object
389 //							<< "pindex" << i   // for debugging
390                             << "id"     << -1
391                             << "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
392                             << "passdir" << (m_dir & 1 ? "rtl" : "ltr")
393                             << "slots"  << json::array;
394                 seg->positionSlots(0, 0, 0, seg->currdir());
395                 for(Slot * s = seg->first(); s; s = s->next())
396                     *dbgout     << dslot(seg, s);
397                 *dbgout         << json::close
398                             << "rules"  << json::array << json::close
399                             << json::close;
400             }
401 #endif
402             if (seg->currdir() != (m_dir & 1))
403                 seg->reverseSlots();
404             if (m_aMirror && (seg->dir() & 3) == 3)
405                 seg->doMirror(m_aMirror);
406         --i;
407         lbidi = lastPass;
408         --lastPass;
409         continue;
410         }
411 
412 #if !defined GRAPHITE2_NTRACING
413         if (dbgout)
414         {
415             *dbgout << json::item << json::object
416 //						<< "pindex" << i   // for debugging
417                         << "id"     << i+1
418                         << "slotsdir" << (seg->currdir() ? "rtl" : "ltr")
419                         << "passdir" << ((m_dir & 1) ^ m_passes[i].reverseDir() ? "rtl" : "ltr")
420                         << "slots"  << json::array;
421             seg->positionSlots(0, 0, 0, seg->currdir());
422             for(Slot * s = seg->first(); s; s = s->next())
423                 *dbgout     << dslot(seg, s);
424             *dbgout         << json::close;
425         }
426 #endif
427 
428         // test whether to reorder, prepare for positioning
429         bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
430         if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
431                 && !m_passes[i].runGraphite(m, fsm, reverse))
432             return false;
433         // only subsitution passes can change segment length, cached subsegments are short for their text
434         if (m.status() != vm::Machine::finished
435             || (seg->slotCount() && seg->slotCount() > maxSize))
436             return false;
437     }
438     return true;
439 }
440