michael@0: /* michael@0: ******************************************************************************* michael@0: * michael@0: * Copyright (C) 2001-2011, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ******************************************************************************* michael@0: * file name: casetrn.cpp michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:4 michael@0: * michael@0: * created on: 2004sep03 michael@0: * created by: Markus W. Scherer michael@0: * michael@0: * Implementation class for lower-/upper-/title-casing transliterators. michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_TRANSLITERATION michael@0: michael@0: #include "unicode/uchar.h" michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/utf.h" michael@0: #include "unicode/utf16.h" michael@0: #include "tolowtrn.h" michael@0: #include "ucase.h" michael@0: #include "cpputils.h" michael@0: michael@0: /* case context iterator using a Replaceable */ michael@0: U_CFUNC UChar32 U_CALLCONV michael@0: utrans_rep_caseContextIterator(void *context, int8_t dir) michael@0: { michael@0: U_NAMESPACE_USE michael@0: michael@0: UCaseContext *csc=(UCaseContext *)context; michael@0: Replaceable *rep=(Replaceable *)csc->p; michael@0: UChar32 c; michael@0: michael@0: if(dir<0) { michael@0: /* reset for backward iteration */ michael@0: csc->index=csc->cpStart; michael@0: csc->dir=dir; michael@0: } else if(dir>0) { michael@0: /* reset for forward iteration */ michael@0: csc->index=csc->cpLimit; michael@0: csc->dir=dir; michael@0: } else { michael@0: /* continue current iteration direction */ michael@0: dir=csc->dir; michael@0: } michael@0: michael@0: // automatically adjust start and limit if the Replaceable disagrees michael@0: // with the original values michael@0: if(dir<0) { michael@0: if(csc->startindex) { michael@0: c=rep->char32At(csc->index-1); michael@0: if(c<0) { michael@0: csc->start=csc->index; michael@0: } else { michael@0: csc->index-=U16_LENGTH(c); michael@0: return c; michael@0: } michael@0: } michael@0: } else { michael@0: // detect, and store in csc->b1, if we hit the limit michael@0: if(csc->indexlimit) { michael@0: c=rep->char32At(csc->index); michael@0: if(c<0) { michael@0: csc->limit=csc->index; michael@0: csc->b1=TRUE; michael@0: } else { michael@0: csc->index+=U16_LENGTH(c); michael@0: return c; michael@0: } michael@0: } else { michael@0: csc->b1=TRUE; michael@0: } michael@0: } michael@0: return U_SENTINEL; michael@0: } michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(CaseMapTransliterator) michael@0: michael@0: /** michael@0: * Constructs a transliterator. michael@0: */ michael@0: CaseMapTransliterator::CaseMapTransliterator(const UnicodeString &id, UCaseMapFull *map) : michael@0: Transliterator(id, 0), michael@0: fCsp(ucase_getSingleton()), michael@0: fMap(map) michael@0: { michael@0: // TODO test incremental mode with context-sensitive text (e.g. greek sigma) michael@0: // TODO need to call setMaximumContextLength()?! michael@0: } michael@0: michael@0: /** michael@0: * Destructor. michael@0: */ michael@0: CaseMapTransliterator::~CaseMapTransliterator() { michael@0: } michael@0: michael@0: /** michael@0: * Copy constructor. michael@0: */ michael@0: CaseMapTransliterator::CaseMapTransliterator(const CaseMapTransliterator& o) : michael@0: Transliterator(o), michael@0: fCsp(o.fCsp), fMap(o.fMap) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Assignment operator. michael@0: */ michael@0: /*CaseMapTransliterator& CaseMapTransliterator::operator=(const CaseMapTransliterator& o) { michael@0: Transliterator::operator=(o); michael@0: fCsp = o.fCsp; michael@0: fMap = o.fMap; michael@0: return *this; michael@0: }*/ michael@0: michael@0: /** michael@0: * Transliterator API. michael@0: */ michael@0: /*Transliterator* CaseMapTransliterator::clone(void) const { michael@0: return new CaseMapTransliterator(*this); michael@0: }*/ michael@0: michael@0: /** michael@0: * Implements {@link Transliterator#handleTransliterate}. michael@0: */ michael@0: void CaseMapTransliterator::handleTransliterate(Replaceable& text, michael@0: UTransPosition& offsets, michael@0: UBool isIncremental) const michael@0: { michael@0: if (offsets.start >= offsets.limit) { michael@0: return; michael@0: } michael@0: michael@0: UCaseContext csc; michael@0: uprv_memset(&csc, 0, sizeof(csc)); michael@0: csc.p = &text; michael@0: csc.start = offsets.contextStart; michael@0: csc.limit = offsets.contextLimit; michael@0: michael@0: UnicodeString tmp; michael@0: const UChar *s; michael@0: UChar32 c; michael@0: int32_t textPos, delta, result, locCache=0; michael@0: michael@0: for(textPos=offsets.start; textPos=0) { michael@0: // replace the current code point with its full case mapping result michael@0: // see UCASE_MAX_STRING_LENGTH michael@0: if(result<=UCASE_MAX_STRING_LENGTH) { michael@0: // string s[result] michael@0: tmp.setTo(FALSE, s, result); michael@0: delta=result-U16_LENGTH(c); michael@0: } else { michael@0: // single code point michael@0: tmp.setTo(result); michael@0: delta=tmp.length()-U16_LENGTH(c); michael@0: } michael@0: text.handleReplaceBetween(csc.cpStart, textPos, tmp); michael@0: if(delta!=0) { michael@0: textPos+=delta; michael@0: csc.limit=offsets.contextLimit+=delta; michael@0: offsets.limit+=delta; michael@0: } michael@0: } michael@0: } michael@0: offsets.start=textPos; michael@0: } michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif /* #if !UCONFIG_NO_TRANSLITERATION */