OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // A parser for the Type 2 Charstring Format. | 5 // A parser for the Type 2 Charstring Format. |
6 // http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf | 6 // http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf |
7 | 7 |
8 #include "cff_type2_charstring.h" | 8 #include "cff_type2_charstring.h" |
9 | 9 |
| 10 #include <climits> |
10 #include <cstdio> | 11 #include <cstdio> |
11 #include <cstring> | 12 #include <cstring> |
12 #include <limits> | |
13 #include <stack> | 13 #include <stack> |
14 #include <string> | 14 #include <string> |
15 #include <utility> | 15 #include <utility> |
16 | 16 |
17 namespace { | 17 namespace { |
18 | 18 |
19 // The list of Operators. See Appendix. A in Adobe Technical Note #5177. | |
20 enum Type2CharStringOperator { | |
21 kHStem = 1, | |
22 kVStem = 3, | |
23 kVMoveTo = 4, | |
24 kRLineTo = 5, | |
25 kHLineTo = 6, | |
26 kVLineTo = 7, | |
27 kRRCurveTo = 8, | |
28 kCallSubr = 10, | |
29 kReturn = 11, | |
30 kEndChar = 14, | |
31 kHStemHm = 18, | |
32 kHintMask = 19, | |
33 kCntrMask = 20, | |
34 kRMoveTo = 21, | |
35 kHMoveTo = 22, | |
36 kVStemHm = 23, | |
37 kRCurveLine = 24, | |
38 kRLineCurve = 25, | |
39 kVVCurveTo = 26, | |
40 kHHCurveTo = 27, | |
41 kCallGSubr = 29, | |
42 kVHCurveTo = 30, | |
43 kHVCurveTo = 31, | |
44 kAnd = (12 << 8) + 3, | |
45 kOr = (12 << 8) + 4, | |
46 kNot = (12 << 8) + 5, | |
47 kAbs = (12 << 8) + 9, | |
48 kAdd = (12 << 8) + 10, | |
49 kSub = (12 << 8) + 11, | |
50 kDiv = (12 << 8) + 12, | |
51 kNeg = (12 << 8) + 14, | |
52 kEq = (12 << 8) + 15, | |
53 kDrop = (12 << 8) + 18, | |
54 kPut = (12 << 8) + 20, | |
55 kGet = (12 << 8) + 21, | |
56 kIfElse = (12 << 8) + 22, | |
57 kRandom = (12 << 8) + 23, | |
58 kMul = (12 << 8) + 24, | |
59 kSqrt = (12 << 8) + 26, | |
60 kDup = (12 << 8) + 27, | |
61 kExch = (12 << 8) + 28, | |
62 kIndex = (12 << 8) + 29, | |
63 kRoll = (12 << 8) + 30, | |
64 kHFlex = (12 << 8) + 34, | |
65 kFlex = (12 << 8) + 35, | |
66 kHFlex1 = (12 << 8) + 36, | |
67 kFlex1 = (12 << 8) + 37, | |
68 }; | |
69 | |
70 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical | 19 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical |
71 // Note #5177. | 20 // Note #5177. |
| 21 const int32_t kMaxSubrsCount = 65536; |
72 const size_t kMaxCharStringLength = 65535; | 22 const size_t kMaxCharStringLength = 65535; |
73 const size_t kMaxArgumentStack = 48; | 23 const size_t kMaxArgumentStack = 48; |
74 const size_t kMaxNumberOfStemHints = 96; | 24 const size_t kMaxNumberOfStemHints = 96; |
75 const size_t kMaxSubrNesting = 10; | 25 const size_t kMaxSubrNesting = 10; |
76 | 26 |
| 27 // |dummy_result| should be a huge positive integer so callsubr and callgsubr |
| 28 // will fail with the dummy value. |
| 29 const int32_t dummy_result = INT_MAX; |
| 30 |
77 bool ExecuteType2CharString(size_t call_depth, | 31 bool ExecuteType2CharString(size_t call_depth, |
78 const ots::CFFIndex& global_subrs_index, | 32 const ots::CFFIndex& global_subrs_index, |
79 const ots::CFFIndex& local_subrs_index, | 33 const ots::CFFIndex& local_subrs_index, |
80 ots::Buffer *cff_table, | 34 ots::Buffer *cff_table, |
81 ots::Buffer *char_string, | 35 ots::Buffer *char_string, |
82 std::stack<int32_t> *argument_stack, | 36 std::stack<int32_t> *argument_stack, |
83 bool *out_found_endchar, | 37 bool *out_found_endchar, |
84 bool *out_found_width, | 38 bool *out_found_width, |
85 size_t *in_out_num_stems); | 39 size_t *in_out_num_stems); |
86 | 40 |
87 // Converts |op| to a string and returns it. | 41 // Converts |op| to a string and returns it. |
88 const char *Type2CharStringOperatorToString(Type2CharStringOperator op) { | 42 const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) { |
89 switch (op) { | 43 switch (op) { |
90 case kHStem: | 44 case ots::kHStem: |
91 return "HStem"; | 45 return "HStem"; |
92 case kVStem: | 46 case ots::kVStem: |
93 return "VStem"; | 47 return "VStem"; |
94 case kVMoveTo: | 48 case ots::kVMoveTo: |
95 return "VMoveTo"; | 49 return "VMoveTo"; |
96 case kRLineTo: | 50 case ots::kRLineTo: |
97 return "RLineTo"; | 51 return "RLineTo"; |
98 case kHLineTo: | 52 case ots::kHLineTo: |
99 return "HLineTo"; | 53 return "HLineTo"; |
100 case kVLineTo: | 54 case ots::kVLineTo: |
101 return "VLineTo"; | 55 return "VLineTo"; |
102 case kRRCurveTo: | 56 case ots::kRRCurveTo: |
103 return "RRCurveTo"; | 57 return "RRCurveTo"; |
104 case kCallSubr: | 58 case ots::kCallSubr: |
105 return "CallSubr"; | 59 return "CallSubr"; |
106 case kReturn: | 60 case ots::kReturn: |
107 return "Return"; | 61 return "Return"; |
108 case kEndChar: | 62 case ots::kEndChar: |
109 return "EndChar"; | 63 return "EndChar"; |
110 case kHStemHm: | 64 case ots::kHStemHm: |
111 return "HStemHm"; | 65 return "HStemHm"; |
112 case kHintMask: | 66 case ots::kHintMask: |
113 return "HintMask"; | 67 return "HintMask"; |
114 case kCntrMask: | 68 case ots::kCntrMask: |
115 return "CntrMask"; | 69 return "CntrMask"; |
116 case kRMoveTo: | 70 case ots::kRMoveTo: |
117 return "RMoveTo"; | 71 return "RMoveTo"; |
118 case kHMoveTo: | 72 case ots::kHMoveTo: |
119 return "HMoveTo"; | 73 return "HMoveTo"; |
120 case kVStemHm: | 74 case ots::kVStemHm: |
121 return "VStemHm"; | 75 return "VStemHm"; |
122 case kRCurveLine: | 76 case ots::kRCurveLine: |
123 return "RCurveLine"; | 77 return "RCurveLine"; |
124 case kRLineCurve: | 78 case ots::kRLineCurve: |
125 return "RLineCurve"; | 79 return "RLineCurve"; |
126 case kVVCurveTo: | 80 case ots::kVVCurveTo: |
127 return "VVCurveTo"; | 81 return "VVCurveTo"; |
128 case kHHCurveTo: | 82 case ots::kHHCurveTo: |
129 return "HHCurveTo"; | 83 return "HHCurveTo"; |
130 case kCallGSubr: | 84 case ots::kCallGSubr: |
131 return "CallGSubr"; | 85 return "CallGSubr"; |
132 case kVHCurveTo: | 86 case ots::kVHCurveTo: |
133 return "VHCurveTo"; | 87 return "VHCurveTo"; |
134 case kHVCurveTo: | 88 case ots::kHVCurveTo: |
135 return "HVCurveTo"; | 89 return "HVCurveTo"; |
136 case kAnd: | 90 case ots::kAnd: |
137 return "And"; | 91 return "And"; |
138 case kOr: | 92 case ots::kOr: |
139 return "Or"; | 93 return "Or"; |
140 case kNot: | 94 case ots::kNot: |
141 return "Not"; | 95 return "Not"; |
142 case kAbs: | 96 case ots::kAbs: |
143 return "Abs"; | 97 return "Abs"; |
144 case kAdd: | 98 case ots::kAdd: |
145 return "Add"; | 99 return "Add"; |
146 case kSub: | 100 case ots::kSub: |
147 return "Sub"; | 101 return "Sub"; |
148 case kDiv: | 102 case ots::kDiv: |
149 return "Div"; | 103 return "Div"; |
150 case kNeg: | 104 case ots::kNeg: |
151 return "Neg"; | 105 return "Neg"; |
152 case kEq: | 106 case ots::kEq: |
153 return "Eq"; | 107 return "Eq"; |
154 case kDrop: | 108 case ots::kDrop: |
155 return "Drop"; | 109 return "Drop"; |
156 case kPut: | 110 case ots::kPut: |
157 return "Put"; | 111 return "Put"; |
158 case kGet: | 112 case ots::kGet: |
159 return "Get"; | 113 return "Get"; |
160 case kIfElse: | 114 case ots::kIfElse: |
161 return "IfElse"; | 115 return "IfElse"; |
162 case kRandom: | 116 case ots::kRandom: |
163 return "Random"; | 117 return "Random"; |
164 case kMul: | 118 case ots::kMul: |
165 return "Mul"; | 119 return "Mul"; |
166 case kSqrt: | 120 case ots::kSqrt: |
167 return "Sqrt"; | 121 return "Sqrt"; |
168 case kDup: | 122 case ots::kDup: |
169 return "Dup"; | 123 return "Dup"; |
170 case kExch: | 124 case ots::kExch: |
171 return "Exch"; | 125 return "Exch"; |
172 case kIndex: | 126 case ots::kIndex: |
173 return "Index"; | 127 return "Index"; |
174 case kRoll: | 128 case ots::kRoll: |
175 return "Roll"; | 129 return "Roll"; |
176 case kHFlex: | 130 case ots::kHFlex: |
177 return "HFlex"; | 131 return "HFlex"; |
178 case kFlex: | 132 case ots::kFlex: |
179 return "Flex"; | 133 return "Flex"; |
180 case kHFlex1: | 134 case ots::kHFlex1: |
181 return "HFlex1"; | 135 return "HFlex1"; |
182 case kFlex1: | 136 case ots::kFlex1: |
183 return "Flex1"; | 137 return "Flex1"; |
184 } | 138 } |
185 | 139 |
186 return "UNKNOWN"; | 140 return "UNKNOWN"; |
187 } | 141 } |
188 | 142 |
189 // Read one or more bytes from the |char_string| buffer and stores the number | 143 // Read one or more bytes from the |char_string| buffer and stores the number |
190 // read on |out_number|. If the number read is an operator (ex 'vstem'), sets | 144 // read on |out_number|. If the number read is an operator (ex 'vstem'), sets |
191 // true on |out_is_operator|. Returns true if the function read a number. | 145 // true on |out_is_operator|. Returns true if the function read a number. |
192 bool ReadNextNumberFromType2CharString(ots::Buffer *char_string, | 146 bool ReadNextNumberFromType2CharString(ots::Buffer *char_string, |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 *out_number = ((static_cast<int32_t>(v) - 247) * 256) + | 193 *out_number = ((static_cast<int32_t>(v) - 247) * 256) + |
240 static_cast<int32_t>(w) + 108; | 194 static_cast<int32_t>(w) + 108; |
241 } else if (v <= 254) { | 195 } else if (v <= 254) { |
242 uint8_t w = 0; | 196 uint8_t w = 0; |
243 if (!char_string->ReadU8(&w)) { | 197 if (!char_string->ReadU8(&w)) { |
244 return OTS_FAILURE(); | 198 return OTS_FAILURE(); |
245 } | 199 } |
246 *out_number = -((static_cast<int32_t>(v) - 251) * 256) - | 200 *out_number = -((static_cast<int32_t>(v) - 251) * 256) - |
247 static_cast<int32_t>(w) - 108; | 201 static_cast<int32_t>(w) - 108; |
248 } else if (v == 255) { | 202 } else if (v == 255) { |
249 uint32_t result = 0; | 203 // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255, |
250 for (size_t i = 0; i < 4; ++i) { | 204 // we should treat the following 4-bytes as a 16.16 fixed-point number |
251 if (!char_string->ReadU8(&v)) { | 205 // rather than 32bit signed int. |
252 return OTS_FAILURE(); | 206 if (!char_string->Skip(4)) { |
253 } | 207 return OTS_FAILURE(); |
254 result = (result << 8) + v; | |
255 } | 208 } |
256 // TODO(yusukes): |result| should be treated as 16.16 fixed-point number | 209 *out_number = dummy_result; |
257 // rather than 32bit signed int. | |
258 *out_number = static_cast<int32_t>(result); | |
259 } else { | 210 } else { |
260 return OTS_FAILURE(); | 211 return OTS_FAILURE(); |
261 } | 212 } |
262 | 213 |
263 return true; | 214 return true; |
264 } | 215 } |
265 | 216 |
266 // Executes |op| and updates |argument_stack|. Returns true if the execution | 217 // Executes |op| and updates |argument_stack|. Returns true if the execution |
267 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively | 218 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively |
268 // calls ExecuteType2CharString() function. The arguments other than |op| and | 219 // calls ExecuteType2CharString() function. The arguments other than |op| and |
269 // |argument_stack| are passed for that reason. | 220 // |argument_stack| are passed for that reason. |
270 bool ExecuteType2CharStringOperator(int32_t op, | 221 bool ExecuteType2CharStringOperator(int32_t op, |
271 size_t call_depth, | 222 size_t call_depth, |
272 const ots::CFFIndex& global_subrs_index, | 223 const ots::CFFIndex& global_subrs_index, |
273 const ots::CFFIndex& local_subrs_index, | 224 const ots::CFFIndex& local_subrs_index, |
274 ots::Buffer *cff_table, | 225 ots::Buffer *cff_table, |
275 ots::Buffer *char_string, | 226 ots::Buffer *char_string, |
276 std::stack<int32_t> *argument_stack, | 227 std::stack<int32_t> *argument_stack, |
277 bool *out_found_endchar, | 228 bool *out_found_endchar, |
278 bool *in_out_found_width, | 229 bool *in_out_found_width, |
279 size_t *in_out_num_stems) { | 230 size_t *in_out_num_stems) { |
280 // |dummy_result| should be a huge positive integer so callsubr and callgsubr | |
281 // will fail with the dummy value. | |
282 const int32_t dummy_result = std::numeric_limits<int>::max(); | |
283 const size_t stack_size = argument_stack->size(); | 231 const size_t stack_size = argument_stack->size(); |
284 | 232 |
285 switch (op) { | 233 switch (op) { |
286 case kCallSubr: | 234 case ots::kCallSubr: |
287 case kCallGSubr: { | 235 case ots::kCallGSubr: { |
288 const ots::CFFIndex& subrs_index = | 236 const ots::CFFIndex& subrs_index = |
289 (op == kCallSubr ? local_subrs_index : global_subrs_index); | 237 (op == ots::kCallSubr ? local_subrs_index : global_subrs_index); |
290 | 238 |
291 if (stack_size < 1) { | 239 if (stack_size < 1) { |
292 return OTS_FAILURE(); | 240 return OTS_FAILURE(); |
293 } | 241 } |
294 int32_t subr_number = argument_stack->top(); | 242 int32_t subr_number = argument_stack->top(); |
295 argument_stack->pop(); | 243 argument_stack->pop(); |
296 if (subr_number == dummy_result) { | 244 if (subr_number == dummy_result) { |
297 // For safety, we allow subr calls only with immediate subr numbers for | 245 // For safety, we allow subr calls only with immediate subr numbers for |
298 // now. For example, we allow "123 callgsubr", but does not allow "100 12 | 246 // now. For example, we allow "123 callgsubr", but does not allow "100 12 |
299 // add callgsubr". Please note that arithmetic and conditional operators | 247 // add callgsubr". Please note that arithmetic and conditional operators |
300 // always push the |dummy_result| in this implementation. | 248 // always push the |dummy_result| in this implementation. |
301 return OTS_FAILURE(); | 249 return OTS_FAILURE(); |
302 } | 250 } |
303 | 251 |
304 // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes." | 252 // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes." |
305 int32_t bias = 32768; | 253 int32_t bias = 32768; |
306 if (subrs_index.count < 1240) { | 254 if (subrs_index.count < 1240) { |
307 bias = 107; | 255 bias = 107; |
308 } else if (subrs_index.count < 33900) { | 256 } else if (subrs_index.count < 33900) { |
309 bias = 1131; | 257 bias = 1131; |
310 } | 258 } |
311 subr_number += bias; | 259 subr_number += bias; |
312 | 260 |
313 // Sanity checks of |subr_number|. | 261 // Sanity checks of |subr_number|. |
314 if (subr_number < 0) { | 262 if (subr_number < 0) { |
315 return OTS_FAILURE(); | 263 return OTS_FAILURE(); |
316 } | 264 } |
317 if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number)) { | 265 if (subr_number >= kMaxSubrsCount) { |
| 266 return OTS_FAILURE(); |
| 267 } |
| 268 if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) { |
318 return OTS_FAILURE(); // The number is out-of-bounds. | 269 return OTS_FAILURE(); // The number is out-of-bounds. |
319 } | 270 } |
320 | 271 |
321 // Prepare ots::Buffer where we're going to jump. | 272 // Prepare ots::Buffer where we're going to jump. |
322 const size_t length = | 273 const size_t length = |
323 subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number]; | 274 subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number]; |
324 if (length > kMaxCharStringLength) { | 275 if (length > kMaxCharStringLength) { |
325 return OTS_FAILURE(); | 276 return OTS_FAILURE(); |
326 } | 277 } |
327 const size_t offset = subrs_index.offsets[subr_number]; | 278 const size_t offset = subrs_index.offsets[subr_number]; |
328 cff_table->set_offset(offset); | 279 cff_table->set_offset(offset); |
329 if (!cff_table->Skip(length)) { | 280 if (!cff_table->Skip(length)) { |
330 return OTS_FAILURE(); | 281 return OTS_FAILURE(); |
331 } | 282 } |
332 ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length); | 283 ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length); |
333 | 284 |
334 return ExecuteType2CharString(call_depth + 1, | 285 return ExecuteType2CharString(call_depth + 1, |
335 global_subrs_index, | 286 global_subrs_index, |
336 local_subrs_index, | 287 local_subrs_index, |
337 cff_table, | 288 cff_table, |
338 &char_string_to_jump, | 289 &char_string_to_jump, |
339 argument_stack, | 290 argument_stack, |
340 out_found_endchar, | 291 out_found_endchar, |
341 in_out_found_width, | 292 in_out_found_width, |
342 in_out_num_stems); | 293 in_out_num_stems); |
343 } | 294 } |
344 | 295 |
345 case kReturn: | 296 case ots::kReturn: |
346 return true; | 297 return true; |
347 | 298 |
348 case kEndChar: | 299 case ots::kEndChar: |
349 *out_found_endchar = true; | 300 *out_found_endchar = true; |
350 *in_out_found_width = true; // just in case. | 301 *in_out_found_width = true; // just in case. |
351 return true; | 302 return true; |
352 | 303 |
353 case kHStem: | 304 case ots::kHStem: |
354 case kVStem: | 305 case ots::kVStem: |
355 case kHStemHm: | 306 case ots::kHStemHm: |
356 case kVStemHm: { | 307 case ots::kVStemHm: { |
357 bool successful = false; | 308 bool successful = false; |
358 if (stack_size < 2) { | 309 if (stack_size < 2) { |
359 return OTS_FAILURE(); | 310 return OTS_FAILURE(); |
360 } | 311 } |
361 if ((stack_size % 2) == 0) { | 312 if ((stack_size % 2) == 0) { |
362 successful = true; | 313 successful = true; |
363 } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) { | 314 } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) { |
364 // The -1 is for "width" argument. For details, see Adobe Technical Note | 315 // The -1 is for "width" argument. For details, see Adobe Technical Note |
365 // #5177, page 16, note 4. | 316 // #5177, page 16, note 4. |
366 successful = true; | 317 successful = true; |
367 } | 318 } |
368 (*in_out_num_stems) += (stack_size / 2); | 319 (*in_out_num_stems) += (stack_size / 2); |
369 if ((*in_out_num_stems) > kMaxNumberOfStemHints) { | 320 if ((*in_out_num_stems) > kMaxNumberOfStemHints) { |
370 return OTS_FAILURE(); | 321 return OTS_FAILURE(); |
371 } | 322 } |
372 while (!argument_stack->empty()) | 323 while (!argument_stack->empty()) |
373 argument_stack->pop(); | 324 argument_stack->pop(); |
374 *in_out_found_width = true; // always set true since "w" might be 0 byte. | 325 *in_out_found_width = true; // always set true since "w" might be 0 byte. |
375 return successful ? true : OTS_FAILURE(); | 326 return successful ? true : OTS_FAILURE(); |
376 } | 327 } |
377 | 328 |
378 case kRMoveTo: { | 329 case ots::kRMoveTo: { |
379 bool successful = false; | 330 bool successful = false; |
380 if (stack_size == 2) { | 331 if (stack_size == 2) { |
381 successful = true; | 332 successful = true; |
382 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) { | 333 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) { |
383 successful = true; | 334 successful = true; |
384 } | 335 } |
385 while (!argument_stack->empty()) | 336 while (!argument_stack->empty()) |
386 argument_stack->pop(); | 337 argument_stack->pop(); |
387 *in_out_found_width = true; | 338 *in_out_found_width = true; |
388 return successful ? true : OTS_FAILURE(); | 339 return successful ? true : OTS_FAILURE(); |
389 } | 340 } |
390 | 341 |
391 case kVMoveTo: | 342 case ots::kVMoveTo: |
392 case kHMoveTo: { | 343 case ots::kHMoveTo: { |
393 bool successful = false; | 344 bool successful = false; |
394 if (stack_size == 1) { | 345 if (stack_size == 1) { |
395 successful = true; | 346 successful = true; |
396 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) { | 347 } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) { |
397 successful = true; | 348 successful = true; |
398 } | 349 } |
399 while (!argument_stack->empty()) | 350 while (!argument_stack->empty()) |
400 argument_stack->pop(); | 351 argument_stack->pop(); |
401 *in_out_found_width = true; | 352 *in_out_found_width = true; |
402 return successful ? true : OTS_FAILURE(); | 353 return successful ? true : OTS_FAILURE(); |
403 } | 354 } |
404 | 355 |
405 case kHintMask: | 356 case ots::kHintMask: |
406 case kCntrMask: { | 357 case ots::kCntrMask: { |
407 bool successful = false; | 358 bool successful = false; |
408 if (stack_size == 0) { | 359 if (stack_size == 0) { |
409 successful = true; | 360 successful = true; |
410 } else if ((!(*in_out_found_width)) && (stack_size == 1)) { | 361 } else if ((!(*in_out_found_width)) && (stack_size == 1)) { |
411 // A number for "width" is found. | 362 // A number for "width" is found. |
412 successful = true; | 363 successful = true; |
413 } else if ((!(*in_out_found_width)) || // in this case, any sizes are ok. | 364 } else if ((!(*in_out_found_width)) || // in this case, any sizes are ok. |
414 ((stack_size % 2) == 0)) { | 365 ((stack_size % 2) == 0)) { |
415 // The numbers are vstem definition. | 366 // The numbers are vstem definition. |
416 // See Adobe Technical Note #5177, page 24, hintmask. | 367 // See Adobe Technical Note #5177, page 24, hintmask. |
(...skipping 13 matching lines...) Expand all Loading... |
430 const size_t mask_bytes = (*in_out_num_stems + 7) / 8; | 381 const size_t mask_bytes = (*in_out_num_stems + 7) / 8; |
431 if (!char_string->Skip(mask_bytes)) { | 382 if (!char_string->Skip(mask_bytes)) { |
432 return OTS_FAILURE(); | 383 return OTS_FAILURE(); |
433 } | 384 } |
434 while (!argument_stack->empty()) | 385 while (!argument_stack->empty()) |
435 argument_stack->pop(); | 386 argument_stack->pop(); |
436 *in_out_found_width = true; | 387 *in_out_found_width = true; |
437 return true; | 388 return true; |
438 } | 389 } |
439 | 390 |
440 case kRLineTo: | 391 case ots::kRLineTo: |
441 if (!(*in_out_found_width)) { | 392 if (!(*in_out_found_width)) { |
442 // The first stack-clearing operator should be one of hstem, hstemhm, | 393 // The first stack-clearing operator should be one of hstem, hstemhm, |
443 // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or | 394 // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or |
444 // endchar. For details, see Adobe Technical Note #5177, page 16, note 4. | 395 // endchar. For details, see Adobe Technical Note #5177, page 16, note 4. |
445 return OTS_FAILURE(); | 396 return OTS_FAILURE(); |
446 } | 397 } |
447 if (stack_size < 2) { | 398 if (stack_size < 2) { |
448 return OTS_FAILURE(); | 399 return OTS_FAILURE(); |
449 } | 400 } |
450 if ((stack_size % 2) != 0) { | 401 if ((stack_size % 2) != 0) { |
451 return OTS_FAILURE(); | 402 return OTS_FAILURE(); |
452 } | 403 } |
453 while (!argument_stack->empty()) | 404 while (!argument_stack->empty()) |
454 argument_stack->pop(); | 405 argument_stack->pop(); |
455 return true; | 406 return true; |
456 | 407 |
457 case kHLineTo: | 408 case ots::kHLineTo: |
458 case kVLineTo: | 409 case ots::kVLineTo: |
459 if (!(*in_out_found_width)) { | 410 if (!(*in_out_found_width)) { |
460 return OTS_FAILURE(); | 411 return OTS_FAILURE(); |
461 } | 412 } |
462 if (stack_size < 1) { | 413 if (stack_size < 1) { |
463 return OTS_FAILURE(); | 414 return OTS_FAILURE(); |
464 } | 415 } |
465 while (!argument_stack->empty()) | 416 while (!argument_stack->empty()) |
466 argument_stack->pop(); | 417 argument_stack->pop(); |
467 return true; | 418 return true; |
468 | 419 |
469 case kRRCurveTo: | 420 case ots::kRRCurveTo: |
470 if (!(*in_out_found_width)) { | 421 if (!(*in_out_found_width)) { |
471 return OTS_FAILURE(); | 422 return OTS_FAILURE(); |
472 } | 423 } |
473 if (stack_size < 6) { | 424 if (stack_size < 6) { |
474 return OTS_FAILURE(); | 425 return OTS_FAILURE(); |
475 } | 426 } |
476 if ((stack_size % 6) != 0) { | 427 if ((stack_size % 6) != 0) { |
477 return OTS_FAILURE(); | 428 return OTS_FAILURE(); |
478 } | 429 } |
479 while (!argument_stack->empty()) | 430 while (!argument_stack->empty()) |
480 argument_stack->pop(); | 431 argument_stack->pop(); |
481 return true; | 432 return true; |
482 | 433 |
483 case kRCurveLine: | 434 case ots::kRCurveLine: |
484 if (!(*in_out_found_width)) { | 435 if (!(*in_out_found_width)) { |
485 return OTS_FAILURE(); | 436 return OTS_FAILURE(); |
486 } | 437 } |
487 if (stack_size < 8) { | 438 if (stack_size < 8) { |
488 return OTS_FAILURE(); | 439 return OTS_FAILURE(); |
489 } | 440 } |
490 if (((stack_size - 2) % 6) != 0) { | 441 if (((stack_size - 2) % 6) != 0) { |
491 return OTS_FAILURE(); | 442 return OTS_FAILURE(); |
492 } | 443 } |
493 while (!argument_stack->empty()) | 444 while (!argument_stack->empty()) |
494 argument_stack->pop(); | 445 argument_stack->pop(); |
495 return true; | 446 return true; |
496 | 447 |
497 case kRLineCurve: | 448 case ots::kRLineCurve: |
498 if (!(*in_out_found_width)) { | 449 if (!(*in_out_found_width)) { |
499 return OTS_FAILURE(); | 450 return OTS_FAILURE(); |
500 } | 451 } |
501 if (stack_size < 8) { | 452 if (stack_size < 8) { |
502 return OTS_FAILURE(); | 453 return OTS_FAILURE(); |
503 } | 454 } |
504 if (((stack_size - 6) % 2) != 0) { | 455 if (((stack_size - 6) % 2) != 0) { |
505 return OTS_FAILURE(); | 456 return OTS_FAILURE(); |
506 } | 457 } |
507 while (!argument_stack->empty()) | 458 while (!argument_stack->empty()) |
508 argument_stack->pop(); | 459 argument_stack->pop(); |
509 return true; | 460 return true; |
510 | 461 |
511 case kVVCurveTo: | 462 case ots::kVVCurveTo: |
512 if (!(*in_out_found_width)) { | 463 if (!(*in_out_found_width)) { |
513 return OTS_FAILURE(); | 464 return OTS_FAILURE(); |
514 } | 465 } |
515 if (stack_size < 4) { | 466 if (stack_size < 4) { |
516 return OTS_FAILURE(); | 467 return OTS_FAILURE(); |
517 } | 468 } |
518 if (((stack_size % 4) != 0) && | 469 if (((stack_size % 4) != 0) && |
519 (((stack_size - 1) % 4) != 0)) { | 470 (((stack_size - 1) % 4) != 0)) { |
520 return OTS_FAILURE(); | 471 return OTS_FAILURE(); |
521 } | 472 } |
522 while (!argument_stack->empty()) | 473 while (!argument_stack->empty()) |
523 argument_stack->pop(); | 474 argument_stack->pop(); |
524 return true; | 475 return true; |
525 | 476 |
526 case kHHCurveTo: { | 477 case ots::kHHCurveTo: { |
527 bool successful = false; | 478 bool successful = false; |
528 if (!(*in_out_found_width)) { | 479 if (!(*in_out_found_width)) { |
529 return OTS_FAILURE(); | 480 return OTS_FAILURE(); |
530 } | 481 } |
531 if (stack_size < 4) { | 482 if (stack_size < 4) { |
532 return OTS_FAILURE(); | 483 return OTS_FAILURE(); |
533 } | 484 } |
534 if ((stack_size % 4) == 0) { | 485 if ((stack_size % 4) == 0) { |
535 // {dxa dxb dyb dxc}+ | 486 // {dxa dxb dyb dxc}+ |
536 successful = true; | 487 successful = true; |
537 } else if (((stack_size - 1) % 4) == 0) { | 488 } else if (((stack_size - 1) % 4) == 0) { |
538 // dy1? {dxa dxb dyb dxc}+ | 489 // dy1? {dxa dxb dyb dxc}+ |
539 successful = true; | 490 successful = true; |
540 } | 491 } |
541 while (!argument_stack->empty()) | 492 while (!argument_stack->empty()) |
542 argument_stack->pop(); | 493 argument_stack->pop(); |
543 return successful ? true : OTS_FAILURE(); | 494 return successful ? true : OTS_FAILURE(); |
544 } | 495 } |
545 | 496 |
546 case kVHCurveTo: | 497 case ots::kVHCurveTo: |
547 case kHVCurveTo: { | 498 case ots::kHVCurveTo: { |
548 bool successful = false; | 499 bool successful = false; |
549 if (!(*in_out_found_width)) { | 500 if (!(*in_out_found_width)) { |
550 return OTS_FAILURE(); | 501 return OTS_FAILURE(); |
551 } | 502 } |
552 if (stack_size < 4) { | 503 if (stack_size < 4) { |
553 return OTS_FAILURE(); | 504 return OTS_FAILURE(); |
554 } | 505 } |
555 if (((stack_size - 4) % 8) == 0) { | 506 if (((stack_size - 4) % 8) == 0) { |
556 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* | 507 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* |
557 successful = true; | 508 successful = true; |
558 } else if ((stack_size >= 5) && | 509 } else if ((stack_size >= 5) && |
559 ((stack_size - 5) % 8) == 0) { | 510 ((stack_size - 5) % 8) == 0) { |
560 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf | 511 // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf |
561 successful = true; | 512 successful = true; |
562 } else if ((stack_size >= 8) && | 513 } else if ((stack_size >= 8) && |
563 ((stack_size - 8) % 8) == 0) { | 514 ((stack_size - 8) % 8) == 0) { |
564 // {dxa dxb dyb dyc dyd dxe dye dxf}+ | 515 // {dxa dxb dyb dyc dyd dxe dye dxf}+ |
565 successful = true; | 516 successful = true; |
566 } else if ((stack_size >= 9) && | 517 } else if ((stack_size >= 9) && |
567 ((stack_size - 9) % 8) == 0) { | 518 ((stack_size - 9) % 8) == 0) { |
568 // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? | 519 // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? |
569 successful = true; | 520 successful = true; |
570 } | 521 } |
571 while (!argument_stack->empty()) | 522 while (!argument_stack->empty()) |
572 argument_stack->pop(); | 523 argument_stack->pop(); |
573 return successful ? true : OTS_FAILURE(); | 524 return successful ? true : OTS_FAILURE(); |
574 } | 525 } |
575 | 526 |
576 case kAnd: | 527 case ots::kAnd: |
577 case kOr: | 528 case ots::kOr: |
578 case kEq: | 529 case ots::kEq: |
579 case kAdd: | 530 case ots::kAdd: |
580 case kSub: | 531 case ots::kSub: |
581 if (stack_size < 2) { | 532 if (stack_size < 2) { |
582 return OTS_FAILURE(); | 533 return OTS_FAILURE(); |
583 } | 534 } |
584 argument_stack->pop(); | 535 argument_stack->pop(); |
585 argument_stack->pop(); | 536 argument_stack->pop(); |
586 argument_stack->push(dummy_result); | 537 argument_stack->push(dummy_result); |
587 // TODO(yusukes): Implement this. We should push a real value for all | 538 // TODO(yusukes): Implement this. We should push a real value for all |
588 // arithmetic and conditional operations. | 539 // arithmetic and conditional operations. |
589 return true; | 540 return true; |
590 | 541 |
591 case kNot: | 542 case ots::kNot: |
592 case kAbs: | 543 case ots::kAbs: |
593 case kNeg: | 544 case ots::kNeg: |
594 if (stack_size < 1) { | 545 if (stack_size < 1) { |
595 return OTS_FAILURE(); | 546 return OTS_FAILURE(); |
596 } | 547 } |
597 argument_stack->pop(); | 548 argument_stack->pop(); |
598 argument_stack->push(dummy_result); | 549 argument_stack->push(dummy_result); |
599 // TODO(yusukes): Implement this. We should push a real value for all | 550 // TODO(yusukes): Implement this. We should push a real value for all |
600 // arithmetic and conditional operations. | 551 // arithmetic and conditional operations. |
601 return true; | 552 return true; |
602 | 553 |
603 case kDiv: | 554 case ots::kDiv: |
604 // TODO(yusukes): Should detect div-by-zero errors. | 555 // TODO(yusukes): Should detect div-by-zero errors. |
605 if (stack_size < 1) { | 556 if (stack_size < 2) { |
606 return OTS_FAILURE(); | 557 return OTS_FAILURE(); |
607 } | 558 } |
608 argument_stack->pop(); | 559 argument_stack->pop(); |
| 560 argument_stack->pop(); |
609 argument_stack->push(dummy_result); | 561 argument_stack->push(dummy_result); |
610 // TODO(yusukes): Implement this. We should push a real value for all | 562 // TODO(yusukes): Implement this. We should push a real value for all |
611 // arithmetic and conditional operations. | 563 // arithmetic and conditional operations. |
612 return true; | 564 return true; |
613 | 565 |
614 case kDrop: | 566 case ots::kDrop: |
615 if (stack_size < 1) { | 567 if (stack_size < 1) { |
616 return OTS_FAILURE(); | 568 return OTS_FAILURE(); |
617 } | 569 } |
618 argument_stack->pop(); | 570 argument_stack->pop(); |
619 return true; | 571 return true; |
620 | 572 |
621 case kPut: | 573 case ots::kPut: |
622 case kGet: | 574 case ots::kGet: |
623 case kIndex: | 575 case ots::kIndex: |
624 // For now, just call OTS_FAILURE since there is no way to check whether the | 576 // For now, just call OTS_FAILURE since there is no way to check whether the |
625 // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType | 577 // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType |
626 // fonts I have (except malicious ones!) use the operators. | 578 // fonts I have (except malicious ones!) use the operators. |
627 // TODO(yusukes): Implement them in a secure way. | 579 // TODO(yusukes): Implement them in a secure way. |
628 return OTS_FAILURE(); | 580 return OTS_FAILURE(); |
629 | 581 |
630 case kRoll: | 582 case ots::kRoll: |
631 // Likewise, just call OTS_FAILURE for kRoll since there is no way to check | 583 // Likewise, just call OTS_FAILURE for kRoll since there is no way to check |
632 // whether |N| is smaller than the current stack depth or not. | 584 // whether |N| is smaller than the current stack depth or not. |
633 // TODO(yusukes): Implement them in a secure way. | 585 // TODO(yusukes): Implement them in a secure way. |
634 return OTS_FAILURE(); | 586 return OTS_FAILURE(); |
635 | 587 |
636 case kRandom: | 588 case ots::kRandom: |
637 // For now, we don't handle the 'random' operator since the operator makes | 589 // For now, we don't handle the 'random' operator since the operator makes |
638 // it hard to analyze hinting code statically. | 590 // it hard to analyze hinting code statically. |
639 return OTS_FAILURE(); | 591 return OTS_FAILURE(); |
640 | 592 |
641 case kIfElse: | 593 case ots::kIfElse: |
642 if (stack_size < 4) { | 594 if (stack_size < 4) { |
643 return OTS_FAILURE(); | 595 return OTS_FAILURE(); |
644 } | 596 } |
645 argument_stack->pop(); | 597 argument_stack->pop(); |
646 argument_stack->pop(); | 598 argument_stack->pop(); |
647 argument_stack->pop(); | 599 argument_stack->pop(); |
648 argument_stack->pop(); | 600 argument_stack->pop(); |
649 argument_stack->push(dummy_result); | 601 argument_stack->push(dummy_result); |
650 // TODO(yusukes): Implement this. We should push a real value for all | 602 // TODO(yusukes): Implement this. We should push a real value for all |
651 // arithmetic and conditional operations. | 603 // arithmetic and conditional operations. |
652 return true; | 604 return true; |
653 | 605 |
654 case kMul: | 606 case ots::kMul: |
655 // TODO(yusukes): Should detect overflows. | 607 // TODO(yusukes): Should detect overflows. |
656 if (stack_size < 2) { | 608 if (stack_size < 2) { |
657 return OTS_FAILURE(); | 609 return OTS_FAILURE(); |
658 } | 610 } |
659 argument_stack->pop(); | 611 argument_stack->pop(); |
660 argument_stack->pop(); | 612 argument_stack->pop(); |
661 argument_stack->push(dummy_result); | 613 argument_stack->push(dummy_result); |
662 // TODO(yusukes): Implement this. We should push a real value for all | 614 // TODO(yusukes): Implement this. We should push a real value for all |
663 // arithmetic and conditional operations. | 615 // arithmetic and conditional operations. |
664 return true; | 616 return true; |
665 | 617 |
666 case kSqrt: | 618 case ots::kSqrt: |
667 // TODO(yusukes): Should check if the argument is negative. | 619 // TODO(yusukes): Should check if the argument is negative. |
668 if (stack_size < 1) { | 620 if (stack_size < 1) { |
669 return OTS_FAILURE(); | 621 return OTS_FAILURE(); |
670 } | 622 } |
671 argument_stack->pop(); | 623 argument_stack->pop(); |
672 argument_stack->push(dummy_result); | 624 argument_stack->push(dummy_result); |
673 // TODO(yusukes): Implement this. We should push a real value for all | 625 // TODO(yusukes): Implement this. We should push a real value for all |
674 // arithmetic and conditional operations. | 626 // arithmetic and conditional operations. |
675 return true; | 627 return true; |
676 | 628 |
677 case kDup: | 629 case ots::kDup: |
678 if (stack_size < 1) { | 630 if (stack_size < 1) { |
679 return OTS_FAILURE(); | 631 return OTS_FAILURE(); |
680 } | 632 } |
681 argument_stack->pop(); | 633 argument_stack->pop(); |
682 argument_stack->push(dummy_result); | 634 argument_stack->push(dummy_result); |
683 argument_stack->push(dummy_result); | 635 argument_stack->push(dummy_result); |
684 if (argument_stack->size() > kMaxArgumentStack) { | 636 if (argument_stack->size() > kMaxArgumentStack) { |
685 return OTS_FAILURE(); | 637 return OTS_FAILURE(); |
686 } | 638 } |
687 // TODO(yusukes): Implement this. We should push a real value for all | 639 // TODO(yusukes): Implement this. We should push a real value for all |
688 // arithmetic and conditional operations. | 640 // arithmetic and conditional operations. |
689 return true; | 641 return true; |
690 | 642 |
691 case kExch: | 643 case ots::kExch: |
692 if (stack_size < 2) { | 644 if (stack_size < 2) { |
693 return OTS_FAILURE(); | 645 return OTS_FAILURE(); |
694 } | 646 } |
695 argument_stack->pop(); | 647 argument_stack->pop(); |
696 argument_stack->pop(); | 648 argument_stack->pop(); |
697 argument_stack->push(dummy_result); | 649 argument_stack->push(dummy_result); |
698 argument_stack->push(dummy_result); | 650 argument_stack->push(dummy_result); |
699 // TODO(yusukes): Implement this. We should push a real value for all | 651 // TODO(yusukes): Implement this. We should push a real value for all |
700 // arithmetic and conditional operations. | 652 // arithmetic and conditional operations. |
701 return true; | 653 return true; |
702 | 654 |
703 case kHFlex: | 655 case ots::kHFlex: |
704 if (!(*in_out_found_width)) { | 656 if (!(*in_out_found_width)) { |
705 return OTS_FAILURE(); | 657 return OTS_FAILURE(); |
706 } | 658 } |
707 if (stack_size != 7) { | 659 if (stack_size != 7) { |
708 return OTS_FAILURE(); | 660 return OTS_FAILURE(); |
709 } | 661 } |
710 while (!argument_stack->empty()) | 662 while (!argument_stack->empty()) |
711 argument_stack->pop(); | 663 argument_stack->pop(); |
712 return true; | 664 return true; |
713 | 665 |
714 case kFlex: | 666 case ots::kFlex: |
715 if (!(*in_out_found_width)) { | 667 if (!(*in_out_found_width)) { |
716 return OTS_FAILURE(); | 668 return OTS_FAILURE(); |
717 } | 669 } |
718 if (stack_size != 13) { | 670 if (stack_size != 13) { |
719 return OTS_FAILURE(); | 671 return OTS_FAILURE(); |
720 } | 672 } |
721 while (!argument_stack->empty()) | 673 while (!argument_stack->empty()) |
722 argument_stack->pop(); | 674 argument_stack->pop(); |
723 return true; | 675 return true; |
724 | 676 |
725 case kHFlex1: | 677 case ots::kHFlex1: |
726 if (!(*in_out_found_width)) { | 678 if (!(*in_out_found_width)) { |
727 return OTS_FAILURE(); | 679 return OTS_FAILURE(); |
728 } | 680 } |
729 if (stack_size != 9) { | 681 if (stack_size != 9) { |
730 return OTS_FAILURE(); | 682 return OTS_FAILURE(); |
731 } | 683 } |
732 while (!argument_stack->empty()) | 684 while (!argument_stack->empty()) |
733 argument_stack->pop(); | 685 argument_stack->pop(); |
734 return true; | 686 return true; |
735 | 687 |
736 case kFlex1: | 688 case ots::kFlex1: |
737 if (!(*in_out_found_width)) { | 689 if (!(*in_out_found_width)) { |
738 return OTS_FAILURE(); | 690 return OTS_FAILURE(); |
739 } | 691 } |
740 if (stack_size != 11) { | 692 if (stack_size != 11) { |
741 return OTS_FAILURE(); | 693 return OTS_FAILURE(); |
742 } | 694 } |
743 while (!argument_stack->empty()) | 695 while (!argument_stack->empty()) |
744 argument_stack->pop(); | 696 argument_stack->pop(); |
745 return true; | 697 return true; |
746 } | 698 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
817 char_string, | 769 char_string, |
818 argument_stack, | 770 argument_stack, |
819 out_found_endchar, | 771 out_found_endchar, |
820 in_out_found_width, | 772 in_out_found_width, |
821 in_out_num_stems)) { | 773 in_out_num_stems)) { |
822 return OTS_FAILURE(); | 774 return OTS_FAILURE(); |
823 } | 775 } |
824 if (*out_found_endchar) { | 776 if (*out_found_endchar) { |
825 return true; | 777 return true; |
826 } | 778 } |
827 if (operator_or_operand == kReturn) { | 779 if (operator_or_operand == ots::kReturn) { |
828 return true; | 780 return true; |
829 } | 781 } |
830 } | 782 } |
831 | 783 |
832 // No endchar operator is found. | 784 // No endchar operator is found. |
833 return OTS_FAILURE(); | 785 return OTS_FAILURE(); |
834 } | 786 } |
835 | 787 |
836 // Selects a set of subroutings for |glyph_index| from |cff| and sets it on | 788 // Selects a set of subroutings for |glyph_index| from |cff| and sets it on |
837 // |out_local_subrs_to_use|. Returns true on success. | 789 // |out_local_subrs_to_use|. Returns true on success. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
920 std::stack<int32_t> argument_stack; | 872 std::stack<int32_t> argument_stack; |
921 bool found_endchar = false; | 873 bool found_endchar = false; |
922 bool found_width = false; | 874 bool found_width = false; |
923 size_t num_stems = 0; | 875 size_t num_stems = 0; |
924 if (!ExecuteType2CharString(0 /* initial call_depth is zero */, | 876 if (!ExecuteType2CharString(0 /* initial call_depth is zero */, |
925 global_subrs_index, *local_subrs_to_use, | 877 global_subrs_index, *local_subrs_to_use, |
926 cff_table, &char_string, &argument_stack, | 878 cff_table, &char_string, &argument_stack, |
927 &found_endchar, &found_width, &num_stems)) { | 879 &found_endchar, &found_width, &num_stems)) { |
928 return OTS_FAILURE(); | 880 return OTS_FAILURE(); |
929 } | 881 } |
| 882 if (!found_endchar) { |
| 883 return OTS_FAILURE(); |
| 884 } |
930 } | 885 } |
931 return true; | 886 return true; |
932 } | 887 } |
933 | 888 |
934 } // namespace ots | 889 } // namespace ots |
OLD | NEW |