// © 2016 and later: Unicode, Inc. and others.1// License & terms of use: http://www.unicode.org/copyright.html2/*3*******************************************************************************4*5* Copyright (C) 2001-2011, International Business Machines6* Corporation and others. All Rights Reserved.7*8*******************************************************************************9* file name: casetrn.cpp10* encoding: UTF-811* tab size: 8 (not used)12* indentation:413*14* created on: 2004sep0315* created by: Markus W. Scherer16*17* Implementation class for lower-/upper-/title-casing transliterators.18*/1920#include "unicode/utypes.h"2122#if !UCONFIG_NO_TRANSLITERATION2324#include "unicode/uchar.h"25#include "unicode/ustring.h"26#include "unicode/utf.h"27#include "unicode/utf16.h"28#include "tolowtrn.h"29#include "ucase.h"30#include "cpputils.h"3132/* case context iterator using a Replaceable */33U_CFUNC UChar32 U_CALLCONV34utrans_rep_caseContextIterator(void *context, int8_t dir)35{36U_NAMESPACE_USE3738UCaseContext *csc=(UCaseContext *)context;39Replaceable *rep=(Replaceable *)csc->p;40UChar32 c;4142if(dir<0) {43/* reset for backward iteration */44csc->index=csc->cpStart;45csc->dir=dir;46} else if(dir>0) {47/* reset for forward iteration */48csc->index=csc->cpLimit;49csc->dir=dir;50} else {51/* continue current iteration direction */52dir=csc->dir;53}5455// automatically adjust start and limit if the Replaceable disagrees56// with the original values57if(dir<0) {58if(csc->start<csc->index) {59c=rep->char32At(csc->index-1);60if(c<0) {61csc->start=csc->index;62} else {63csc->index-=U16_LENGTH(c);64return c;65}66}67} else {68// detect, and store in csc->b1, if we hit the limit69if(csc->index<csc->limit) {70c=rep->char32At(csc->index);71if(c<0) {72csc->limit=csc->index;73csc->b1=true;74} else {75csc->index+=U16_LENGTH(c);76return c;77}78} else {79csc->b1=true;80}81}82return U_SENTINEL;83}8485U_NAMESPACE_BEGIN8687UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(CaseMapTransliterator)8889/**90* Constructs a transliterator.91*/92CaseMapTransliterator::CaseMapTransliterator(const UnicodeString &id, UCaseMapFull *map) :93Transliterator(id, 0),94fMap(map)95{96// TODO test incremental mode with context-sensitive text (e.g. greek sigma)97// TODO need to call setMaximumContextLength()?!98}99100/**101* Destructor.102*/103CaseMapTransliterator::~CaseMapTransliterator() {104}105106/**107* Copy constructor.108*/109CaseMapTransliterator::CaseMapTransliterator(const CaseMapTransliterator& o) :110Transliterator(o),111fMap(o.fMap)112{113}114115/**116* Assignment operator.117*/118/*CaseMapTransliterator& CaseMapTransliterator::operator=(const CaseMapTransliterator& o) {119Transliterator::operator=(o);120fMap = o.fMap;121return *this;122}*/123124/**125* Transliterator API.126*/127/*CaseMapTransliterator* CaseMapTransliterator::clone() const {128return new CaseMapTransliterator(*this);129}*/130131/**132* Implements {@link Transliterator#handleTransliterate}.133*/134void CaseMapTransliterator::handleTransliterate(Replaceable& text,135UTransPosition& offsets,136UBool isIncremental) const137{138if (offsets.start >= offsets.limit) {139return;140}141142UCaseContext csc;143uprv_memset(&csc, 0, sizeof(csc));144csc.p = &text;145csc.start = offsets.contextStart;146csc.limit = offsets.contextLimit;147148UnicodeString tmp;149const UChar *s;150UChar32 c;151int32_t textPos, delta, result;152153for(textPos=offsets.start; textPos<offsets.limit;) {154csc.cpStart=textPos;155c=text.char32At(textPos);156csc.cpLimit=textPos+=U16_LENGTH(c);157158result=fMap(c, utrans_rep_caseContextIterator, &csc, &s, UCASE_LOC_ROOT);159160if(csc.b1 && isIncremental) {161// fMap() tried to look beyond the context limit162// wait for more input163offsets.start=csc.cpStart;164return;165}166167if(result>=0) {168// replace the current code point with its full case mapping result169// see UCASE_MAX_STRING_LENGTH170if(result<=UCASE_MAX_STRING_LENGTH) {171// string s[result]172tmp.setTo(false, s, result);173delta=result-U16_LENGTH(c);174} else {175// single code point176tmp.setTo(result);177delta=tmp.length()-U16_LENGTH(c);178}179text.handleReplaceBetween(csc.cpStart, textPos, tmp);180if(delta!=0) {181textPos+=delta;182csc.limit=offsets.contextLimit+=delta;183offsets.limit+=delta;184}185}186}187offsets.start=textPos;188}189190U_NAMESPACE_END191192#endif /* #if !UCONFIG_NO_TRANSLITERATION */193194195