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: WindowsFileMgr.cpp 556533 2007-07-16 07:36:41Z amassari $ 00020 */ 00021 00022 #include <windows.h> 00023 00024 #include <xercesc/util/FileManagers/WindowsFileMgr.hpp> 00025 #include <xercesc/util/Janitor.hpp> 00026 #include <xercesc/util/XMLString.hpp> 00027 #include <xercesc/util/XMLUniDefs.hpp> 00028 00029 #ifndef INVALID_SET_FILE_POINTER 00030 #define INVALID_SET_FILE_POINTER ((DWORD)-1) 00031 #endif 00032 00033 XERCES_CPP_NAMESPACE_BEGIN 00034 00035 static bool isBackSlash(XMLCh c) { 00036 return c == chBackSlash || 00037 c == chYenSign || 00038 c == chWonSign; 00039 } 00040 00041 WindowsFileMgr::WindowsFileMgr() 00042 { 00043 // Figure out if we are on NT and save that flag for later use 00044 OSVERSIONINFO OSVer; 00045 OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 00046 ::GetVersionEx(&OSVer); 00047 _onNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT); 00048 } 00049 00050 00051 WindowsFileMgr::~WindowsFileMgr() 00052 { 00053 } 00054 00055 00056 FileHandle 00057 WindowsFileMgr::fileOpen(const XMLCh* fileName, bool toWrite, MemoryManager* const manager) 00058 { 00059 // Watch for obvious wierdness 00060 if (!fileName) 00061 return 0; 00062 00063 // 00064 // We have to play a little trick here. If its /x:..... 00065 // style fully qualified path, we have to toss the leading / 00066 // character. 00067 // 00068 const XMLCh* nameToOpen = fileName; 00069 if (*fileName == chForwardSlash) 00070 { 00071 if (XMLString::stringLen(fileName) > 3) 00072 { 00073 if (*(fileName + 2) == chColon) 00074 { 00075 const XMLCh chDrive = *(fileName + 1); 00076 if (((chDrive >= chLatin_A) && (chDrive <= chLatin_Z)) 00077 || ((chDrive >= chLatin_a) && (chDrive <= chLatin_z))) 00078 { 00079 nameToOpen = fileName + 1; 00080 } 00081 } 00082 00083 // Similarly for UNC paths 00084 if ( *(fileName + 1) == *(fileName + 2) && 00085 (*(fileName + 1) == chForwardSlash || 00086 *(fileName + 1) == chBackSlash) ) 00087 { 00088 nameToOpen = fileName + 1; 00089 } 00090 } 00091 } 00092 00093 // Ok, this might look stupid but its a semi-expedient way to deal 00094 // with a thorny problem. Shift-JIS and some other Asian encodings 00095 // are fundamentally broken and map both the backslash and the Yen 00096 // sign to the same code point. Transcoders have to pick one or the 00097 // other to map '\' to Unicode and tend to choose the Yen sign. 00098 // 00099 // Unicode Yen or Won signs as directory separators will fail. 00100 // 00101 // So, we will check this path name for Yen or won signs and, if they are 00102 // there, we'll replace them with slashes. 00103 // 00104 // A further twist: we replace Yen and Won with forward slashes rather 00105 // than back slashes. Either form of slash will work as a directory 00106 // separator. On Win 95 and 98, though, Unicode back-slashes may 00107 // fail to transode back to 8-bit 0x5C with some Unicode converters 00108 // to some of the problematic code pages. Forward slashes always 00109 // transcode correctly back to 8 bit char * form. 00110 // 00111 XMLCh *tmpUName = 0; 00112 00113 const XMLCh* srcPtr = nameToOpen; 00114 while (*srcPtr) 00115 { 00116 if (*srcPtr == chYenSign || 00117 *srcPtr == chWonSign) 00118 break; 00119 srcPtr++; 00120 } 00121 00122 // 00123 // If we found a yen, then we have to create a temp file name. Else 00124 // go with the file name as is and save the overhead. 00125 // 00126 if (*srcPtr) 00127 { 00128 tmpUName = XMLString::replicate(nameToOpen, manager); 00129 00130 XMLCh* tmpPtr = tmpUName; 00131 while (*tmpPtr) 00132 { 00133 if (*tmpPtr == chYenSign || 00134 *tmpPtr == chWonSign) 00135 *tmpPtr = chForwardSlash; 00136 tmpPtr++; 00137 } 00138 nameToOpen = tmpUName; 00139 } 00140 FileHandle retVal = 0; 00141 if (_onNT) 00142 { 00143 retVal = ::CreateFileW 00144 ( 00145 (LPCWSTR) nameToOpen 00146 , toWrite?GENERIC_WRITE:GENERIC_READ 00147 , FILE_SHARE_READ 00148 , 0 00149 , toWrite?CREATE_ALWAYS:OPEN_EXISTING 00150 , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN 00151 , 0 00152 ); 00153 } 00154 else 00155 { 00156 // 00157 // We are Win 95 / 98. Take the Unicode file name back to (char *) 00158 // so that we can open it. 00159 // 00160 char* tmpName = XMLString::transcode(nameToOpen, manager); 00161 retVal = ::CreateFileA 00162 ( 00163 tmpName 00164 , toWrite?GENERIC_WRITE:GENERIC_READ 00165 , FILE_SHARE_READ 00166 , 0 00167 , toWrite?CREATE_ALWAYS:OPEN_EXISTING 00168 , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN 00169 , 0 00170 ); 00171 manager->deallocate(tmpName);//delete [] tmpName; 00172 } 00173 00174 if (tmpUName) 00175 manager->deallocate(tmpUName);//delete [] tmpUName; 00176 00177 if (retVal == INVALID_HANDLE_VALUE) 00178 return 0; 00179 00180 return retVal; 00181 } 00182 00183 00184 FileHandle 00185 WindowsFileMgr::fileOpen(const char* path, bool toWrite, MemoryManager* const manager) 00186 { 00187 XMLCh* tmpFileName = XMLString::transcode(path, manager); 00188 ArrayJanitor<XMLCh> janText(tmpFileName, manager); 00189 return fileOpen(tmpFileName, toWrite, manager); 00190 } 00191 00192 00193 FileHandle 00194 WindowsFileMgr::openStdIn(MemoryManager* const manager) 00195 { 00196 // 00197 // Get the standard input handle. Duplicate it and return that copy 00198 // since the outside world cannot tell the difference and will shut 00199 // down this handle when its done with it. If we gave out the orignal, 00200 // shutting it would prevent any further output. 00201 // 00202 HANDLE stdInOrg = ::GetStdHandle(STD_INPUT_HANDLE); 00203 if (stdInOrg == INVALID_HANDLE_VALUE) { 00204 XMLCh stdinStr[] = {chLatin_s, chLatin_t, chLatin_d, chLatin_i, chLatin_n, chNull}; 00205 ThrowXMLwithMemMgr1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, stdinStr, manager); 00206 } 00207 00208 HANDLE retHandle; 00209 if (!::DuplicateHandle 00210 ( 00211 ::GetCurrentProcess() 00212 , stdInOrg 00213 , ::GetCurrentProcess() 00214 , &retHandle 00215 , 0 00216 , FALSE 00217 , DUPLICATE_SAME_ACCESS)) 00218 { 00219 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotDupHandle, manager); 00220 } 00221 return retHandle; 00222 } 00223 00224 00225 void 00226 WindowsFileMgr::fileClose(FileHandle f, MemoryManager* const manager) 00227 { 00228 if (!f) 00229 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager); 00230 00231 if (!::CloseHandle(f)) 00232 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager); 00233 } 00234 00235 00236 void 00237 WindowsFileMgr::fileReset(FileHandle f, MemoryManager* const manager) 00238 { 00239 if (!f) 00240 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager); 00241 00242 // Seek to the start of the file 00243 if (::SetFilePointer(f, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 00244 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile, manager); 00245 } 00246 00247 00248 XMLFilePos 00249 WindowsFileMgr::curPos(FileHandle f, MemoryManager* const manager) 00250 { 00251 if (!f) 00252 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager); 00253 00254 // Get the current position 00255 LONG high=0; 00256 DWORD low = ::SetFilePointer(f, 0, &high, FILE_CURRENT); 00257 if (low == INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) 00258 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager); 00259 00260 return (((XMLFilePos)high) << 32) | low; 00261 } 00262 00263 00264 XMLFilePos 00265 WindowsFileMgr::fileSize(FileHandle f, MemoryManager* const manager) 00266 { 00267 if (!f) 00268 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager); 00269 00270 DWORD high=0; 00271 DWORD low=::GetFileSize(f, &high); 00272 if(low==INVALID_FILE_SIZE && GetLastError()!=NO_ERROR) 00273 // TODO: find a better exception 00274 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager); 00275 00276 return (((XMLFilePos)high) << 32) | low; 00277 } 00278 00279 00280 XMLSize_t 00281 WindowsFileMgr::fileRead(FileHandle f, XMLSize_t byteCount, XMLByte* buffer, MemoryManager* const manager) 00282 { 00283 if (!f || !buffer) 00284 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager); 00285 00286 DWORD bytesRead = 0; 00287 if (!::ReadFile(f, buffer, (DWORD)byteCount, &bytesRead, 0)) 00288 { 00289 // 00290 // Check specially for a broken pipe error. If we get this, it just 00291 // means no more data from the pipe, so return zero. 00292 // 00293 if (::GetLastError() != ERROR_BROKEN_PIPE) 00294 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager); 00295 } 00296 return (unsigned int)bytesRead; 00297 } 00298 00299 00300 void 00301 WindowsFileMgr::fileWrite(FileHandle f, XMLSize_t byteCount, const XMLByte* buffer, MemoryManager* const manager) 00302 { 00303 if (!f || !buffer) 00304 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager); 00305 00306 const XMLByte* tmpFlush = buffer; 00307 00308 while (byteCount > 0) 00309 { 00310 DWORD bytesWritten = 0; 00311 if (!::WriteFile(f, tmpFlush, (DWORD)byteCount, &bytesWritten, 0)) 00312 ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager); 00313 00314 tmpFlush+=bytesWritten; 00315 byteCount-=bytesWritten; 00316 } 00317 } 00318 00319 00320 XMLCh* 00321 WindowsFileMgr::getFullPath(const XMLCh* const srcPath, MemoryManager* const manager) 00322 { 00323 // 00324 // If we are on NT, then use wide character APIs, else use ASCII APIs. 00325 // We have to do it manually since we are only built in ASCII mode from 00326 // the standpoint of the APIs. 00327 // 00328 if (_onNT) 00329 { 00330 // Use a local buffer that is big enough for the largest legal path 00331 const unsigned int bufSize = 1024; 00332 XMLCh tmpPath[bufSize + 1]; 00333 00334 XMLCh* namePart = 0; 00335 if (!::GetFullPathNameW((LPCWSTR)srcPath, bufSize, (LPWSTR)tmpPath, (LPWSTR*)&namePart)) 00336 return 0; 00337 00338 // Return a copy of the path 00339 return XMLString::replicate(tmpPath, manager); 00340 } 00341 else 00342 { 00343 // Transcode the incoming string 00344 char* tmpSrcPath = XMLString::transcode(srcPath, manager); 00345 ArrayJanitor<char> janSrcPath(tmpSrcPath, manager); 00346 00347 // Use a local buffer that is big enough for the largest legal path 00348 const unsigned int bufSize = 511; 00349 char tmpPath[511 + 1]; 00350 00351 char* namePart = 0; 00352 if (!::GetFullPathNameA(tmpSrcPath, bufSize, tmpPath, &namePart)) 00353 return 0; 00354 00355 // Return a transcoded copy of the path 00356 return XMLString::transcode(tmpPath, manager); 00357 } 00358 } 00359 00360 00361 XMLCh* 00362 WindowsFileMgr::getCurrentDirectory(MemoryManager* const manager) 00363 { 00364 // 00365 // If we are on NT, then use wide character APIs, else use ASCII APIs. 00366 // We have to do it manually since we are only built in ASCII mode from 00367 // the standpoint of the APIs. 00368 // 00369 if (_onNT) 00370 { 00371 // Use a local buffer that is big enough for the largest legal path 00372 const unsigned int bufSize = 1024; 00373 XMLCh tmpPath[bufSize + 1]; 00374 00375 if (!::GetCurrentDirectoryW(bufSize, (LPWSTR)tmpPath)) 00376 return 0; 00377 00378 // Return a copy of the path 00379 return XMLString::replicate(tmpPath, manager); 00380 } 00381 else 00382 { 00383 // Use a local buffer that is big enough for the largest legal path 00384 const unsigned int bufSize = 511; 00385 char tmpPath[511 + 1]; 00386 00387 if (!::GetCurrentDirectoryA(bufSize, tmpPath)) 00388 return 0; 00389 00390 // Return a transcoded copy of the path 00391 return XMLString::transcode(tmpPath, manager); 00392 } 00393 } 00394 00395 00396 bool 00397 WindowsFileMgr::isRelative(const XMLCh* const toCheck, MemoryManager* const /*manager*/) 00398 { 00399 // Check for pathological case of empty path 00400 if (!toCheck || !toCheck[0]) 00401 return false; 00402 00403 // 00404 // If its starts with a drive, then it cannot be relative. Note that 00405 // we checked the drive not being empty above, so worst case its one 00406 // char long and the check of the 1st char will fail because its really 00407 // a null character. 00408 // 00409 if (toCheck[1] == chColon) 00410 { 00411 if (((toCheck[0] >= chLatin_A) && (toCheck[0] <= chLatin_Z)) 00412 || ((toCheck[0] >= chLatin_a) && (toCheck[0] <= chLatin_z))) 00413 { 00414 return false; 00415 } 00416 } 00417 00418 // 00419 // If it starts with a double slash, then it cannot be relative since 00420 // it's a remote file. 00421 // 00422 if (isBackSlash(toCheck[0])) 00423 return false; 00424 00425 // Else assume its a relative path 00426 return true; 00427 } 00428 00429 00430 XERCES_CPP_NAMESPACE_END 00431