source: NonGTP/Xerces/xerces-c_2_8_0/include/xercesc/util/LogicalPath.c @ 2674

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