1/* 2******************************************************************************* 3* 4* Copyright (C) 2001-2011, International Business Machines 5* Corporation and others. All Rights Reserved. 6* 7******************************************************************************* 8* file name: casetrn.cpp 9* encoding: US-ASCII 10* tab size: 8 (not used) 11* indentation:4 12* 13* created on: 2004sep03 14* created by: Markus W. Scherer 15* 16* Implementation class for lower-/upper-/title-casing transliterators. 17*/ 18 19#include "unicode/utypes.h" 20 21#if !UCONFIG_NO_TRANSLITERATION 22 23#include "unicode/uchar.h" 24#include "unicode/ustring.h" 25#include "unicode/utf.h" 26#include "unicode/utf16.h" 27#include "tolowtrn.h" 28#include "ucase.h" 29#include "cpputils.h" 30 31/* case context iterator using a Replaceable */ 32U_CFUNC UChar32 U_CALLCONV 33utrans_rep_caseContextIterator(void *context, int8_t dir) 34{ 35 U_NAMESPACE_USE 36 37 UCaseContext *csc=(UCaseContext *)context; 38 Replaceable *rep=(Replaceable *)csc->p; 39 UChar32 c; 40 41 if(dir<0) { 42 /* reset for backward iteration */ 43 csc->index=csc->cpStart; 44 csc->dir=dir; 45 } else if(dir>0) { 46 /* reset for forward iteration */ 47 csc->index=csc->cpLimit; 48 csc->dir=dir; 49 } else { 50 /* continue current iteration direction */ 51 dir=csc->dir; 52 } 53 54 // automatically adjust start and limit if the Replaceable disagrees 55 // with the original values 56 if(dir<0) { 57 if(csc->start<csc->index) { 58 c=rep->char32At(csc->index-1); 59 if(c<0) { 60 csc->start=csc->index; 61 } else { 62 csc->index-=U16_LENGTH(c); 63 return c; 64 } 65 } 66 } else { 67 // detect, and store in csc->b1, if we hit the limit 68 if(csc->index<csc->limit) { 69 c=rep->char32At(csc->index); 70 if(c<0) { 71 csc->limit=csc->index; 72 csc->b1=TRUE; 73 } else { 74 csc->index+=U16_LENGTH(c); 75 return c; 76 } 77 } else { 78 csc->b1=TRUE; 79 } 80 } 81 return U_SENTINEL; 82} 83 84U_NAMESPACE_BEGIN 85 86UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(CaseMapTransliterator) 87 88/** 89 * Constructs a transliterator. 90 */ 91CaseMapTransliterator::CaseMapTransliterator(const UnicodeString &id, UCaseMapFull *map) : 92 Transliterator(id, 0), 93 fCsp(ucase_getSingleton()), 94 fMap(map) 95{ 96 // TODO test incremental mode with context-sensitive text (e.g. greek sigma) 97 // TODO need to call setMaximumContextLength()?! 98} 99 100/** 101 * Destructor. 102 */ 103CaseMapTransliterator::~CaseMapTransliterator() { 104} 105 106/** 107 * Copy constructor. 108 */ 109CaseMapTransliterator::CaseMapTransliterator(const CaseMapTransliterator& o) : 110 Transliterator(o), 111 fCsp(o.fCsp), fMap(o.fMap) 112{ 113} 114 115/** 116 * Assignment operator. 117 */ 118/*CaseMapTransliterator& CaseMapTransliterator::operator=(const CaseMapTransliterator& o) { 119 Transliterator::operator=(o); 120 fCsp = o.fCsp; 121 fMap = o.fMap; 122 return *this; 123}*/ 124 125/** 126 * Transliterator API. 127 */ 128/*Transliterator* CaseMapTransliterator::clone(void) const { 129 return new CaseMapTransliterator(*this); 130}*/ 131 132/** 133 * Implements {@link Transliterator#handleTransliterate}. 134 */ 135void CaseMapTransliterator::handleTransliterate(Replaceable& text, 136 UTransPosition& offsets, 137 UBool isIncremental) const 138{ 139 if (offsets.start >= offsets.limit) { 140 return; 141 } 142 143 UCaseContext csc; 144 uprv_memset(&csc, 0, sizeof(csc)); 145 csc.p = &text; 146 csc.start = offsets.contextStart; 147 csc.limit = offsets.contextLimit; 148 149 UnicodeString tmp; 150 const UChar *s; 151 UChar32 c; 152 int32_t textPos, delta, result, locCache=0; 153 154 for(textPos=offsets.start; textPos<offsets.limit;) { 155 csc.cpStart=textPos; 156 c=text.char32At(textPos); 157 csc.cpLimit=textPos+=U16_LENGTH(c); 158 159 result=fMap(fCsp, c, utrans_rep_caseContextIterator, &csc, &s, "", &locCache); 160 161 if(csc.b1 && isIncremental) { 162 // fMap() tried to look beyond the context limit 163 // wait for more input 164 offsets.start=csc.cpStart; 165 return; 166 } 167 168 if(result>=0) { 169 // replace the current code point with its full case mapping result 170 // see UCASE_MAX_STRING_LENGTH 171 if(result<=UCASE_MAX_STRING_LENGTH) { 172 // string s[result] 173 tmp.setTo(FALSE, s, result); 174 delta=result-U16_LENGTH(c); 175 } else { 176 // single code point 177 tmp.setTo(result); 178 delta=tmp.length()-U16_LENGTH(c); 179 } 180 text.handleReplaceBetween(csc.cpStart, textPos, tmp); 181 if(delta!=0) { 182 textPos+=delta; 183 csc.limit=offsets.contextLimit+=delta; 184 offsets.limit+=delta; 185 } 186 } 187 } 188 offsets.start=textPos; 189} 190 191U_NAMESPACE_END 192 193#endif /* #if !UCONFIG_NO_TRANSLITERATION */ 194