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