001: /*
002: *******************************************************************************
003: * Copyright (C) 1996-2005, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *******************************************************************************
006: */
007: package com.ibm.icu.text;
008:
009: import java.io.IOException;
010:
011: import com.ibm.icu.impl.UCaseProps;
012:
013: import com.ibm.icu.util.ULocale;
014:
015: import com.ibm.icu.text.ReplaceableContextIterator;
016:
017: /**
018: * A transliterator that performs locale-sensitive toLower()
019: * case mapping.
020: */
021: class LowercaseTransliterator extends Transliterator {
022:
023: /**
024: * Package accessible ID.
025: */
026: static final String _ID = "Any-Lower";
027:
028: // TODO: Add variants for tr, az, lt, default = default locale
029:
030: /**
031: * System registration hook.
032: */
033: static void register() {
034: Transliterator.registerFactory(_ID,
035: new Transliterator.Factory() {
036: public Transliterator getInstance(String ID) {
037: return new LowercaseTransliterator(ULocale.US);
038: }
039: });
040:
041: Transliterator.registerSpecialInverse("Lower", "Upper", true);
042: }
043:
044: private ULocale locale;
045:
046: private UCaseProps csp;
047: private ReplaceableContextIterator iter;
048: private StringBuffer result;
049: private int[] locCache;
050:
051: /**
052: * Constructs a transliterator.
053: */
054:
055: public LowercaseTransliterator(ULocale loc) {
056: super (_ID, null);
057: locale = loc;
058: try {
059: csp = UCaseProps.getSingleton();
060: } catch (IOException e) {
061: csp = null;
062: }
063: iter = new ReplaceableContextIterator();
064: result = new StringBuffer();
065: int[] locCache = new int[1];
066: locCache[0] = 0;
067: }
068:
069: /**
070: * Implements {@link Transliterator#handleTransliterate}.
071: */
072: protected void handleTransliterate(Replaceable text,
073: Position offsets, boolean isIncremental) {
074: if (csp == null) {
075: return;
076: }
077:
078: if (offsets.start >= offsets.limit) {
079: return;
080: }
081:
082: iter.setText(text);
083: result.setLength(0);
084: int c, delta;
085:
086: // Walk through original string
087: // If there is a case change, modify corresponding position in replaceable
088:
089: iter.setIndex(offsets.start);
090: iter.setLimit(offsets.limit);
091: iter.setContextLimits(offsets.contextStart,
092: offsets.contextLimit);
093: while ((c = iter.nextCaseMapCP()) >= 0) {
094: c = csp.toFullLower(c, iter, result, locale, locCache);
095:
096: if (iter.didReachLimit() && isIncremental) {
097: // the case mapping function tried to look beyond the context limit
098: // wait for more input
099: offsets.start = iter.getCaseMapCPStart();
100: return;
101: }
102:
103: /* decode the result */
104: if (c < 0) {
105: /* c mapped to itself, no change */
106: continue;
107: } else if (c <= UCaseProps.MAX_STRING_LENGTH) {
108: /* replace by the mapping string */
109: delta = iter.replace(result.toString());
110: result.setLength(0);
111: } else {
112: /* replace by single-code point mapping */
113: delta = iter.replace(UTF16.valueOf(c));
114: }
115:
116: if (delta != 0) {
117: offsets.limit += delta;
118: offsets.contextLimit += delta;
119: }
120: }
121: offsets.start = offsets.limit;
122: }
123: }
|