xref: /trunk/main/l10ntools/source/wtratree.cxx (revision 3cd96b95)
1*3cd96b95SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*3cd96b95SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*3cd96b95SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*3cd96b95SAndrew Rist  * distributed with this work for additional information
6*3cd96b95SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*3cd96b95SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*3cd96b95SAndrew Rist  * "License"); you may not use this file except in compliance
9*3cd96b95SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*3cd96b95SAndrew Rist  *
11*3cd96b95SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*3cd96b95SAndrew Rist  *
13*3cd96b95SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*3cd96b95SAndrew Rist  * software distributed under the License is distributed on an
15*3cd96b95SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*3cd96b95SAndrew Rist  * KIND, either express or implied.  See the License for the
17*3cd96b95SAndrew Rist  * specific language governing permissions and limitations
18*3cd96b95SAndrew Rist  * under the License.
19*3cd96b95SAndrew Rist  *
20*3cd96b95SAndrew Rist  *************************************************************/
21*3cd96b95SAndrew Rist 
22*3cd96b95SAndrew 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
211cdf0e10cSrcweir 	till this functon 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 }
414cdf0e10cSrcweir 
415