1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
259d709d503bab6e2b61931737e662dd293b40578ccornelius * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LETypes.h"
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "OpenTypeTables.h"
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "OpenTypeUtilities.h"
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "ScriptAndLanguage.h"
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LESwaps.h"
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1459d709d503bab6e2b61931737e662dd293b40578ccorneliusLEReferenceTo<LangSysTable> ScriptTable::findLanguage(const LETableReference& base, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_uint16 count = SWAPW(langSysCount);
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    Offset langSysTableOffset = exactMatch? 0 : SWAPW(defaultLangSysTableOffset);
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (count > 0) {
2059d709d503bab6e2b61931737e662dd293b40578ccornelius      LEReferenceToArrayOf<TagAndOffsetRecord> langSysRecords(base, success, langSysRecordArray, count);
2159d709d503bab6e2b61931737e662dd293b40578ccornelius      Offset foundOffset =
2259d709d503bab6e2b61931737e662dd293b40578ccornelius        OpenTypeUtilities::getTagOffset(languageTag, langSysRecords, success);
2359d709d503bab6e2b61931737e662dd293b40578ccornelius
2459d709d503bab6e2b61931737e662dd293b40578ccornelius      if (foundOffset != 0 && LE_SUCCESS(success)) {
2559d709d503bab6e2b61931737e662dd293b40578ccornelius        langSysTableOffset = foundOffset;
2659d709d503bab6e2b61931737e662dd293b40578ccornelius      }
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2859d709d503bab6e2b61931737e662dd293b40578ccornelius
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (langSysTableOffset != 0) {
3059d709d503bab6e2b61931737e662dd293b40578ccornelius      return LEReferenceTo<LangSysTable>(base, success, langSysTableOffset);
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
3359d709d503bab6e2b61931737e662dd293b40578ccornelius    return LEReferenceTo<LangSysTable>();
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
3659d709d503bab6e2b61931737e662dd293b40578ccorneliusLEReferenceTo<ScriptTable> ScriptListTable::findScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
3859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (LE_FAILURE(success) ) {
3959d709d503bab6e2b61931737e662dd293b40578ccornelius      return LEReferenceTo<ScriptTable>(); // get out
4059d709d503bab6e2b61931737e662dd293b40578ccornelius    }
4185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    /*
4285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * There are some fonts that have a large, bogus value for scriptCount. To try
4385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * and protect against this, we use the offset in the first scriptRecord,
4485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * which we know has to be past the end of the scriptRecordArray, to compute
4585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * a value which is greater than or equal to the actual script count.
4685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     *
4785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * Note: normally, the first offset will point to just after the scriptRecordArray,
4885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * but there's no guarantee of this, only that it's *after* the scriptRecordArray.
4985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * Because of this, a binary serach isn't safe, because the new count may include
5085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * data that's not actually in the scriptRecordArray and hence the array will appear
5185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     * to be unsorted.
5285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     */
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_uint16 count = SWAPW(scriptCount);
5459d709d503bab6e2b61931737e662dd293b40578ccornelius
5559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (count == 0) {
5659d709d503bab6e2b61931737e662dd293b40578ccornelius      return LEReferenceTo<ScriptTable>(); // no items, no search
5759d709d503bab6e2b61931737e662dd293b40578ccornelius    }
5859d709d503bab6e2b61931737e662dd293b40578ccornelius
5959d709d503bab6e2b61931737e662dd293b40578ccornelius    // attempt to construct a ref with at least one element
6059d709d503bab6e2b61931737e662dd293b40578ccornelius    LEReferenceToArrayOf<ScriptRecord> oneElementTable(base, success, &scriptRecordArray[0], 1);
6159d709d503bab6e2b61931737e662dd293b40578ccornelius
6259d709d503bab6e2b61931737e662dd293b40578ccornelius    if( LE_FAILURE(success) ) {
6359d709d503bab6e2b61931737e662dd293b40578ccornelius      return LEReferenceTo<ScriptTable>(); // couldn't even read the first record - bad font.
6459d709d503bab6e2b61931737e662dd293b40578ccornelius    }
6559d709d503bab6e2b61931737e662dd293b40578ccornelius
6685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    le_uint16 limit = ((SWAPW(scriptRecordArray[0].offset) - sizeof(ScriptListTable)) / sizeof(scriptRecordArray)) + ANY_NUMBER;
6785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    Offset scriptTableOffset = 0;
6859d709d503bab6e2b61931737e662dd293b40578ccornelius
6985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
7085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (count > limit) {
7185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        // the scriptCount value is bogus; do a linear search
7285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        // because limit may still be too large.
7359d709d503bab6e2b61931737e662dd293b40578ccornelius        LEReferenceToArrayOf<ScriptRecord> scriptRecordArrayRef(base, success, &scriptRecordArray[0], limit);
7459d709d503bab6e2b61931737e662dd293b40578ccornelius        for(le_int32 s = 0; (s < limit)&&LE_SUCCESS(success); s += 1) {
7559d709d503bab6e2b61931737e662dd293b40578ccornelius          if (SWAPT(scriptRecordArrayRef(s,success).tag) == scriptTag) {
7659d709d503bab6e2b61931737e662dd293b40578ccornelius            scriptTableOffset = SWAPW(scriptRecordArrayRef(s,success).offset);
7759d709d503bab6e2b61931737e662dd293b40578ccornelius            break;
7859d709d503bab6e2b61931737e662dd293b40578ccornelius          }
7985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
8085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    } else {
8159d709d503bab6e2b61931737e662dd293b40578ccornelius      LEReferenceToArrayOf<ScriptRecord> scriptRecordArrayRef(base, success, &scriptRecordArray[0], count);
8259d709d503bab6e2b61931737e662dd293b40578ccornelius
8359d709d503bab6e2b61931737e662dd293b40578ccornelius      scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArrayRef, success);
8485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (scriptTableOffset != 0) {
8759d709d503bab6e2b61931737e662dd293b40578ccornelius      return LEReferenceTo<ScriptTable>(base, success, scriptTableOffset);
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
9059d709d503bab6e2b61931737e662dd293b40578ccornelius  return LEReferenceTo<ScriptTable>();
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
9359d709d503bab6e2b61931737e662dd293b40578ccorneliusLEReferenceTo<LangSysTable>  ScriptListTable::findLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
9559d709d503bab6e2b61931737e662dd293b40578ccornelius  const LEReferenceTo<ScriptTable> scriptTable = findScript(base, scriptTag, success);
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
9759d709d503bab6e2b61931737e662dd293b40578ccornelius  if (scriptTable.isEmpty()) {
9859d709d503bab6e2b61931737e662dd293b40578ccornelius    return LEReferenceTo<LangSysTable>();
9959d709d503bab6e2b61931737e662dd293b40578ccornelius  }
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
10159d709d503bab6e2b61931737e662dd293b40578ccornelius  return scriptTable->findLanguage(scriptTable, languageTag, success, exactMatch).reparent(base);
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
105