1 /*
2 *******************************************************************************
3 *
4 * © 2016 and later: Unicode, Inc. and others.
5 * License & terms of use: http://www.unicode.org/copyright.html
6 *
7 *******************************************************************************
8 *******************************************************************************
9 *
10 * Copyright (C) 2003-2006, International Business Machines
11 * Corporation and others. All Rights Reserved.
12 *
13 *******************************************************************************
14 * file name: uit_len8.c
15 * encoding: UTF-8
16 * tab size: 8 (not used)
17 * indentation:4
18 *
19 * created on: 2003feb10
20 * created by: Markus W. Scherer
21 *
22 * This file contains the implementation of the "lenient UTF-8" UCharIterator
23 * as used in the uciter8 sample code.
24 * UTF-8-style macros are defined as well as the UCharIterator.
25 * The macros are incomplete (do not assemble code points from pairs of
26 * surrogates, see comment below)
27 * but sufficient for the iterator.
28 */
29
30 #include <string.h>
31 #include "unicode/utypes.h"
32 #include "unicode/uiter.h"
33
34 /* lenient UTF-8/CESU-8 macros ---------------------------------------------- */
35
36 /*
37 * This code leniently reads 8-bit Unicode strings,
38 * which could contain a mix of UTF-8 and CESU-8.
39 * More precisely:
40 * - supplementary code points may be encoded with dedicated 4-byte sequences
41 * (UTF-8 style)
42 * - supplementary code points may be encoded with
43 * pairs of 3-byte sequences, one for each surrogate of the UTF-16 form
44 * (CESU-8 style)
45 * - single surrogates are allowed, encoded with their "natural" 3-byte sequences
46 *
47 * Limitation:
48 * Right now, the macros do not attempt to assemble code points from pairs of
49 * separately encoded surrogates.
50 * This would not be sufficient for processing based on these macros,
51 * but it is sufficient for a UCharIterator that returns only UChars anyway.
52 *
53 * The code is copied and modified from utf_impl.c and utf8.h.
54 *
55 * Change 2006feb08: Much of the implementation code is replaced by calling
56 * the utf_impl.c functions which accept a new "strict" parameter value
57 * of -2 implementing exactly this leniency.
58 */
59
60 #define L8_NEXT(s, i, length, c) { \
61 (c)=(uint8_t)(s)[(i)++]; \
62 if((c)>=0x80) { \
63 if(U8_IS_LEAD(c)) { \
64 (c)=utf8_nextCharSafeBody((const uint8_t *)s, &(i), (int32_t)(length), c, -2); \
65 } else { \
66 (c)=U_SENTINEL; \
67 } \
68 } \
69 }
70
71 #define L8_PREV(s, start, i, c) { \
72 (c)=(uint8_t)(s)[--(i)]; \
73 if((c)>=0x80) { \
74 if((c)<=0xbf) { \
75 (c)=utf8_prevCharSafeBody((const uint8_t *)s, start, &(i), c, -2); \
76 } else { \
77 (c)=U_SENTINEL; \
78 } \
79 } \
80 }
81
82 /* lenient-8 UCharIterator -------------------------------------------------- */
83
84 /*
85 * This is a copy of the UTF-8 UCharIterator in uiter.cpp,
86 * except that it uses the lenient-8-bit-Unicode macros above.
87 */
88
89 /*
90 * Minimal implementation:
91 * Maintain a single-UChar buffer for an additional surrogate.
92 * The caller must not modify start and limit because they are used internally.
93 *
94 * Use UCharIterator fields as follows:
95 * context pointer to UTF-8 string
96 * length UTF-16 length of the string; -1 until lazy evaluation
97 * start current UTF-8 index
98 * index current UTF-16 index; may be -1="unknown" after setState()
99 * limit UTF-8 length of the string
100 * reservedField supplementary code point
101 *
102 * Since UCharIterator delivers 16-bit code units, the iteration can be
103 * currently in the middle of the byte sequence for a supplementary code point.
104 * In this case, reservedField will contain that code point and start will
105 * point to after the corresponding byte sequence. The UTF-16 index will be
106 * one less than what it would otherwise be corresponding to the UTF-8 index.
107 * Otherwise, reservedField will be 0.
108 */
109
110 /*
111 * Possible optimization for NUL-terminated UTF-8 and UTF-16 strings:
112 * Add implementations that do not call strlen() for iteration but check for NUL.
113 */
114
115 static int32_t U_CALLCONV
lenient8IteratorGetIndex(UCharIterator * iter,UCharIteratorOrigin origin)116 lenient8IteratorGetIndex(UCharIterator *iter, UCharIteratorOrigin origin) {
117 switch(origin) {
118 case UITER_ZERO:
119 case UITER_START:
120 return 0;
121 case UITER_CURRENT:
122 if(iter->index<0) {
123 /* the current UTF-16 index is unknown after setState(), count from the beginning */
124 const uint8_t *s;
125 UChar32 c;
126 int32_t i, limit, index;
127
128 s=(const uint8_t *)iter->context;
129 i=index=0;
130 limit=iter->start; /* count up to the UTF-8 index */
131 while(i<limit) {
132 L8_NEXT(s, i, limit, c);
133 if(c<=0xffff) {
134 ++index;
135 } else {
136 index+=2;
137 }
138 }
139
140 iter->start=i; /* just in case setState() did not get us to a code point boundary */
141 if(i==iter->limit) {
142 iter->length=index; /* in case it was <0 or wrong */
143 }
144 if(iter->reservedField!=0) {
145 --index; /* we are in the middle of a supplementary code point */
146 }
147 iter->index=index;
148 }
149 return iter->index;
150 case UITER_LIMIT:
151 case UITER_LENGTH:
152 if(iter->length<0) {
153 const uint8_t *s;
154 UChar32 c;
155 int32_t i, limit, length;
156
157 s=(const uint8_t *)iter->context;
158 if(iter->index<0) {
159 /*
160 * the current UTF-16 index is unknown after setState(),
161 * we must first count from the beginning to here
162 */
163 i=length=0;
164 limit=iter->start;
165
166 /* count from the beginning to the current index */
167 while(i<limit) {
168 L8_NEXT(s, i, limit, c);
169 if(c<=0xffff) {
170 ++length;
171 } else {
172 length+=2;
173 }
174 }
175
176 /* assume i==limit==iter->start, set the UTF-16 index */
177 iter->start=i; /* just in case setState() did not get us to a code point boundary */
178 iter->index= iter->reservedField!=0 ? length-1 : length;
179 } else {
180 i=iter->start;
181 length=iter->index;
182 if(iter->reservedField!=0) {
183 ++length;
184 }
185 }
186
187 /* count from the current index to the end */
188 limit=iter->limit;
189 while(i<limit) {
190 L8_NEXT(s, i, limit, c);
191 if(c<=0xffff) {
192 ++length;
193 } else {
194 length+=2;
195 }
196 }
197 iter->length=length;
198 }
199 return iter->length;
200 default:
201 /* not a valid origin */
202 /* Should never get here! */
203 return -1;
204 }
205 }
206
207 static int32_t U_CALLCONV
lenient8IteratorMove(UCharIterator * iter,int32_t delta,UCharIteratorOrigin origin)208 lenient8IteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin) {
209 const uint8_t *s;
210 UChar32 c;
211 int32_t pos; /* requested UTF-16 index */
212 int32_t i; /* UTF-8 index */
213 UBool havePos;
214
215 /* calculate the requested UTF-16 index */
216 switch(origin) {
217 case UITER_ZERO:
218 case UITER_START:
219 pos=delta;
220 havePos=true;
221 /* iter->index<0 (unknown) is possible */
222 break;
223 case UITER_CURRENT:
224 if(iter->index>=0) {
225 pos=iter->index+delta;
226 havePos=true;
227 } else {
228 /* the current UTF-16 index is unknown after setState(), use only delta */
229 pos=0;
230 havePos=false;
231 }
232 break;
233 case UITER_LIMIT:
234 case UITER_LENGTH:
235 if(iter->length>=0) {
236 pos=iter->length+delta;
237 havePos=true;
238 } else {
239 /* pin to the end, avoid counting the length */
240 iter->index=-1;
241 iter->start=iter->limit;
242 iter->reservedField=0;
243 if(delta>=0) {
244 return UITER_UNKNOWN_INDEX;
245 } else {
246 /* the current UTF-16 index is unknown, use only delta */
247 pos=0;
248 havePos=false;
249 }
250 }
251 break;
252 default:
253 return -1; /* Error */
254 }
255
256 if(havePos) {
257 /* shortcuts: pinning to the edges of the string */
258 if(pos<=0) {
259 iter->index=iter->start=iter->reservedField=0;
260 return 0;
261 } else if(iter->length>=0 && pos>=iter->length) {
262 iter->index=iter->length;
263 iter->start=iter->limit;
264 iter->reservedField=0;
265 return iter->index;
266 }
267
268 /* minimize the number of L8_NEXT/PREV operations */
269 if(iter->index<0 || pos<iter->index/2) {
270 /* go forward from the start instead of backward from the current index */
271 iter->index=iter->start=iter->reservedField=0;
272 } else if(iter->length>=0 && (iter->length-pos)<(pos-iter->index)) {
273 /*
274 * if we have the UTF-16 index and length and the new position is
275 * closer to the end than the current index,
276 * then go backward from the end instead of forward from the current index
277 */
278 iter->index=iter->length;
279 iter->start=iter->limit;
280 iter->reservedField=0;
281 }
282
283 delta=pos-iter->index;
284 if(delta==0) {
285 return iter->index; /* nothing to do */
286 }
287 } else {
288 /* move relative to unknown UTF-16 index */
289 if(delta==0) {
290 return UITER_UNKNOWN_INDEX; /* nothing to do */
291 } else if(-delta>=iter->start) {
292 /* moving backwards by more UChars than there are UTF-8 bytes, pin to 0 */
293 iter->index=iter->start=iter->reservedField=0;
294 return 0;
295 } else if(delta>=(iter->limit-iter->start)) {
296 /* moving forward by more UChars than the remaining UTF-8 bytes, pin to the end */
297 iter->index=iter->length; /* may or may not be <0 (unknown) */
298 iter->start=iter->limit;
299 iter->reservedField=0;
300 return iter->index>=0 ? iter->index : UITER_UNKNOWN_INDEX;
301 }
302 }
303
304 /* delta!=0 */
305
306 /* move towards the requested position, pin to the edges of the string */
307 s=(const uint8_t *)iter->context;
308 pos=iter->index; /* could be <0 (unknown) */
309 i=iter->start;
310 if(delta>0) {
311 /* go forward */
312 int32_t limit=iter->limit;
313 if(iter->reservedField!=0) {
314 iter->reservedField=0;
315 ++pos;
316 --delta;
317 }
318 while(delta>0 && i<limit) {
319 L8_NEXT(s, i, limit, c);
320 if(c<0xffff) {
321 ++pos;
322 --delta;
323 } else if(delta>=2) {
324 pos+=2;
325 delta-=2;
326 } else /* delta==1 */ {
327 /* stop in the middle of a supplementary code point */
328 iter->reservedField=c;
329 ++pos;
330 break; /* delta=0; */
331 }
332 }
333 if(i==limit) {
334 if(iter->length<0 && iter->index>=0) {
335 iter->length= iter->reservedField==0 ? pos : pos+1;
336 } else if(iter->index<0 && iter->length>=0) {
337 iter->index= iter->reservedField==0 ? iter->length : iter->length-1;
338 }
339 }
340 } else /* delta<0 */ {
341 /* go backward */
342 if(iter->reservedField!=0) {
343 iter->reservedField=0;
344 i-=4; /* we stayed behind the supplementary code point; go before it now */
345 --pos;
346 ++delta;
347 }
348 while(delta<0 && i>0) {
349 L8_PREV(s, 0, i, c);
350 if(c<0xffff) {
351 --pos;
352 ++delta;
353 } else if(delta<=-2) {
354 pos-=2;
355 delta+=2;
356 } else /* delta==-1 */ {
357 /* stop in the middle of a supplementary code point */
358 i+=4; /* back to behind this supplementary code point for consistent state */
359 iter->reservedField=c;
360 --pos;
361 break; /* delta=0; */
362 }
363 }
364 }
365
366 iter->start=i;
367 if(iter->index>=0) {
368 return iter->index=pos;
369 } else {
370 /* we started with index<0 (unknown) so pos is bogus */
371 if(i<=1) {
372 return iter->index=i; /* reached the beginning */
373 } else {
374 /* we still don't know the UTF-16 index */
375 return UITER_UNKNOWN_INDEX;
376 }
377 }
378 }
379
380 static UBool U_CALLCONV
lenient8IteratorHasNext(UCharIterator * iter)381 lenient8IteratorHasNext(UCharIterator *iter) {
382 return iter->reservedField!=0 || iter->start<iter->limit;
383 }
384
385 static UBool U_CALLCONV
lenient8IteratorHasPrevious(UCharIterator * iter)386 lenient8IteratorHasPrevious(UCharIterator *iter) {
387 return iter->start>0;
388 }
389
390 static UChar32 U_CALLCONV
lenient8IteratorCurrent(UCharIterator * iter)391 lenient8IteratorCurrent(UCharIterator *iter) {
392 if(iter->reservedField!=0) {
393 return U16_TRAIL(iter->reservedField);
394 } else if(iter->start<iter->limit) {
395 const uint8_t *s=(const uint8_t *)iter->context;
396 UChar32 c;
397 int32_t i=iter->start;
398
399 L8_NEXT(s, i, iter->limit, c);
400 if(c<0) {
401 return 0xfffd;
402 } else if(c<=0xffff) {
403 return c;
404 } else {
405 return U16_LEAD(c);
406 }
407 } else {
408 return U_SENTINEL;
409 }
410 }
411
412 static UChar32 U_CALLCONV
lenient8IteratorNext(UCharIterator * iter)413 lenient8IteratorNext(UCharIterator *iter) {
414 int32_t index;
415
416 if(iter->reservedField!=0) {
417 UChar trail=U16_TRAIL(iter->reservedField);
418 iter->reservedField=0;
419 if((index=iter->index)>=0) {
420 iter->index=index+1;
421 }
422 return trail;
423 } else if(iter->start<iter->limit) {
424 const uint8_t *s=(const uint8_t *)iter->context;
425 UChar32 c;
426
427 L8_NEXT(s, iter->start, iter->limit, c);
428 if((index=iter->index)>=0) {
429 iter->index=++index;
430 if(iter->length<0 && iter->start==iter->limit) {
431 iter->length= c<=0xffff ? index : index+1;
432 }
433 } else if(iter->start==iter->limit && iter->length>=0) {
434 iter->index= c<=0xffff ? iter->length : iter->length-1;
435 }
436 if(c<0) {
437 return 0xfffd;
438 } else if(c<=0xffff) {
439 return c;
440 } else {
441 iter->reservedField=c;
442 return U16_LEAD(c);
443 }
444 } else {
445 return U_SENTINEL;
446 }
447 }
448
449 static UChar32 U_CALLCONV
lenient8IteratorPrevious(UCharIterator * iter)450 lenient8IteratorPrevious(UCharIterator *iter) {
451 int32_t index;
452
453 if(iter->reservedField!=0) {
454 UChar lead=U16_LEAD(iter->reservedField);
455 iter->reservedField=0;
456 iter->start-=4; /* we stayed behind the supplementary code point; go before it now */
457 if((index=iter->index)>0) {
458 iter->index=index-1;
459 }
460 return lead;
461 } else if(iter->start>0) {
462 const uint8_t *s=(const uint8_t *)iter->context;
463 UChar32 c;
464
465 L8_PREV(s, 0, iter->start, c);
466 if((index=iter->index)>0) {
467 iter->index=index-1;
468 } else if(iter->start<=1) {
469 iter->index= c<=0xffff ? iter->start : iter->start+1;
470 }
471 if(c<0) {
472 return 0xfffd;
473 } else if(c<=0xffff) {
474 return c;
475 } else {
476 iter->start+=4; /* back to behind this supplementary code point for consistent state */
477 iter->reservedField=c;
478 return U16_TRAIL(c);
479 }
480 } else {
481 return U_SENTINEL;
482 }
483 }
484
485 static uint32_t U_CALLCONV
lenient8IteratorGetState(const UCharIterator * iter)486 lenient8IteratorGetState(const UCharIterator *iter) {
487 uint32_t state=(uint32_t)(iter->start<<1);
488 if(iter->reservedField!=0) {
489 state|=1;
490 }
491 return state;
492 }
493
494 static void U_CALLCONV
lenient8IteratorSetState(UCharIterator * iter,uint32_t state,UErrorCode * pErrorCode)495 lenient8IteratorSetState(UCharIterator *iter, uint32_t state, UErrorCode *pErrorCode) {
496 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
497 /* do nothing */
498 } else if(iter==NULL) {
499 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
500 } else if(state==lenient8IteratorGetState(iter)) {
501 /* setting to the current state: no-op */
502 } else {
503 int32_t index=(int32_t)(state>>1); /* UTF-8 index */
504 state&=1; /* 1 if in surrogate pair, must be index>=4 */
505
506 if((state==0 ? index<0 : index<4) || iter->limit<index) {
507 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
508 } else {
509 iter->start=index; /* restore UTF-8 byte index */
510 if(index<=1) {
511 iter->index=index;
512 } else {
513 iter->index=-1; /* unknown UTF-16 index */
514 }
515 if(state==0) {
516 iter->reservedField=0;
517 } else {
518 /* verified index>=4 above */
519 UChar32 c;
520 L8_PREV((const uint8_t *)iter->context, 0, index, c);
521 if(c<=0xffff) {
522 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
523 } else {
524 iter->reservedField=c;
525 }
526 }
527 }
528 }
529 }
530
531 static const UCharIterator lenient8Iterator={
532 0, 0, 0, 0, 0, 0,
533 lenient8IteratorGetIndex,
534 lenient8IteratorMove,
535 lenient8IteratorHasNext,
536 lenient8IteratorHasPrevious,
537 lenient8IteratorCurrent,
538 lenient8IteratorNext,
539 lenient8IteratorPrevious,
540 NULL,
541 lenient8IteratorGetState,
542 lenient8IteratorSetState
543 };
544
545 U_CAPI void U_EXPORT2
uiter_setLenient8(UCharIterator * iter,const char * s,int32_t length)546 uiter_setLenient8(UCharIterator *iter, const char *s, int32_t length) {
547 if(iter!=0) {
548 if(s!=0 && length>=-1) {
549 *iter=lenient8Iterator;
550 iter->context=s;
551 if(length>=0) {
552 iter->limit=length;
553 } else {
554 iter->limit=(int32_t)strlen(s);
555 }
556 iter->length= iter->limit<=1 ? iter->limit : -1;
557 } else {
558 /* set no-op iterator */
559 uiter_setString(iter, NULL, 0);
560 }
561 }
562 }
563