GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: LogicalPath.c 932887 2010-04-11 13:04:59Z borisk $ 00020 */ 00021 00022 #if !defined(XERCESC_INCLUDE_GUARD_WEAVEPATH_CPP) 00023 #define XERCESC_INCLUDE_GUARD_WEAVEPATH_CPP 00024 00025 /*** 00026 * 00027 * Previously, each <OS>PlatformUtils.cpp has its onw copy of the 00028 * method weavePaths(), and almost of them implemented the same logic, 00029 * with few platform specific difference, and unfortunately that 00030 * implementation was wrong. 00031 * 00032 * The only platform specific issue is slash character. 00033 * On all platforms other than Windows, chForwardSlash and chBackSlash 00034 * are considered slash, while on Windows, two additional characters, 00035 * chYenSign and chWonSign are slash as well. 00036 * 00037 * The idea is to maintain a SINGLE copy of this method rather than 00038 * each <OS>PlatformUtils.cpp has its own copy, we introduce a new 00039 * method, XMLPlatformUtils::isAnySlash(), to replace the direct checking 00040 * code ( if ( c == chForwardSlash || c == chBackSlash). 00041 * 00042 * With this approach, we might have a performance hit since isAnySlash() 00043 * is so frequently used in this implementation, so we intend to make it 00044 * inline. Then we face a complier issue. 00045 * 00046 * There are two compilation units involved, one is PlatformUtils.cpp and 00047 * the other <OS>PlatformUtils.cpp. When PlatformUtils.cp get compiled, 00048 * the weavePath(), remove**Slash() have dependency upon isAnySlash() which 00049 * is in <OS>PlatformUtils.cpp (and what is worse, it is inlined), so we have 00050 * undefined/unresolved symbol: isAnySlash() on AIX/xlc_r, Solaris/cc and 00051 * Linux/gcc, while MSVC and HP/aCC are fine with this. 00052 * 00053 * That means we can not place these new methods in PlatformUtils.cpp with 00054 * inlined XMLPlatformUtils::isAnySlash() in <OS>PlatformUtils.cpp. 00055 * 00056 * The solution to this is <os>PlatformUtils.cpp will include this file so that 00057 * we have only one copy of these methods while get compiled in <os>PlatformUtils 00058 * inlined isAnySlash(). 00059 * 00060 ***/ 00061 XMLCh* XMLPlatformUtils::weavePaths(const XMLCh* const basePath 00062 , const XMLCh* const relativePath 00063 , MemoryManager* const manager) 00064 00065 { 00066 // Create a buffer as large as both parts and empty it 00067 XMLCh* tmpBuf = (XMLCh*) manager->allocate 00068 ( 00069 (XMLString::stringLen(basePath) 00070 + XMLString::stringLen(relativePath) + 2) * sizeof(XMLCh) 00071 );//new XMLCh[XMLString::stringLen(basePath) + XMLString::stringLen(relativePath) + 2]; 00072 *tmpBuf = 0; 00073 00074 // 00075 // If we have no base path, then just take the relative path as is. 00076 // 00077 if ((!basePath) || (!*basePath)) 00078 { 00079 XMLString::copyString(tmpBuf, relativePath); 00080 return tmpBuf; 00081 } 00082 00083 // 00084 // Remove anything after the last slash 00085 // 00086 const XMLCh* basePtr = basePath + (XMLString::stringLen(basePath) - 1); 00087 while ((basePtr >= basePath) && ((isAnySlash(*basePtr) == false))) 00088 { 00089 basePtr--; 00090 } 00091 00092 // There is no relevant base path, so just take the relative part 00093 if (basePtr < basePath) 00094 { 00095 XMLString::copyString(tmpBuf, relativePath); 00096 return tmpBuf; 00097 } 00098 00099 // 00100 // 1. concatenate the base and relative 00101 // 2. remove all occurrences of "/./" 00102 // 3. remove all occurrences of segment/../ where segment is not ../ 00103 // 00104 00105 XMLString::subString(tmpBuf, basePath, 0, (basePtr - basePath + 1), manager); 00106 tmpBuf[basePtr - basePath + 1] = 0; 00107 XMLString::catString(tmpBuf, relativePath); 00108 00109 removeDotSlash(tmpBuf, manager); 00110 00111 removeDotDotSlash(tmpBuf, manager); 00112 00113 return tmpBuf; 00114 00115 } 00116 00117 // 00118 // Remove all occurrences of './' when it is part of '/./' 00119 // 00120 // Since it could be '.\' or other combination on windows ( eg, '.'+chYanSign) 00121 // we can't make use of patterMatch(). 00122 // 00123 // 00124 void XMLPlatformUtils::removeDotSlash(XMLCh* const path 00125 , MemoryManager* const manager) 00126 { 00127 if ((!path) || (!*path)) 00128 return; 00129 00130 XMLCh* srcPtr = XMLString::replicate(path, manager); 00131 int srcLen = XMLString::stringLen(srcPtr); 00132 ArrayJanitor<XMLCh> janName(srcPtr, manager); 00133 XMLCh* tarPtr = path; 00134 00135 while (*srcPtr) 00136 { 00137 if ( 3 <= srcLen ) 00138 { 00139 if ( (isAnySlash(*srcPtr)) && 00140 (chPeriod == *(srcPtr+1)) && 00141 (isAnySlash(*(srcPtr+2))) ) 00142 { 00143 // "\.\x" seen 00144 // skip the first two, and start from the 3rd, 00145 // since "\x" could be another "\." 00146 srcPtr+=2; 00147 srcLen-=2; 00148 } 00149 else 00150 { 00151 *tarPtr++ = *srcPtr++; // eat the current char 00152 srcLen--; 00153 } 00154 } 00155 else if ( 1 == srcLen ) 00156 { 00157 *tarPtr++ = *srcPtr++; 00158 } 00159 else if ( 2 == srcLen) 00160 { 00161 *tarPtr++ = *srcPtr++; 00162 *tarPtr++ = *srcPtr++; 00163 } 00164 00165 } 00166 00167 *tarPtr = 0; 00168 00169 return; 00170 } 00171 00172 // 00173 // Remove all occurrences of '/segment/../' when segment is not '..' 00174 // 00175 // Cases with extra /../ is left to the underlying file system. 00176 // 00177 void XMLPlatformUtils::removeDotDotSlash(XMLCh* const path 00178 , MemoryManager* const manager) 00179 { 00180 int pathLen = XMLString::stringLen(path); 00181 XMLCh* tmp1 = (XMLCh*) manager->allocate 00182 ( 00183 (pathLen+1) * sizeof(XMLCh) 00184 );//new XMLCh [pathLen+1]; 00185 ArrayJanitor<XMLCh> tmp1Name(tmp1, manager); 00186 00187 XMLCh* tmp2 = (XMLCh*) manager->allocate 00188 ( 00189 (pathLen+1) * sizeof(XMLCh) 00190 );//new XMLCh [pathLen+1]; 00191 ArrayJanitor<XMLCh> tmp2Name(tmp2, manager); 00192 00193 // remove all "<segment>/../" where "<segment>" is a complete 00194 // path segment not equal to ".." 00195 int index = -1; 00196 int segIndex = -1; 00197 int offset = 1; 00198 00199 while ((index = searchSlashDotDotSlash(&(path[offset]))) != -1) 00200 { 00201 // Undo offset 00202 index += offset; 00203 00204 // Find start of <segment> within substring ending at found point. 00205 XMLString::subString(tmp1, path, 0, index-1, manager); 00206 segIndex = index - 1; 00207 while ((segIndex >= 0) && (!isAnySlash(tmp1[segIndex]))) 00208 { 00209 segIndex--; 00210 } 00211 00212 // Ensure <segment> exists and != ".." 00213 if (segIndex >= 0 && 00214 (path[segIndex+1] != chPeriod || 00215 path[segIndex+2] != chPeriod || 00216 segIndex + 3 != index)) 00217 { 00218 00219 XMLString::subString(tmp1, path, 0, segIndex, manager); 00220 XMLString::subString(tmp2, path, index+3, XMLString::stringLen(path), manager); 00221 00222 path[0] = 0; 00223 XMLString::catString(path, tmp1); 00224 XMLString::catString(path, tmp2); 00225 00226 offset = (segIndex == 0 ? 1 : segIndex); 00227 } 00228 else 00229 { 00230 offset += 4; 00231 } 00232 00233 }// while 00234 00235 } 00236 00237 int XMLPlatformUtils::searchSlashDotDotSlash(XMLCh* const srcPath) 00238 { 00239 if ((!srcPath) || (!*srcPath)) 00240 return -1; 00241 00242 XMLCh* srcPtr = srcPath; 00243 int srcLen = XMLString::stringLen(srcPath); 00244 int retVal = -1; 00245 00246 while (*srcPtr) 00247 { 00248 if ( 4 <= srcLen ) 00249 { 00250 if ( (isAnySlash(*srcPtr)) && 00251 (chPeriod == *(srcPtr+1)) && 00252 (chPeriod == *(srcPtr+2)) && 00253 (isAnySlash(*(srcPtr+3))) ) 00254 { 00255 retVal = (srcPtr - srcPath); 00256 break; 00257 } 00258 else 00259 { 00260 srcPtr++; 00261 srcLen--; 00262 } 00263 } 00264 else 00265 { 00266 break; 00267 } 00268 00269 } // while 00270 00271 return retVal; 00272 00273 } 00274 00275 #endif