Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : // Description:
21 : // Parse a string of features specified as & separated pairs.
22 : // e.g.
23 : // 1001=1&2002=2&fav1=0
24 :
25 :
26 : #include <sal/types.h>
27 : #include <osl/endian.h>
28 :
29 : #ifdef WNT
30 : #include <windows.h>
31 : #endif
32 :
33 : #include <graphite_features.hxx>
34 :
35 : using namespace grutils;
36 : // These mustn't conflict with font name lists which use ; and ,
37 : const char GrFeatureParser::FEAT_PREFIX = ':';
38 : const char GrFeatureParser::FEAT_SEPARATOR = '&';
39 : const char GrFeatureParser::FEAT_ID_VALUE_SEPARATOR = '=';
40 :
41 0 : GrFeatureParser::GrFeatureParser(const gr_face * pFace, const OString lang)
42 0 : : mnNumSettings(0), mbErrors(false), mpSettings(NULL)
43 : {
44 0 : maLang.label[0] = maLang.label[1] = maLang.label[2] = maLang.label[3] = '\0';
45 0 : setLang(pFace, lang);
46 0 : }
47 :
48 0 : GrFeatureParser::GrFeatureParser(const gr_face * pFace, const OString features, const OString lang)
49 0 : : mnNumSettings(0), mbErrors(false), mpSettings(NULL)
50 : {
51 0 : sal_Int32 nEquals = 0;
52 0 : sal_Int32 nFeatEnd = 0;
53 0 : sal_Int32 pos = 0;
54 0 : maLang.num = 0u;
55 0 : setLang(pFace, lang);
56 0 : while ((pos < features.getLength()) && (mnNumSettings < MAX_FEATURES))
57 : {
58 0 : nEquals = features.indexOf(FEAT_ID_VALUE_SEPARATOR, pos);
59 0 : if (nEquals == -1)
60 : {
61 0 : mbErrors = true;
62 0 : break;
63 : }
64 : // check for a lang=xxx specification
65 0 : const OString aLangPrefix("lang");
66 0 : if (features.match(aLangPrefix, pos ))
67 : {
68 0 : pos = nEquals + 1;
69 0 : nFeatEnd = features.indexOf(FEAT_SEPARATOR, pos);
70 0 : if (nFeatEnd == -1)
71 : {
72 0 : nFeatEnd = features.getLength();
73 : }
74 0 : if (nFeatEnd - pos > 3)
75 0 : mbErrors = true;
76 : else
77 : {
78 0 : FeatId aLang = maLang;
79 0 : aLang.num = 0;
80 0 : for (sal_Int32 i = pos; i < nFeatEnd; i++)
81 0 : aLang.label[i-pos] = features[i];
82 :
83 : //ext_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported
84 : // = font.getSupportedLanguages();
85 : //gr::LanguageIterator iL = aSupported.first;
86 0 : unsigned short i = 0;
87 0 : for (; i < gr_face_n_languages(pFace); i++)
88 : {
89 0 : gr_uint32 nFaceLang = gr_face_lang_by_index(pFace, i);
90 : FeatId aSupportedLang;
91 0 : aSupportedLang.num = nFaceLang;
92 : #ifdef OSL_BIGENDIAN
93 : // here we only expect full 3 letter codes
94 : if (aLang.label[0] == aSupportedLang.label[0] &&
95 : aLang.label[1] == aSupportedLang.label[1] &&
96 : aLang.label[2] == aSupportedLang.label[2] &&
97 : aLang.label[3] == aSupportedLang.label[3])
98 : #else
99 0 : if (aLang.label[0] == aSupportedLang.label[3] &&
100 0 : aLang.label[1] == aSupportedLang.label[2] &&
101 0 : aLang.label[2] == aSupportedLang.label[1] &&
102 0 : aLang.label[3] == aSupportedLang.label[0])
103 : #endif
104 : {
105 0 : maLang = aSupportedLang;
106 0 : break;
107 : }
108 : }
109 0 : if (i == gr_face_n_languages(pFace)) mbErrors = true;
110 : else
111 : {
112 0 : mnHash = maLang.num;
113 0 : mpSettings = gr_face_featureval_for_lang(pFace, maLang.num);
114 : }
115 : }
116 : }
117 : else
118 : {
119 0 : sal_uInt32 featId = 0;
120 0 : if (isCharId(features, pos, nEquals - pos))
121 : {
122 0 : featId = getCharId(features, pos, nEquals - pos);
123 : }
124 : else
125 : {
126 0 : featId = getIntValue(features, pos, nEquals - pos);
127 : }
128 0 : const gr_feature_ref * pFref = gr_face_find_fref(pFace, featId);
129 0 : pos = nEquals + 1;
130 0 : nFeatEnd = features.indexOf(FEAT_SEPARATOR, pos);
131 0 : if (nFeatEnd == -1)
132 : {
133 0 : nFeatEnd = features.getLength();
134 : }
135 0 : sal_Int16 featValue = 0;
136 0 : featValue = getIntValue(features, pos, nFeatEnd - pos);
137 0 : if (pFref && gr_fref_set_feature_value(pFref, featValue, mpSettings))
138 : {
139 0 : mnHash = (mnHash << 16) ^ ((featId << 8) | featValue);
140 0 : mnNumSettings++;
141 : }
142 : else
143 0 : mbErrors = true;
144 : }
145 0 : pos = nFeatEnd + 1;
146 0 : }
147 0 : }
148 :
149 0 : void GrFeatureParser::setLang(const gr_face * pFace, const OString & lang)
150 : {
151 : FeatId aLang;
152 0 : aLang.num = 0;
153 0 : if (lang.getLength() >= 2)
154 : {
155 0 : for (sal_Int32 i = 0; i < lang.getLength() && i < 3; i++)
156 : {
157 0 : if (lang[i] == '-') break;
158 0 : aLang.label[i] = lang[i];
159 : }
160 0 : unsigned short i = 0;
161 0 : for (; i < gr_face_n_languages(pFace); i++)
162 : {
163 0 : gr_uint32 nFaceLang = gr_face_lang_by_index(pFace, i);
164 : FeatId aSupportedLang;
165 0 : aSupportedLang.num = nFaceLang;
166 : // here we only expect full 2 & 3 letter codes
167 : #ifdef OSL_BIGENDIAN
168 : if (aLang.label[0] == aSupportedLang.label[0] &&
169 : aLang.label[1] == aSupportedLang.label[1] &&
170 : aLang.label[2] == aSupportedLang.label[2] &&
171 : aLang.label[3] == aSupportedLang.label[3])
172 : #else
173 0 : if (aLang.label[0] == aSupportedLang.label[3] &&
174 0 : aLang.label[1] == aSupportedLang.label[2] &&
175 0 : aLang.label[2] == aSupportedLang.label[1] &&
176 0 : aLang.label[3] == aSupportedLang.label[0])
177 : #endif
178 : {
179 0 : maLang = aSupportedLang;
180 0 : break;
181 : }
182 : }
183 0 : if (i != gr_face_n_languages(pFace))
184 : {
185 0 : if (mpSettings)
186 0 : gr_featureval_destroy(mpSettings);
187 0 : mpSettings = gr_face_featureval_for_lang(pFace, maLang.num);
188 0 : mnHash = maLang.num;
189 : }
190 : }
191 0 : if (!mpSettings)
192 0 : mpSettings = gr_face_featureval_for_lang(pFace, 0);
193 0 : }
194 :
195 0 : GrFeatureParser::~GrFeatureParser()
196 : {
197 0 : if (mpSettings)
198 : {
199 0 : gr_featureval_destroy(mpSettings);
200 0 : mpSettings = NULL;
201 : }
202 0 : }
203 :
204 0 : bool GrFeatureParser::isCharId(const OString & id, size_t offset, size_t length)
205 : {
206 0 : if (length > 4) return false;
207 0 : for (size_t i = 0; i < length; i++)
208 : {
209 0 : if (i > 0 && id[offset+i] == '\0') continue;
210 0 : if (id[offset+i] < 0x20 || static_cast<signed char>(id[offset+i]) < 0)
211 0 : return false;
212 0 : if (i==0 && (id[offset+i] < 0x41))
213 0 : return false;
214 : }
215 0 : return true;
216 : }
217 :
218 0 : gr_uint32 GrFeatureParser::getCharId(const OString & id, size_t offset, size_t length)
219 : {
220 : FeatId charId;
221 0 : charId.num = 0;
222 : #ifdef WORDS_BIGENDIAN
223 : for (size_t i = 0; i < length; i++)
224 : {
225 : charId.label[i] = id[offset+i];
226 : }
227 : #else
228 0 : for (size_t i = 0; i < length; i++)
229 : {
230 0 : charId.label[3-i] = id[offset+i];
231 : }
232 : #endif
233 0 : return charId.num;
234 : }
235 :
236 0 : short GrFeatureParser::getIntValue(const OString & id, size_t offset, size_t length)
237 : {
238 0 : short value = 0;
239 0 : int sign = 1;
240 0 : for (size_t i = 0; i < length; i++)
241 : {
242 0 : switch (id[offset + i])
243 : {
244 : case '0':
245 : case '1':
246 : case '2':
247 : case '3':
248 : case '4':
249 : case '5':
250 : case '6':
251 : case '7':
252 : case '8':
253 : case '9':
254 0 : value *= 10;
255 0 : if (sign < 0)
256 : {
257 0 : value = -(id[offset + i] - '0');
258 0 : sign = 1;
259 : }
260 0 : value += (id[offset + i] - '0');
261 0 : break;
262 : case '-':
263 0 : if (i == 0)
264 0 : sign = -1;
265 : else
266 : {
267 0 : mbErrors = true;
268 0 : break;
269 : }
270 : default:
271 0 : mbErrors = true;
272 0 : break;
273 : }
274 : }
275 0 : return value;
276 : }
277 :
278 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|