1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_l10ntools.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir 32*cdf0e10cSrcweir #include "wtratree.hxx" 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir 35*cdf0e10cSrcweir 36*cdf0e10cSrcweir /** @ATTENTION 37*cdf0e10cSrcweir For reasons of speed, class WordTransTree works with two simple 38*cdf0e10cSrcweir char arrays, sOutput and sInput, instead of secure containers or 39*cdf0e10cSrcweir streams. So be extremely careful, when changing this code!!! 40*cdf0e10cSrcweir **/ 41*cdf0e10cSrcweir 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir // NOT FULLY DECLARED SERVICES 45*cdf0e10cSrcweir #include <string.h> 46*cdf0e10cSrcweir #include <stdio.h> 47*cdf0e10cSrcweir #include <ctype.h> 48*cdf0e10cSrcweir #include "wtranode.hxx" 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir const BRANCH_T BR_END = 0; 52*cdf0e10cSrcweir const BRANCH_T BR_NONALPHA = 1; 53*cdf0e10cSrcweir const BRANCH_T BR_HOTKEY = 2; 54*cdf0e10cSrcweir const BRANCH_T BR_BACKSLASH = 3; 55*cdf0e10cSrcweir const BRANCH_T BR_ALPHABASE = 4; /// @ATTENTION All branches not valid for words must be smaller than this value! 56*cdf0e10cSrcweir const BRANCH_T BR_AE = 30; 57*cdf0e10cSrcweir const BRANCH_T BR_OE = 31; 58*cdf0e10cSrcweir const BRANCH_T BR_UE = 32; 59*cdf0e10cSrcweir const BRANCH_T BR_SZ = 33; 60*cdf0e10cSrcweir const BRANCH_T BR_MAX = 34; /// @ATTENTION Must be updated always! 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir const BRANCH_T BR_START = 0; 63*cdf0e10cSrcweir 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir 68*cdf0e10cSrcweir WordTransTree::WordTransTree(CharSet i_nWorkingCharSet) 69*cdf0e10cSrcweir : sInput(0), 70*cdf0e10cSrcweir nInputLength(0), 71*cdf0e10cSrcweir pInputEnd(0), 72*cdf0e10cSrcweir sOutput(0), 73*cdf0e10cSrcweir nOutputMaxLength(0), 74*cdf0e10cSrcweir dpParsingTreeTop(0), 75*cdf0e10cSrcweir pUnknownAlpha(0), 76*cdf0e10cSrcweir // cChar2Branch 77*cdf0e10cSrcweir c_AE(u_char('\xC4')), c_OE(u_char('\xD6')), c_UE(u_char('\xDC')), 78*cdf0e10cSrcweir c_ae(u_char('\xE4')), c_oe(u_char('\xF6')), c_ue(u_char('\xFC')), 79*cdf0e10cSrcweir pInputCurTokenStart(0), 80*cdf0e10cSrcweir pInputPosition(0), 81*cdf0e10cSrcweir pOutputPosition(0), 82*cdf0e10cSrcweir pCurParseNode(0), 83*cdf0e10cSrcweir eCurResult(OK), 84*cdf0e10cSrcweir cCurHotkey(0), 85*cdf0e10cSrcweir cCurHotkeySign(u_char('~')) 86*cdf0e10cSrcweir { 87*cdf0e10cSrcweir // Initialize parsing tree: 88*cdf0e10cSrcweir pUnknownAlpha = new WTT_Node(BR_ALPHABASE,0,0); // This will be deleted as part of the parsing tree. 89*cdf0e10cSrcweir for ( UINT8 i = BR_ALPHABASE; i < C_NR_OF_BRANCHES; i++) 90*cdf0e10cSrcweir { 91*cdf0e10cSrcweir pUnknownAlpha->SetBranch(i,pUnknownAlpha); 92*cdf0e10cSrcweir } // end for 93*cdf0e10cSrcweir 94*cdf0e10cSrcweir dpParsingTreeTop = new WTT_Node(BR_START,0,pUnknownAlpha); 95*cdf0e10cSrcweir 96*cdf0e10cSrcweir WTT_Node * dpNonAlpha = new WTT_Node(BR_NONALPHA,0,0); 97*cdf0e10cSrcweir 98*cdf0e10cSrcweir dpNonAlpha->SetBranch(BR_NONALPHA,dpNonAlpha); 99*cdf0e10cSrcweir dpParsingTreeTop->SetBranch(BR_NONALPHA,dpNonAlpha); 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir WTT_Node * dpBackslash = new WTT_Node(BR_BACKSLASH,dpNonAlpha,dpNonAlpha); 102*cdf0e10cSrcweir dpBackslash->SetBranch(BR_END,0); 103*cdf0e10cSrcweir 104*cdf0e10cSrcweir dpParsingTreeTop->SetBranch(BR_BACKSLASH,dpBackslash); 105*cdf0e10cSrcweir dpNonAlpha->SetBranch(BR_BACKSLASH,dpBackslash); 106*cdf0e10cSrcweir 107*cdf0e10cSrcweir 108*cdf0e10cSrcweir // Initialize character set: 109*cdf0e10cSrcweir SetCharSet(i_nWorkingCharSet); 110*cdf0e10cSrcweir 111*cdf0e10cSrcweir if (C_BR_ALPHABASE != BR_ALPHABASE || C_NR_OF_BRANCHES != BR_MAX) 112*cdf0e10cSrcweir { 113*cdf0e10cSrcweir fprintf(stderr, "Assertion failed: file %s line %d.", __FILE__, __LINE__); 114*cdf0e10cSrcweir exit(1); 115*cdf0e10cSrcweir } 116*cdf0e10cSrcweir } 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir void 119*cdf0e10cSrcweir WordTransTree::SetCharSet(CharSet i_nWorkingCharSet) 120*cdf0e10cSrcweir { 121*cdf0e10cSrcweir ByteString sConvert("\xC4\xD6\xDC\xE4\xF6\xFC\xDF"); 122*cdf0e10cSrcweir const u_char * pConvert = (const u_char * ) ( sConvert.Convert(RTL_TEXTENCODING_MS_1252, i_nWorkingCharSet).GetBuffer() ); 123*cdf0e10cSrcweir 124*cdf0e10cSrcweir INT16 i = 0; 125*cdf0e10cSrcweir for ( ; i < C_NR_OF_POSSIBLE_CHARS; ++i ) 126*cdf0e10cSrcweir { 127*cdf0e10cSrcweir cChar2Branch[i] = BR_NONALPHA; 128*cdf0e10cSrcweir } // end for 129*cdf0e10cSrcweir for ( i = 'a'; i <= 'z'; ++i ) 130*cdf0e10cSrcweir { 131*cdf0e10cSrcweir cChar2Branch[i] = BR_ALPHABASE + i - 'a'; 132*cdf0e10cSrcweir } // end for 133*cdf0e10cSrcweir for ( i = 'A'; i <= 'Z'; ++i ) 134*cdf0e10cSrcweir { 135*cdf0e10cSrcweir cChar2Branch[i] = BR_ALPHABASE + i - 'A'; 136*cdf0e10cSrcweir } // end for 137*cdf0e10cSrcweir cChar2Branch[pConvert[0]] = BR_AE; 138*cdf0e10cSrcweir cChar2Branch[pConvert[1]] = BR_OE; 139*cdf0e10cSrcweir cChar2Branch[pConvert[2]] = BR_UE; 140*cdf0e10cSrcweir cChar2Branch[pConvert[3]] = BR_AE; 141*cdf0e10cSrcweir cChar2Branch[pConvert[4]] = BR_OE; 142*cdf0e10cSrcweir cChar2Branch[pConvert[5]] = BR_UE; 143*cdf0e10cSrcweir cChar2Branch[pConvert[6]] = BR_SZ; 144*cdf0e10cSrcweir 145*cdf0e10cSrcweir cChar2Branch[u_char('~')] = BR_HOTKEY; 146*cdf0e10cSrcweir cChar2Branch[u_char('&')] = BR_HOTKEY; 147*cdf0e10cSrcweir 148*cdf0e10cSrcweir 149*cdf0e10cSrcweir c_AE = pConvert[0]; 150*cdf0e10cSrcweir c_OE = pConvert[1]; 151*cdf0e10cSrcweir c_UE = pConvert[2]; 152*cdf0e10cSrcweir c_ae = pConvert[3]; 153*cdf0e10cSrcweir c_oe = pConvert[4]; 154*cdf0e10cSrcweir c_ue = pConvert[5]; 155*cdf0e10cSrcweir } 156*cdf0e10cSrcweir 157*cdf0e10cSrcweir WordTransTree::~WordTransTree() 158*cdf0e10cSrcweir { 159*cdf0e10cSrcweir delete dpParsingTreeTop; 160*cdf0e10cSrcweir if (sOutput != 0) 161*cdf0e10cSrcweir delete [] sOutput; 162*cdf0e10cSrcweir } 163*cdf0e10cSrcweir 164*cdf0e10cSrcweir void 165*cdf0e10cSrcweir WordTransTree::AddWordPair( const ByteString & i_sOldString, 166*cdf0e10cSrcweir const ByteString & i_sReplaceString ) 167*cdf0e10cSrcweir { 168*cdf0e10cSrcweir if (i_sOldString.Len() == 0) 169*cdf0e10cSrcweir return; 170*cdf0e10cSrcweir 171*cdf0e10cSrcweir pCurParseNode = dpParsingTreeTop; 172*cdf0e10cSrcweir WTT_Node * pBranch = 0; 173*cdf0e10cSrcweir char cBranch = 0; 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir for ( constr pOld = i_sOldString.GetBuffer(); 176*cdf0e10cSrcweir *pOld != 0; 177*cdf0e10cSrcweir pOld++ ) 178*cdf0e10cSrcweir { 179*cdf0e10cSrcweir cBranch = CalculateBranch(*pOld); 180*cdf0e10cSrcweir pBranch = pCurParseNode->GetNextNode(cBranch); 181*cdf0e10cSrcweir if (pBranch == 0 || pBranch == pUnknownAlpha) 182*cdf0e10cSrcweir { 183*cdf0e10cSrcweir pBranch = new WTT_Node(cBranch,0,pUnknownAlpha); 184*cdf0e10cSrcweir pCurParseNode->SetBranch(cBranch,pBranch); 185*cdf0e10cSrcweir } 186*cdf0e10cSrcweir pCurParseNode = pBranch; 187*cdf0e10cSrcweir } // end for 188*cdf0e10cSrcweir pCurParseNode->SetAsTokenToReplace(i_sReplaceString); 189*cdf0e10cSrcweir } 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir void 192*cdf0e10cSrcweir WordTransTree::InitTransformation( const char * i_sInput, 193*cdf0e10cSrcweir UINT32 i_nInputLength, 194*cdf0e10cSrcweir UINT32 i_nOutputMaxLength ) 195*cdf0e10cSrcweir { 196*cdf0e10cSrcweir sInput = (const u_char *)i_sInput; 197*cdf0e10cSrcweir nInputLength = i_nInputLength; 198*cdf0e10cSrcweir pInputEnd = &sInput[i_nInputLength]; 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir pInputCurTokenStart = sInput; 201*cdf0e10cSrcweir pInputPosition = sInput; 202*cdf0e10cSrcweir 203*cdf0e10cSrcweir if (nOutputMaxLength < i_nOutputMaxLength) 204*cdf0e10cSrcweir { 205*cdf0e10cSrcweir if (sOutput != 0) 206*cdf0e10cSrcweir delete [] sOutput; 207*cdf0e10cSrcweir sOutput = new unsigned char[i_nOutputMaxLength]; 208*cdf0e10cSrcweir nOutputMaxLength = i_nOutputMaxLength; 209*cdf0e10cSrcweir } 210*cdf0e10cSrcweir pOutputPosition = sOutput; 211*cdf0e10cSrcweir } 212*cdf0e10cSrcweir 213*cdf0e10cSrcweir /** pInputCurTokenStart and CurParseNode are updated just when 214*cdf0e10cSrcweir starting this function. After its end they must not be changed 215*cdf0e10cSrcweir till this functon is called again. 216*cdf0e10cSrcweir Outside this function pInputPositon and pOutputPosition are both 217*cdf0e10cSrcweir on the first not transformed char in their respective array. 218*cdf0e10cSrcweir **/ 219*cdf0e10cSrcweir WordTransTree::E_Result 220*cdf0e10cSrcweir WordTransTree::TransformNextToken() 221*cdf0e10cSrcweir { 222*cdf0e10cSrcweir pInputCurTokenStart = pInputPosition; 223*cdf0e10cSrcweir pCurParseNode = dpParsingTreeTop; 224*cdf0e10cSrcweir cCurHotkey = 0; 225*cdf0e10cSrcweir eCurResult = OK; 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir WTT_Node * pBranch = 0; 228*cdf0e10cSrcweir UINT8 cBranch = 0; 229*cdf0e10cSrcweir 230*cdf0e10cSrcweir for ( pCurParseNode = dpParsingTreeTop; 231*cdf0e10cSrcweir pInputPosition != pInputEnd; 232*cdf0e10cSrcweir ++pInputPosition ) 233*cdf0e10cSrcweir { 234*cdf0e10cSrcweir cBranch = CalculateBranch(*pInputPosition); 235*cdf0e10cSrcweir pBranch = pCurParseNode->GetNextNode( cBranch ); 236*cdf0e10cSrcweir if (pBranch != 0) 237*cdf0e10cSrcweir { 238*cdf0e10cSrcweir pCurParseNode = pBranch; 239*cdf0e10cSrcweir } 240*cdf0e10cSrcweir else 241*cdf0e10cSrcweir { 242*cdf0e10cSrcweir if (cBranch == BR_HOTKEY) // current letter is '~' or '&'. 243*cdf0e10cSrcweir { 244*cdf0e10cSrcweir // Logic of the following. There are 9 possible cases - 245*cdf0e10cSrcweir // A = alphabetic letter, NA = non alphabetic, TB = token begin, 246*cdf0e10cSrcweir // Eot = end of text: 247*cdf0e10cSrcweir // 1. A~A set hotkey to following letter, continue 248*cdf0e10cSrcweir // 2. A~NA token end 249*cdf0e10cSrcweir // 3. A~Eot token end 250*cdf0e10cSrcweir // 4. NA~A token end 251*cdf0e10cSrcweir // 5. NA~NA continue 252*cdf0e10cSrcweir // 6. A~Eof continue 253*cdf0e10cSrcweir // 7. TB~A set hotkey to following letter, continue 254*cdf0e10cSrcweir // 8. TB~NA continue 255*cdf0e10cSrcweir // 9. TB~Eot continue 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir // bNext and Prev are true, if there are alphabetic letters: 258*cdf0e10cSrcweir sal_Bool bNext = pInputPosition + 1 != pInputEnd 259*cdf0e10cSrcweir ? CalculateBranch(pInputPosition[1]) >= BR_ALPHABASE 260*cdf0e10cSrcweir : sal_False; 261*cdf0e10cSrcweir sal_Bool bPrev = pCurParseNode->Value() >= BR_ALPHABASE; 262*cdf0e10cSrcweir 263*cdf0e10cSrcweir if ( bNext && (bPrev || pCurParseNode == dpParsingTreeTop) ) 264*cdf0e10cSrcweir { // case 1. and 7. 265*cdf0e10cSrcweir Handle_Hotkey(); 266*cdf0e10cSrcweir continue; 267*cdf0e10cSrcweir } 268*cdf0e10cSrcweir else if (!bPrev && !bNext) 269*cdf0e10cSrcweir { // case 5.,6.,8.,9. 270*cdf0e10cSrcweir continue; 271*cdf0e10cSrcweir } 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir // Case 2.,3.,4. : 274*cdf0e10cSrcweir // so this should be handled as an end of a token. 275*cdf0e10cSrcweir } 276*cdf0e10cSrcweir if (pCurParseNode->TokenType() == WTT_Node::token_to_keep) 277*cdf0e10cSrcweir { 278*cdf0e10cSrcweir Handle_TokenToKeep(); 279*cdf0e10cSrcweir return eCurResult; 280*cdf0e10cSrcweir } 281*cdf0e10cSrcweir else 282*cdf0e10cSrcweir { 283*cdf0e10cSrcweir Handle_TokenToTransform(); 284*cdf0e10cSrcweir return eCurResult; 285*cdf0e10cSrcweir } // endif (pCurParseNode->TokenType() == WTT_Node::token_to_keep) 286*cdf0e10cSrcweir } // endif (pBranch == 0) else 287*cdf0e10cSrcweir } // end for 288*cdf0e10cSrcweir 289*cdf0e10cSrcweir // If here, the text end is reached 290*cdf0e10cSrcweir if (pCurParseNode->TokenType() == WTT_Node::token_to_keep) 291*cdf0e10cSrcweir { 292*cdf0e10cSrcweir Handle_TokenToKeep(); 293*cdf0e10cSrcweir return eCurResult; 294*cdf0e10cSrcweir } 295*cdf0e10cSrcweir else 296*cdf0e10cSrcweir { 297*cdf0e10cSrcweir Handle_TokenToTransform(); 298*cdf0e10cSrcweir return eCurResult; 299*cdf0e10cSrcweir } 300*cdf0e10cSrcweir } 301*cdf0e10cSrcweir 302*cdf0e10cSrcweir ByteString 303*cdf0e10cSrcweir WordTransTree::CurReplacingString() const 304*cdf0e10cSrcweir { 305*cdf0e10cSrcweir return pCurParseNode->ReplaceString(); 306*cdf0e10cSrcweir } 307*cdf0e10cSrcweir 308*cdf0e10cSrcweir void 309*cdf0e10cSrcweir WordTransTree::Handle_Hotkey() 310*cdf0e10cSrcweir { 311*cdf0e10cSrcweir if (cCurHotkey == 0) // Avoid to replace the first found hotkey by 312*cdf0e10cSrcweir // a later one - though this shouldn't happen anyway. 313*cdf0e10cSrcweir { 314*cdf0e10cSrcweir cCurHotkey = (pInputPosition+1) != pInputEnd ? pInputPosition[1] : 0; 315*cdf0e10cSrcweir cCurHotkeySign = *pInputPosition; 316*cdf0e10cSrcweir } 317*cdf0e10cSrcweir } 318*cdf0e10cSrcweir 319*cdf0e10cSrcweir void 320*cdf0e10cSrcweir WordTransTree::Handle_TokenToKeep() 321*cdf0e10cSrcweir { 322*cdf0e10cSrcweir UINT32 nTokenLength = pInputPosition-pInputCurTokenStart; 323*cdf0e10cSrcweir 324*cdf0e10cSrcweir memcpy(pOutputPosition,pInputCurTokenStart,nTokenLength); 325*cdf0e10cSrcweir 326*cdf0e10cSrcweir pOutputPosition += nTokenLength; 327*cdf0e10cSrcweir *pOutputPosition = '\0'; 328*cdf0e10cSrcweir } 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir void 331*cdf0e10cSrcweir WordTransTree::Handle_TokenToTransform() 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir sal_Bool bHaveHotkey = CalculateBranch(cCurHotkey) >= BR_ALPHABASE; 334*cdf0e10cSrcweir const ByteString & rReplace = pCurParseNode->ReplaceString(); 335*cdf0e10cSrcweir 336*cdf0e10cSrcweir // Find position of hotkey in replace-string: 337*cdf0e10cSrcweir sal_uInt16 nHotkeyPos = bHaveHotkey 338*cdf0e10cSrcweir ? rReplace.Search(char(cCurHotkey)) 339*cdf0e10cSrcweir : STRING_NOTFOUND; 340*cdf0e10cSrcweir if (nHotkeyPos == STRING_NOTFOUND && bHaveHotkey) 341*cdf0e10cSrcweir { 342*cdf0e10cSrcweir if (cCurHotkey < 128) 343*cdf0e10cSrcweir { 344*cdf0e10cSrcweir if (islower(cCurHotkey)) 345*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(toupper(char(cCurHotkey))); 346*cdf0e10cSrcweir else 347*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(tolower(char(cCurHotkey))); 348*cdf0e10cSrcweir } 349*cdf0e10cSrcweir else // cCurHotkey >= 128 350*cdf0e10cSrcweir { 351*cdf0e10cSrcweir if (cCurHotkey == c_ae) 352*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(char(c_AE)); 353*cdf0e10cSrcweir else if (cCurHotkey == c_oe) 354*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(char(c_OE)); 355*cdf0e10cSrcweir else if (cCurHotkey == c_ue) 356*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(char(c_UE)); 357*cdf0e10cSrcweir else if (cCurHotkey == c_AE) 358*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(char(c_ae)); 359*cdf0e10cSrcweir else if (cCurHotkey == c_OE) 360*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(char(c_oe)); 361*cdf0e10cSrcweir else if (cCurHotkey == c_UE) 362*cdf0e10cSrcweir nHotkeyPos = rReplace.Search(char(c_ue)); 363*cdf0e10cSrcweir } // endif (cCurHotkey < 128) else 364*cdf0e10cSrcweir 365*cdf0e10cSrcweir if (nHotkeyPos == STRING_NOTFOUND) 366*cdf0e10cSrcweir { 367*cdf0e10cSrcweir eCurResult = HOTKEY_LOST; 368*cdf0e10cSrcweir bHaveHotkey = sal_False; 369*cdf0e10cSrcweir } 370*cdf0e10cSrcweir } // endif (nHotkeyPos == STRING_NOT_FOUND && bHaveHotkey) 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir 373*cdf0e10cSrcweir UINT32 nOutputTokenLength = rReplace.Len() + (bHaveHotkey ? 1 : 0); 374*cdf0e10cSrcweir 375*cdf0e10cSrcweir if (bHaveHotkey) 376*cdf0e10cSrcweir { 377*cdf0e10cSrcweir memcpy( pOutputPosition, 378*cdf0e10cSrcweir pCurParseNode->ReplaceString().GetBuffer(), 379*cdf0e10cSrcweir nHotkeyPos ); 380*cdf0e10cSrcweir *(pOutputPosition + nHotkeyPos) = cCurHotkeySign; 381*cdf0e10cSrcweir memcpy( pOutputPosition + nHotkeyPos + 1, 382*cdf0e10cSrcweir pCurParseNode->ReplaceString().GetBuffer() + nHotkeyPos, 383*cdf0e10cSrcweir nOutputTokenLength - nHotkeyPos - 1); 384*cdf0e10cSrcweir } 385*cdf0e10cSrcweir else 386*cdf0e10cSrcweir { 387*cdf0e10cSrcweir memcpy( pOutputPosition, 388*cdf0e10cSrcweir pCurParseNode->ReplaceString().GetBuffer(), 389*cdf0e10cSrcweir nOutputTokenLength ); 390*cdf0e10cSrcweir } 391*cdf0e10cSrcweir 392*cdf0e10cSrcweir // Convert first letter into upper if necessary: 393*cdf0e10cSrcweir u_char cInStart = CalculateBranch(*pInputCurTokenStart) == BR_HOTKEY 394*cdf0e10cSrcweir ? pInputCurTokenStart[1] 395*cdf0e10cSrcweir : pInputCurTokenStart[0] ; 396*cdf0e10cSrcweir u_char * pOutStart = nHotkeyPos == 0 397*cdf0e10cSrcweir ? pOutputPosition + 1 398*cdf0e10cSrcweir : pOutputPosition ; 399*cdf0e10cSrcweir if (isupper(cInStart) || cInStart > 127) 400*cdf0e10cSrcweir { // Possibly cInStart is upper character: 401*cdf0e10cSrcweir if (isupper(cInStart) || cInStart == c_AE || cInStart == c_OE || cInStart == c_UE) 402*cdf0e10cSrcweir { // Surely cInStart is upper character: 403*cdf0e10cSrcweir u_char cOutStart = *pOutStart; 404*cdf0e10cSrcweir if (cOutStart < 128) 405*cdf0e10cSrcweir *pOutStart = toupper(cOutStart); 406*cdf0e10cSrcweir else if (cOutStart == c_ae) 407*cdf0e10cSrcweir *pOutStart = c_AE; 408*cdf0e10cSrcweir else if (cOutStart == c_oe) 409*cdf0e10cSrcweir *pOutStart = c_OE; 410*cdf0e10cSrcweir else if (cOutStart == c_ue) 411*cdf0e10cSrcweir *pOutStart = c_UE; 412*cdf0e10cSrcweir } 413*cdf0e10cSrcweir } // endif (isupper(cInStart) || cInStart > 127) 414*cdf0e10cSrcweir 415*cdf0e10cSrcweir pOutputPosition += nOutputTokenLength; 416*cdf0e10cSrcweir *pOutputPosition = '\0'; 417*cdf0e10cSrcweir } 418*cdf0e10cSrcweir 419