intl/icu/source/common/unorm_it.c

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 2003-2011, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 *******************************************************************************
michael@0 8 * file name: unorm_it.c
michael@0 9 * encoding: US-ASCII
michael@0 10 * tab size: 8 (not used)
michael@0 11 * indentation:4
michael@0 12 *
michael@0 13 * created on: 2003jan21
michael@0 14 * created by: Markus W. Scherer
michael@0 15 */
michael@0 16
michael@0 17 #include "unicode/utypes.h"
michael@0 18
michael@0 19 #if !UCONFIG_NO_COLLATION && !UCONFIG_NO_NORMALIZATION
michael@0 20
michael@0 21 #include "unicode/uiter.h"
michael@0 22 #include "unicode/unorm.h"
michael@0 23 #include "unicode/utf.h"
michael@0 24 #include "unorm_it.h"
michael@0 25 #include "cmemory.h"
michael@0 26
michael@0 27 /* UNormIterator ------------------------------------------------------------ */
michael@0 28
michael@0 29 enum {
michael@0 30 INITIAL_CAPACITY=100
michael@0 31 };
michael@0 32
michael@0 33 struct UNormIterator {
michael@0 34 UCharIterator api;
michael@0 35 UCharIterator *iter;
michael@0 36
michael@0 37 /*
michael@0 38 * chars and states either use the static buffers
michael@0 39 * or are allocated in the same memory block
michael@0 40 *
michael@0 41 * They are parallel arrays with states[] holding the getState() values
michael@0 42 * from normalization boundaries, and UITER_NO_STATE in between.
michael@0 43 */
michael@0 44 UChar *chars;
michael@0 45 uint32_t *states;
michael@0 46
michael@0 47 /*
michael@0 48 * api.start: first valid character & state in the arrays
michael@0 49 * api.index: current position
michael@0 50 * api.limit: one past the last valid character in chars[], but states[limit] is valid
michael@0 51 * capacity: length of allocated arrays
michael@0 52 */
michael@0 53 int32_t capacity;
michael@0 54
michael@0 55 /* the current iter->getState(), saved to avoid unnecessary setState() calls; may not correspond to api->index! */
michael@0 56 uint32_t state;
michael@0 57
michael@0 58 /* there are UChars available before start or after limit? */
michael@0 59 UBool hasPrevious, hasNext, isStackAllocated;
michael@0 60
michael@0 61 UNormalizationMode mode;
michael@0 62
michael@0 63 UChar charsBuffer[INITIAL_CAPACITY];
michael@0 64 uint32_t statesBuffer[INITIAL_CAPACITY+1]; /* one more than charsBuffer[]! */
michael@0 65 };
michael@0 66
michael@0 67 static void
michael@0 68 initIndexes(UNormIterator *uni, UCharIterator *iter) {
michael@0 69 /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
michael@0 70 UCharIterator *api=&uni->api;
michael@0 71
michael@0 72 if(!iter->hasPrevious(iter)) {
michael@0 73 /* set indexes to the beginning of the arrays */
michael@0 74 api->start=api->index=api->limit=0;
michael@0 75 uni->hasPrevious=FALSE;
michael@0 76 uni->hasNext=iter->hasNext(iter);
michael@0 77 } else if(!iter->hasNext(iter)) {
michael@0 78 /* set indexes to the end of the arrays */
michael@0 79 api->start=api->index=api->limit=uni->capacity;
michael@0 80 uni->hasNext=FALSE;
michael@0 81 uni->hasPrevious=iter->hasPrevious(iter);
michael@0 82 } else {
michael@0 83 /* set indexes into the middle of the arrays */
michael@0 84 api->start=api->index=api->limit=uni->capacity/2;
michael@0 85 uni->hasPrevious=uni->hasNext=TRUE;
michael@0 86 }
michael@0 87 }
michael@0 88
michael@0 89 static UBool
michael@0 90 reallocArrays(UNormIterator *uni, int32_t capacity, UBool addAtStart) {
michael@0 91 /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
michael@0 92 UCharIterator *api=&uni->api;
michael@0 93
michael@0 94 uint32_t *states;
michael@0 95 UChar *chars;
michael@0 96 int32_t start, limit;
michael@0 97
michael@0 98 states=(uint32_t *)uprv_malloc((capacity+1)*4+capacity*2);
michael@0 99 if(states==NULL) {
michael@0 100 return FALSE;
michael@0 101 }
michael@0 102
michael@0 103 chars=(UChar *)(states+(capacity+1));
michael@0 104 uni->capacity=capacity;
michael@0 105
michael@0 106 start=api->start;
michael@0 107 limit=api->limit;
michael@0 108
michael@0 109 if(addAtStart) {
michael@0 110 /* copy old contents to the end of the new arrays */
michael@0 111 int32_t delta;
michael@0 112
michael@0 113 delta=capacity-uni->capacity;
michael@0 114 uprv_memcpy(states+delta+start, uni->states+start, (limit-start+1)*4);
michael@0 115 uprv_memcpy(chars+delta+start, uni->chars+start, (limit-start)*4);
michael@0 116
michael@0 117 api->start=start+delta;
michael@0 118 api->index+=delta;
michael@0 119 api->limit=limit+delta;
michael@0 120 } else {
michael@0 121 /* copy old contents to the beginning of the new arrays */
michael@0 122 uprv_memcpy(states+start, uni->states+start, (limit-start+1)*4);
michael@0 123 uprv_memcpy(chars+start, uni->chars+start, (limit-start)*4);
michael@0 124 }
michael@0 125
michael@0 126 uni->chars=chars;
michael@0 127 uni->states=states;
michael@0 128
michael@0 129 return TRUE;
michael@0 130 }
michael@0 131
michael@0 132 static void
michael@0 133 moveContentsTowardStart(UCharIterator *api, UChar chars[], uint32_t states[], int32_t delta) {
michael@0 134 /* move array contents up to make room */
michael@0 135 int32_t srcIndex, destIndex, limit;
michael@0 136
michael@0 137 limit=api->limit;
michael@0 138 srcIndex=delta;
michael@0 139 if(srcIndex>api->start) {
michael@0 140 /* look for a position in the arrays with a known state */
michael@0 141 while(srcIndex<limit && states[srcIndex]==UITER_NO_STATE) {
michael@0 142 ++srcIndex;
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 /* now actually move the array contents */
michael@0 147 api->start=destIndex=0;
michael@0 148 while(srcIndex<limit) {
michael@0 149 chars[destIndex]=chars[srcIndex];
michael@0 150 states[destIndex++]=states[srcIndex++];
michael@0 151 }
michael@0 152
michael@0 153 /* copy states[limit] as well! */
michael@0 154 states[destIndex]=states[srcIndex];
michael@0 155
michael@0 156 api->limit=destIndex;
michael@0 157 }
michael@0 158
michael@0 159 static void
michael@0 160 moveContentsTowardEnd(UCharIterator *api, UChar chars[], uint32_t states[], int32_t delta) {
michael@0 161 /* move array contents up to make room */
michael@0 162 int32_t srcIndex, destIndex, start;
michael@0 163
michael@0 164 start=api->start;
michael@0 165 destIndex=((UNormIterator *)api)->capacity;
michael@0 166 srcIndex=destIndex-delta;
michael@0 167 if(srcIndex<api->limit) {
michael@0 168 /* look for a position in the arrays with a known state */
michael@0 169 while(srcIndex>start && states[srcIndex]==UITER_NO_STATE) {
michael@0 170 --srcIndex;
michael@0 171 }
michael@0 172 }
michael@0 173
michael@0 174 /* now actually move the array contents */
michael@0 175 api->limit=destIndex;
michael@0 176
michael@0 177 /* copy states[limit] as well! */
michael@0 178 states[destIndex]=states[srcIndex];
michael@0 179
michael@0 180 while(srcIndex>start) {
michael@0 181 chars[--destIndex]=chars[--srcIndex];
michael@0 182 states[destIndex]=states[srcIndex];
michael@0 183 }
michael@0 184
michael@0 185 api->start=destIndex;
michael@0 186 }
michael@0 187
michael@0 188 /* normalize forward from the limit, assume hasNext is true */
michael@0 189 static UBool
michael@0 190 readNext(UNormIterator *uni, UCharIterator *iter) {
michael@0 191 /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
michael@0 192 UCharIterator *api=&uni->api;
michael@0 193
michael@0 194 /* make capacity/4 room at the end of the arrays */
michael@0 195 int32_t limit, capacity, room;
michael@0 196 UErrorCode errorCode;
michael@0 197
michael@0 198 limit=api->limit;
michael@0 199 capacity=uni->capacity;
michael@0 200 room=capacity/4;
michael@0 201 if(room>(capacity-limit)) {
michael@0 202 /* move array contents to make room */
michael@0 203 moveContentsTowardStart(api, uni->chars, uni->states, room);
michael@0 204 api->index=limit=api->limit;
michael@0 205 uni->hasPrevious=TRUE;
michael@0 206 }
michael@0 207
michael@0 208 /* normalize starting from the limit position */
michael@0 209 errorCode=U_ZERO_ERROR;
michael@0 210 if(uni->state!=uni->states[limit]) {
michael@0 211 uiter_setState(iter, uni->states[limit], &errorCode);
michael@0 212 if(U_FAILURE(errorCode)) {
michael@0 213 uni->state=UITER_NO_STATE;
michael@0 214 uni->hasNext=FALSE;
michael@0 215 return FALSE;
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 room=unorm_next(iter, uni->chars+limit, capacity-limit, uni->mode, 0, TRUE, NULL, &errorCode);
michael@0 220 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
michael@0 221 if(room<=capacity) {
michael@0 222 /* empty and re-use the arrays */
michael@0 223 uni->states[0]=uni->states[limit];
michael@0 224 api->start=api->index=api->limit=limit=0;
michael@0 225 uni->hasPrevious=TRUE;
michael@0 226 } else {
michael@0 227 capacity+=room+100;
michael@0 228 if(!reallocArrays(uni, capacity, FALSE)) {
michael@0 229 uni->state=UITER_NO_STATE;
michael@0 230 uni->hasNext=FALSE;
michael@0 231 return FALSE;
michael@0 232 }
michael@0 233 limit=api->limit;
michael@0 234 }
michael@0 235
michael@0 236 errorCode=U_ZERO_ERROR;
michael@0 237 uiter_setState(iter, uni->states[limit], &errorCode);
michael@0 238 room=unorm_next(iter, uni->chars+limit, capacity-limit, uni->mode, 0, TRUE, NULL, &errorCode);
michael@0 239 }
michael@0 240 if(U_FAILURE(errorCode) || room==0) {
michael@0 241 uni->state=UITER_NO_STATE;
michael@0 242 uni->hasNext=FALSE;
michael@0 243 return FALSE;
michael@0 244 }
michael@0 245
michael@0 246 /* room>0 */
michael@0 247 ++limit; /* leave the known states[limit] alone */
michael@0 248 for(--room; room>0; --room) {
michael@0 249 /* set unknown states for all but the normalization boundaries */
michael@0 250 uni->states[limit++]=UITER_NO_STATE;
michael@0 251 }
michael@0 252 uni->states[limit]=uni->state=uiter_getState(iter);
michael@0 253 uni->hasNext=iter->hasNext(iter);
michael@0 254 api->limit=limit;
michael@0 255 return TRUE;
michael@0 256 }
michael@0 257
michael@0 258 /* normalize backward from the start, assume hasPrevious is true */
michael@0 259 static UBool
michael@0 260 readPrevious(UNormIterator *uni, UCharIterator *iter) {
michael@0 261 /* do not pass api so that the compiler knows it's an alias pointer to uni itself */
michael@0 262 UCharIterator *api=&uni->api;
michael@0 263
michael@0 264 /* make capacity/4 room at the start of the arrays */
michael@0 265 int32_t start, capacity, room;
michael@0 266 UErrorCode errorCode;
michael@0 267
michael@0 268 start=api->start;
michael@0 269 capacity=uni->capacity;
michael@0 270 room=capacity/4;
michael@0 271 if(room>start) {
michael@0 272 /* move array contents to make room */
michael@0 273 moveContentsTowardEnd(api, uni->chars, uni->states, room);
michael@0 274 api->index=start=api->start;
michael@0 275 uni->hasNext=TRUE;
michael@0 276 }
michael@0 277
michael@0 278 /* normalize ending at the start position */
michael@0 279 errorCode=U_ZERO_ERROR;
michael@0 280 if(uni->state!=uni->states[start]) {
michael@0 281 uiter_setState(iter, uni->states[start], &errorCode);
michael@0 282 if(U_FAILURE(errorCode)) {
michael@0 283 uni->state=UITER_NO_STATE;
michael@0 284 uni->hasPrevious=FALSE;
michael@0 285 return FALSE;
michael@0 286 }
michael@0 287 }
michael@0 288
michael@0 289 room=unorm_previous(iter, uni->chars, start, uni->mode, 0, TRUE, NULL, &errorCode);
michael@0 290 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
michael@0 291 if(room<=capacity) {
michael@0 292 /* empty and re-use the arrays */
michael@0 293 uni->states[capacity]=uni->states[start];
michael@0 294 api->start=api->index=api->limit=start=capacity;
michael@0 295 uni->hasNext=TRUE;
michael@0 296 } else {
michael@0 297 capacity+=room+100;
michael@0 298 if(!reallocArrays(uni, capacity, TRUE)) {
michael@0 299 uni->state=UITER_NO_STATE;
michael@0 300 uni->hasPrevious=FALSE;
michael@0 301 return FALSE;
michael@0 302 }
michael@0 303 start=api->start;
michael@0 304 }
michael@0 305
michael@0 306 errorCode=U_ZERO_ERROR;
michael@0 307 uiter_setState(iter, uni->states[start], &errorCode);
michael@0 308 room=unorm_previous(iter, uni->chars, start, uni->mode, 0, TRUE, NULL, &errorCode);
michael@0 309 }
michael@0 310 if(U_FAILURE(errorCode) || room==0) {
michael@0 311 uni->state=UITER_NO_STATE;
michael@0 312 uni->hasPrevious=FALSE;
michael@0 313 return FALSE;
michael@0 314 }
michael@0 315
michael@0 316 /* room>0 */
michael@0 317 do {
michael@0 318 /* copy the UChars from chars[0..room[ to chars[(start-room)..start[ */
michael@0 319 uni->chars[--start]=uni->chars[--room];
michael@0 320 /* set unknown states for all but the normalization boundaries */
michael@0 321 uni->states[start]=UITER_NO_STATE;
michael@0 322 } while(room>0);
michael@0 323 uni->states[start]=uni->state=uiter_getState(iter);
michael@0 324 uni->hasPrevious=iter->hasPrevious(iter);
michael@0 325 api->start=start;
michael@0 326 return TRUE;
michael@0 327 }
michael@0 328
michael@0 329 /* Iterator runtime API functions ------------------------------------------- */
michael@0 330
michael@0 331 static int32_t U_CALLCONV
michael@0 332 unormIteratorGetIndex(UCharIterator *api, UCharIteratorOrigin origin) {
michael@0 333 switch(origin) {
michael@0 334 case UITER_ZERO:
michael@0 335 case UITER_START:
michael@0 336 return 0;
michael@0 337 case UITER_CURRENT:
michael@0 338 case UITER_LIMIT:
michael@0 339 case UITER_LENGTH:
michael@0 340 return UITER_UNKNOWN_INDEX;
michael@0 341 default:
michael@0 342 /* not a valid origin */
michael@0 343 /* Should never get here! */
michael@0 344 return -1;
michael@0 345 }
michael@0 346 }
michael@0 347
michael@0 348 static int32_t U_CALLCONV
michael@0 349 unormIteratorMove(UCharIterator *api, int32_t delta, UCharIteratorOrigin origin) {
michael@0 350 UNormIterator *uni=(UNormIterator *)api;
michael@0 351 UCharIterator *iter=uni->iter;
michael@0 352 int32_t pos;
michael@0 353
michael@0 354 switch(origin) {
michael@0 355 case UITER_ZERO:
michael@0 356 case UITER_START:
michael@0 357 /* restart from the beginning */
michael@0 358 if(uni->hasPrevious) {
michael@0 359 iter->move(iter, 0, UITER_START);
michael@0 360 api->start=api->index=api->limit=0;
michael@0 361 uni->states[api->limit]=uni->state=uiter_getState(iter);
michael@0 362 uni->hasPrevious=FALSE;
michael@0 363 uni->hasNext=iter->hasNext(iter);
michael@0 364 } else {
michael@0 365 /* we already have the beginning of the normalized text */
michael@0 366 api->index=api->start;
michael@0 367 }
michael@0 368 break;
michael@0 369 case UITER_CURRENT:
michael@0 370 break;
michael@0 371 case UITER_LIMIT:
michael@0 372 case UITER_LENGTH:
michael@0 373 /* restart from the end */
michael@0 374 if(uni->hasNext) {
michael@0 375 iter->move(iter, 0, UITER_LIMIT);
michael@0 376 api->start=api->index=api->limit=uni->capacity;
michael@0 377 uni->states[api->limit]=uni->state=uiter_getState(iter);
michael@0 378 uni->hasPrevious=iter->hasPrevious(iter);
michael@0 379 uni->hasNext=FALSE;
michael@0 380 } else {
michael@0 381 /* we already have the end of the normalized text */
michael@0 382 api->index=api->limit;
michael@0 383 }
michael@0 384 break;
michael@0 385 default:
michael@0 386 return -1; /* Error */
michael@0 387 }
michael@0 388
michael@0 389 /* move relative to the current position by delta normalized UChars */
michael@0 390 if(delta==0) {
michael@0 391 /* nothing to do */
michael@0 392 } else if(delta>0) {
michael@0 393 /* go forward until the requested position is in the buffer */
michael@0 394 for(;;) {
michael@0 395 pos=api->index+delta; /* requested position */
michael@0 396 delta=pos-api->limit; /* remainder beyond buffered text */
michael@0 397 if(delta<=0) {
michael@0 398 api->index=pos; /* position reached */
michael@0 399 break;
michael@0 400 }
michael@0 401
michael@0 402 /* go to end of buffer and normalize further */
michael@0 403 api->index=api->limit;
michael@0 404 if(!uni->hasNext || !readNext(uni, iter)) {
michael@0 405 break; /* reached end of text */
michael@0 406 }
michael@0 407 }
michael@0 408 } else /* delta<0 */ {
michael@0 409 /* go backward until the requested position is in the buffer */
michael@0 410 for(;;) {
michael@0 411 pos=api->index+delta; /* requested position */
michael@0 412 delta=pos-api->start; /* remainder beyond buffered text */
michael@0 413 if(delta>=0) {
michael@0 414 api->index=pos; /* position reached */
michael@0 415 break;
michael@0 416 }
michael@0 417
michael@0 418 /* go to start of buffer and normalize further */
michael@0 419 api->index=api->start;
michael@0 420 if(!uni->hasPrevious || !readPrevious(uni, iter)) {
michael@0 421 break; /* reached start of text */
michael@0 422 }
michael@0 423 }
michael@0 424 }
michael@0 425
michael@0 426 if(api->index==api->start && !uni->hasPrevious) {
michael@0 427 return 0;
michael@0 428 } else {
michael@0 429 return UITER_UNKNOWN_INDEX;
michael@0 430 }
michael@0 431 }
michael@0 432
michael@0 433 static UBool U_CALLCONV
michael@0 434 unormIteratorHasNext(UCharIterator *api) {
michael@0 435 return api->index<api->limit || ((UNormIterator *)api)->hasNext;
michael@0 436 }
michael@0 437
michael@0 438 static UBool U_CALLCONV
michael@0 439 unormIteratorHasPrevious(UCharIterator *api) {
michael@0 440 return api->index>api->start || ((UNormIterator *)api)->hasPrevious;
michael@0 441 }
michael@0 442
michael@0 443 static UChar32 U_CALLCONV
michael@0 444 unormIteratorCurrent(UCharIterator *api) {
michael@0 445 UNormIterator *uni=(UNormIterator *)api;
michael@0 446
michael@0 447 if( api->index<api->limit ||
michael@0 448 (uni->hasNext && readNext(uni, uni->iter))
michael@0 449 ) {
michael@0 450 return uni->chars[api->index];
michael@0 451 } else {
michael@0 452 return U_SENTINEL;
michael@0 453 }
michael@0 454 }
michael@0 455
michael@0 456 static UChar32 U_CALLCONV
michael@0 457 unormIteratorNext(UCharIterator *api) {
michael@0 458 UNormIterator *uni=(UNormIterator *)api;
michael@0 459
michael@0 460 if( api->index<api->limit ||
michael@0 461 (uni->hasNext && readNext(uni, uni->iter))
michael@0 462 ) {
michael@0 463 return uni->chars[api->index++];
michael@0 464 } else {
michael@0 465 return U_SENTINEL;
michael@0 466 }
michael@0 467 }
michael@0 468
michael@0 469 static UChar32 U_CALLCONV
michael@0 470 unormIteratorPrevious(UCharIterator *api) {
michael@0 471 UNormIterator *uni=(UNormIterator *)api;
michael@0 472
michael@0 473 if( api->index>api->start ||
michael@0 474 (uni->hasPrevious && readPrevious(uni, uni->iter))
michael@0 475 ) {
michael@0 476 return uni->chars[--api->index];
michael@0 477 } else {
michael@0 478 return U_SENTINEL;
michael@0 479 }
michael@0 480 }
michael@0 481
michael@0 482 static uint32_t U_CALLCONV
michael@0 483 unormIteratorGetState(const UCharIterator *api) {
michael@0 484 /* not uni->state because that may not be at api->index */
michael@0 485 return ((UNormIterator *)api)->states[api->index];
michael@0 486 }
michael@0 487
michael@0 488 static void U_CALLCONV
michael@0 489 unormIteratorSetState(UCharIterator *api, uint32_t state, UErrorCode *pErrorCode) {
michael@0 490 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
michael@0 491 /* do nothing */
michael@0 492 } else if(api==NULL) {
michael@0 493 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
michael@0 494 } else if(state==UITER_NO_STATE) {
michael@0 495 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
michael@0 496 } else {
michael@0 497 UNormIterator *uni=(UNormIterator *)api;
michael@0 498 UCharIterator *iter=((UNormIterator *)api)->iter;
michael@0 499 if(state!=uni->state) {
michael@0 500 uni->state=state;
michael@0 501 uiter_setState(iter, state, pErrorCode);
michael@0 502 }
michael@0 503
michael@0 504 /*
michael@0 505 * Try shortcuts: If the requested state is in the array contents
michael@0 506 * then just set the index there.
michael@0 507 *
michael@0 508 * We assume that the state is unique per position!
michael@0 509 */
michael@0 510 if(state==uni->states[api->index]) {
michael@0 511 return;
michael@0 512 } else if(state==uni->states[api->limit]) {
michael@0 513 api->index=api->limit;
michael@0 514 return;
michael@0 515 } else {
michael@0 516 /* search for the index with this state */
michael@0 517 int32_t i;
michael@0 518
michael@0 519 for(i=api->start; i<api->limit; ++i) {
michael@0 520 if(state==uni->states[i]) {
michael@0 521 api->index=i;
michael@0 522 return;
michael@0 523 }
michael@0 524 }
michael@0 525 }
michael@0 526
michael@0 527 /* there is no array index for this state, reset for fresh contents */
michael@0 528 initIndexes((UNormIterator *)api, iter);
michael@0 529 uni->states[api->limit]=state;
michael@0 530 }
michael@0 531 }
michael@0 532
michael@0 533 static const UCharIterator unormIterator={
michael@0 534 NULL, 0, 0, 0, 0, 0,
michael@0 535 unormIteratorGetIndex,
michael@0 536 unormIteratorMove,
michael@0 537 unormIteratorHasNext,
michael@0 538 unormIteratorHasPrevious,
michael@0 539 unormIteratorCurrent,
michael@0 540 unormIteratorNext,
michael@0 541 unormIteratorPrevious,
michael@0 542 NULL,
michael@0 543 unormIteratorGetState,
michael@0 544 unormIteratorSetState
michael@0 545 };
michael@0 546
michael@0 547 /* Setup functions ---------------------------------------------------------- */
michael@0 548
michael@0 549 U_CAPI UNormIterator * U_EXPORT2
michael@0 550 unorm_openIter(void *stackMem, int32_t stackMemSize, UErrorCode *pErrorCode) {
michael@0 551 UNormIterator *uni;
michael@0 552
michael@0 553 /* argument checking */
michael@0 554 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
michael@0 555 return NULL;
michael@0 556 }
michael@0 557
michael@0 558 /* allocate */
michael@0 559 uni=NULL;
michael@0 560 if(stackMem!=NULL && stackMemSize>=sizeof(UNormIterator)) {
michael@0 561 if(U_ALIGNMENT_OFFSET(stackMem)==0) {
michael@0 562 /* already aligned */
michael@0 563 uni=(UNormIterator *)stackMem;
michael@0 564 } else {
michael@0 565 int32_t align=(int32_t)U_ALIGNMENT_OFFSET_UP(stackMem);
michael@0 566 if((stackMemSize-=align)>=(int32_t)sizeof(UNormIterator)) {
michael@0 567 /* needs alignment */
michael@0 568 uni=(UNormIterator *)((char *)stackMem+align);
michael@0 569 }
michael@0 570 }
michael@0 571 /* else does not fit */
michael@0 572 }
michael@0 573
michael@0 574 if(uni!=NULL) {
michael@0 575 uni->isStackAllocated=TRUE;
michael@0 576 } else {
michael@0 577 uni=(UNormIterator *)uprv_malloc(sizeof(UNormIterator));
michael@0 578 if(uni==NULL) {
michael@0 579 *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
michael@0 580 return NULL;
michael@0 581 }
michael@0 582 uni->isStackAllocated=FALSE;
michael@0 583 }
michael@0 584
michael@0 585 /*
michael@0 586 * initialize
michael@0 587 * do not memset because that would unnecessarily initialize the arrays
michael@0 588 */
michael@0 589 uni->iter=NULL;
michael@0 590 uni->chars=uni->charsBuffer;
michael@0 591 uni->states=uni->statesBuffer;
michael@0 592 uni->capacity=INITIAL_CAPACITY;
michael@0 593 uni->state=UITER_NO_STATE;
michael@0 594 uni->hasPrevious=uni->hasNext=FALSE;
michael@0 595 uni->mode=UNORM_NONE;
michael@0 596
michael@0 597 /* set a no-op iterator into the api */
michael@0 598 uiter_setString(&uni->api, NULL, 0);
michael@0 599 return uni;
michael@0 600 }
michael@0 601
michael@0 602 U_CAPI void U_EXPORT2
michael@0 603 unorm_closeIter(UNormIterator *uni) {
michael@0 604 if(uni!=NULL) {
michael@0 605 if(uni->states!=uni->statesBuffer) {
michael@0 606 /* chars and states are allocated in the same memory block */
michael@0 607 uprv_free(uni->states);
michael@0 608 }
michael@0 609 if(!uni->isStackAllocated) {
michael@0 610 uprv_free(uni);
michael@0 611 }
michael@0 612 }
michael@0 613 }
michael@0 614
michael@0 615 U_CAPI UCharIterator * U_EXPORT2
michael@0 616 unorm_setIter(UNormIterator *uni, UCharIterator *iter, UNormalizationMode mode, UErrorCode *pErrorCode) {
michael@0 617 /* argument checking */
michael@0 618 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
michael@0 619 return NULL;
michael@0 620 }
michael@0 621 if(uni==NULL) {
michael@0 622 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
michael@0 623 return NULL;
michael@0 624 }
michael@0 625 if( iter==NULL || iter->getState==NULL || iter->setState==NULL ||
michael@0 626 mode<UNORM_NONE || UNORM_MODE_COUNT<=mode
michael@0 627 ) {
michael@0 628 /* set a no-op iterator into the api */
michael@0 629 uiter_setString(&uni->api, NULL, 0);
michael@0 630 *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
michael@0 631 return NULL;
michael@0 632 }
michael@0 633
michael@0 634 /* set the iterator and initialize */
michael@0 635 uprv_memcpy(&uni->api, &unormIterator, sizeof(unormIterator));
michael@0 636
michael@0 637 uni->iter=iter;
michael@0 638 uni->mode=mode;
michael@0 639
michael@0 640 initIndexes(uni, iter);
michael@0 641 uni->states[uni->api.limit]=uni->state=uiter_getState(iter);
michael@0 642
michael@0 643 return &uni->api;
michael@0 644 }
michael@0 645
michael@0 646 #endif /* uconfig.h switches */

mercurial