source: icXML/icXML-devel/src/xercesc/util/LogicalPath.c @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 8.2 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: LogicalPath.c 932887 2010-04-11 13:04:59Z borisk $
20 */
21
22#if !defined(XERCESC_INCLUDE_GUARD_WEAVEPATH_CPP)
23#define XERCESC_INCLUDE_GUARD_WEAVEPATH_CPP
24
25/***
26 *
27 *  Previously, each <OS>PlatformUtils.cpp has its onw copy of the
28 *  method weavePaths(), and almost of them implemented the same logic,
29 *  with few platform specific difference, and unfortunately that
30 *  implementation was wrong.
31 * 
32 *  The only platform specific issue is slash character.
33 *  On all platforms other than Windows, chForwardSlash and chBackSlash
34 *  are considered slash, while on Windows, two additional characters,
35 *  chYenSign and chWonSign are slash as well.
36 *
37 *  The idea is to maintain a SINGLE copy of this method rather than
38 *  each <OS>PlatformUtils.cpp has its own copy, we introduce a new
39 *  method, XMLPlatformUtils::isAnySlash(), to replace the direct checking
40 *  code ( if ( c == chForwardSlash || c == chBackSlash).
41 *
42 *  With this approach, we might have a performance hit since isAnySlash()
43 *  is so frequently used in this implementation, so we intend to make it
44 *  inline. Then we face a complier issue.
45 *
46 *  There are two compilation units involved, one is PlatformUtils.cpp and
47 *  the other <OS>PlatformUtils.cpp. When PlatformUtils.cp get compiled,
48 *  the weavePath(), remove**Slash() have dependency upon isAnySlash() which
49 *  is in <OS>PlatformUtils.cpp (and what is worse, it is inlined), so we have
50 *  undefined/unresolved symbol: isAnySlash() on AIX/xlc_r, Solaris/cc and
51 *  Linux/gcc, while MSVC and HP/aCC are fine with this.
52 * 
53 *  That means we can not place these new methods in PlatformUtils.cpp with
54 *  inlined XMLPlatformUtils::isAnySlash() in <OS>PlatformUtils.cpp.
55 *
56 *  The solution to this is <os>PlatformUtils.cpp will include this file so that
57 *  we have only one copy of these methods while get compiled in <os>PlatformUtils
58 *  inlined isAnySlash().
59 *
60 ***/
61XMLCh* XMLPlatformUtils::weavePaths(const XMLCh* const    basePath
62                                  , const XMLCh* const    relativePath
63                                  , MemoryManager* const  manager)
64
65{
66    // Create a buffer as large as both parts and empty it
67    XMLCh* tmpBuf = (XMLCh*) manager->allocate
68    (
69        (XMLString::stringLen(basePath)
70         + XMLString::stringLen(relativePath) + 2) * sizeof(XMLCh)
71    );//new XMLCh[XMLString::stringLen(basePath) + XMLString::stringLen(relativePath) + 2];
72    *tmpBuf = 0;
73
74    //
75    //  If we have no base path, then just take the relative path as is.
76    //
77    if ((!basePath) || (!*basePath))
78    {
79        XMLString::copyString(tmpBuf, relativePath);
80        return tmpBuf;
81    }
82
83    //
84    // Remove anything after the last slash
85    //
86    const XMLCh* basePtr = basePath + (XMLString::stringLen(basePath) - 1);
87    while ((basePtr >= basePath)  &&  ((isAnySlash(*basePtr) == false)))
88    {
89        basePtr--;
90    }
91
92    // There is no relevant base path, so just take the relative part
93    if (basePtr < basePath)
94    {
95        XMLString::copyString(tmpBuf, relativePath);
96        return tmpBuf;
97    }
98
99    //
100    // 1. concatenate the base and relative
101    // 2. remove all occurrences of "/./"
102    // 3. remove all occurrences of segment/../ where segment is not ../
103        //
104
105    XMLString::subString(tmpBuf, basePath, 0, (basePtr - basePath + 1), manager);
106    tmpBuf[basePtr - basePath + 1] = 0;
107    XMLString::catString(tmpBuf, relativePath);
108
109    removeDotSlash(tmpBuf, manager);
110
111    removeDotDotSlash(tmpBuf, manager);
112
113    return tmpBuf;
114
115}
116
117//
118// Remove all occurrences of './' when it is part of '/./'
119//
120// Since it could be '.\' or other combination on windows ( eg, '.'+chYanSign)
121// we can't make use of patterMatch().
122//
123//
124void XMLPlatformUtils::removeDotSlash(XMLCh* const path
125                                      , MemoryManager* const manager)
126{
127    if ((!path) || (!*path))
128        return;
129
130    XMLCh* srcPtr = XMLString::replicate(path, manager);
131    int    srcLen = XMLString::stringLen(srcPtr);
132    ArrayJanitor<XMLCh>   janName(srcPtr, manager);   
133    XMLCh* tarPtr = path;
134
135    while (*srcPtr)
136    {
137        if ( 3 <= srcLen )
138        {
139            if ( (isAnySlash(*srcPtr))     &&
140                (chPeriod == *(srcPtr+1)) &&
141                (isAnySlash(*(srcPtr+2)))  )
142            {
143                // "\.\x" seen
144                // skip the first two, and start from the 3rd,
145                // since "\x" could be another "\."
146                srcPtr+=2;             
147                srcLen-=2;
148            }
149            else
150            {
151                *tarPtr++ = *srcPtr++;  // eat the current char
152                srcLen--;
153            }
154        }
155        else if ( 1 == srcLen )
156        {
157            *tarPtr++ = *srcPtr++;
158        }
159        else if ( 2 == srcLen)
160        {
161            *tarPtr++ = *srcPtr++;
162            *tarPtr++ = *srcPtr++;
163        }
164
165    }
166
167    *tarPtr = 0;
168
169    return;
170}
171
172//
173// Remove all occurrences of '/segment/../' when segment is not '..'
174//
175// Cases with extra /../ is left to the underlying file system.
176//
177void XMLPlatformUtils::removeDotDotSlash(XMLCh* const path
178                                         , MemoryManager* const manager)
179{
180    int pathLen = XMLString::stringLen(path);
181    XMLCh* tmp1 = (XMLCh*) manager->allocate
182    (
183        (pathLen+1) * sizeof(XMLCh)
184    );//new XMLCh [pathLen+1];
185    ArrayJanitor<XMLCh>   tmp1Name(tmp1, manager);
186
187    XMLCh* tmp2 = (XMLCh*) manager->allocate
188    (
189        (pathLen+1) * sizeof(XMLCh)
190    );//new XMLCh [pathLen+1];
191    ArrayJanitor<XMLCh>   tmp2Name(tmp2, manager);
192
193    // remove all "<segment>/../" where "<segment>" is a complete
194    // path segment not equal to ".."
195    int index = -1;
196    int segIndex = -1;
197    int offset = 1;
198
199    while ((index = searchSlashDotDotSlash(&(path[offset]))) != -1)
200    {
201        // Undo offset
202        index += offset;
203
204        // Find start of <segment> within substring ending at found point.
205        XMLString::subString(tmp1, path, 0, index-1, manager);
206        segIndex = index - 1;
207        while ((segIndex >= 0) && (!isAnySlash(tmp1[segIndex])))
208        {
209            segIndex--;
210        }
211
212        // Ensure <segment> exists and != ".."
213        if (segIndex >= 0                 &&
214            (path[segIndex+1] != chPeriod ||
215             path[segIndex+2] != chPeriod ||
216             segIndex + 3 != index))
217        {
218
219            XMLString::subString(tmp1, path, 0, segIndex, manager);
220            XMLString::subString(tmp2, path, index+3, XMLString::stringLen(path), manager);
221
222            path[0] = 0;
223            XMLString::catString(path, tmp1);
224            XMLString::catString(path, tmp2);
225
226            offset = (segIndex == 0 ? 1 : segIndex);
227        }
228        else
229        {
230            offset += 4;
231        }
232
233    }// while
234
235}
236
237int XMLPlatformUtils::searchSlashDotDotSlash(XMLCh* const srcPath)
238{
239    if ((!srcPath) || (!*srcPath))
240        return -1;
241
242    XMLCh* srcPtr = srcPath;
243    int    srcLen = XMLString::stringLen(srcPath);
244    int    retVal = -1;
245
246    while (*srcPtr)
247    {
248        if ( 4 <= srcLen )
249        {
250            if ( (isAnySlash(*srcPtr))     &&
251                 (chPeriod == *(srcPtr+1)) &&
252                 (chPeriod == *(srcPtr+2)) &&
253                 (isAnySlash(*(srcPtr+3)))  )
254            {
255                retVal = (srcPtr - srcPath);
256                break;
257            }
258            else
259            {
260                srcPtr++;
261                srcLen--;
262            }
263        }
264        else 
265        {
266            break;
267        }
268
269    } // while
270
271    return retVal;
272
273}
274
275#endif
Note: See TracBrowser for help on using the repository browser.