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
9
* http://www.apache.org/licenses/LICENSE-2.0
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.
19
* $Id: WindowsFileMgr.cpp 556533 2007-07-16 07:36:41Z amassari $
24
#include <xercesc/util/FileManagers/WindowsFileMgr.hpp>
25
#include <xercesc/util/Janitor.hpp>
26
#include <xercesc/util/XMLString.hpp>
27
#include <xercesc/util/XMLUniDefs.hpp>
29
#ifndef INVALID_SET_FILE_POINTER
30
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
33
XERCES_CPP_NAMESPACE_BEGIN
35
static bool isBackSlash(XMLCh c) {
36
return c == chBackSlash ||
41
WindowsFileMgr::WindowsFileMgr()
43
// Figure out if we are on NT and save that flag for later use
45
OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
46
::GetVersionEx(&OSVer);
47
_onNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
51
WindowsFileMgr::~WindowsFileMgr()
57
WindowsFileMgr::fileOpen(const XMLCh* fileName, bool toWrite, MemoryManager* const manager)
59
// Watch for obvious wierdness
64
// We have to play a little trick here. If its /x:.....
65
// style fully qualified path, we have to toss the leading /
68
const XMLCh* nameToOpen = fileName;
69
if (*fileName == chForwardSlash)
71
if (XMLString::stringLen(fileName) > 3)
73
if (*(fileName + 2) == chColon)
75
const XMLCh chDrive = *(fileName + 1);
76
if (((chDrive >= chLatin_A) && (chDrive <= chLatin_Z))
77
|| ((chDrive >= chLatin_a) && (chDrive <= chLatin_z)))
79
nameToOpen = fileName + 1;
83
// Similarly for UNC paths
84
if ( *(fileName + 1) == *(fileName + 2) &&
85
(*(fileName + 1) == chForwardSlash ||
86
*(fileName + 1) == chBackSlash) )
88
nameToOpen = fileName + 1;
93
// Ok, this might look stupid but its a semi-expedient way to deal
94
// with a thorny problem. Shift-JIS and some other Asian encodings
95
// are fundamentally broken and map both the backslash and the Yen
96
// sign to the same code point. Transcoders have to pick one or the
97
// other to map '\' to Unicode and tend to choose the Yen sign.
99
// Unicode Yen or Won signs as directory separators will fail.
101
// So, we will check this path name for Yen or won signs and, if they are
102
// there, we'll replace them with slashes.
104
// A further twist: we replace Yen and Won with forward slashes rather
105
// than back slashes. Either form of slash will work as a directory
106
// separator. On Win 95 and 98, though, Unicode back-slashes may
107
// fail to transode back to 8-bit 0x5C with some Unicode converters
108
// to some of the problematic code pages. Forward slashes always
109
// transcode correctly back to 8 bit char * form.
113
const XMLCh* srcPtr = nameToOpen;
116
if (*srcPtr == chYenSign ||
117
*srcPtr == chWonSign)
123
// If we found a yen, then we have to create a temp file name. Else
124
// go with the file name as is and save the overhead.
128
tmpUName = XMLString::replicate(nameToOpen, manager);
130
XMLCh* tmpPtr = tmpUName;
133
if (*tmpPtr == chYenSign ||
134
*tmpPtr == chWonSign)
135
*tmpPtr = chForwardSlash;
138
nameToOpen = tmpUName;
140
FileHandle retVal = 0;
143
retVal = ::CreateFileW
146
, toWrite?GENERIC_WRITE:GENERIC_READ
149
, toWrite?CREATE_ALWAYS:OPEN_EXISTING
150
, toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
157
// We are Win 95 / 98. Take the Unicode file name back to (char *)
158
// so that we can open it.
160
char* tmpName = XMLString::transcode(nameToOpen, manager);
161
retVal = ::CreateFileA
164
, toWrite?GENERIC_WRITE:GENERIC_READ
167
, toWrite?CREATE_ALWAYS:OPEN_EXISTING
168
, toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
171
manager->deallocate(tmpName);//delete [] tmpName;
175
manager->deallocate(tmpUName);//delete [] tmpUName;
177
if (retVal == INVALID_HANDLE_VALUE)
185
WindowsFileMgr::fileOpen(const char* path, bool toWrite, MemoryManager* const manager)
187
XMLCh* tmpFileName = XMLString::transcode(path, manager);
188
ArrayJanitor<XMLCh> janText(tmpFileName, manager);
189
return fileOpen(tmpFileName, toWrite, manager);
194
WindowsFileMgr::openStdIn(MemoryManager* const manager)
197
// Get the standard input handle. Duplicate it and return that copy
198
// since the outside world cannot tell the difference and will shut
199
// down this handle when its done with it. If we gave out the orignal,
200
// shutting it would prevent any further output.
202
HANDLE stdInOrg = ::GetStdHandle(STD_INPUT_HANDLE);
203
if (stdInOrg == INVALID_HANDLE_VALUE) {
204
XMLCh stdinStr[] = {chLatin_s, chLatin_t, chLatin_d, chLatin_i, chLatin_n, chNull};
205
ThrowXMLwithMemMgr1(XMLPlatformUtilsException, XMLExcepts::File_CouldNotOpenFile, stdinStr, manager);
209
if (!::DuplicateHandle
211
::GetCurrentProcess()
213
, ::GetCurrentProcess()
217
, DUPLICATE_SAME_ACCESS))
219
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotDupHandle, manager);
226
WindowsFileMgr::fileClose(FileHandle f, MemoryManager* const manager)
229
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
231
if (!::CloseHandle(f))
232
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager);
237
WindowsFileMgr::fileReset(FileHandle f, MemoryManager* const manager)
240
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
242
// Seek to the start of the file
243
if (::SetFilePointer(f, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
244
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotResetFile, manager);
249
WindowsFileMgr::curPos(FileHandle f, MemoryManager* const manager)
252
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
254
// Get the current position
256
DWORD low = ::SetFilePointer(f, 0, &high, FILE_CURRENT);
257
if (low == INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR)
258
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager);
260
return (((XMLFilePos)high) << 32) | low;
265
WindowsFileMgr::fileSize(FileHandle f, MemoryManager* const manager)
268
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
271
DWORD low=::GetFileSize(f, &high);
272
if(low==INVALID_FILE_SIZE && GetLastError()!=NO_ERROR)
273
// TODO: find a better exception
274
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotGetCurPos, manager);
276
return (((XMLFilePos)high) << 32) | low;
281
WindowsFileMgr::fileRead(FileHandle f, XMLSize_t byteCount, XMLByte* buffer, MemoryManager* const manager)
284
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
287
if (!::ReadFile(f, buffer, (DWORD)byteCount, &bytesRead, 0))
290
// Check specially for a broken pipe error. If we get this, it just
291
// means no more data from the pipe, so return zero.
293
if (::GetLastError() != ERROR_BROKEN_PIPE)
294
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager);
296
return (unsigned int)bytesRead;
301
WindowsFileMgr::fileWrite(FileHandle f, XMLSize_t byteCount, const XMLByte* buffer, MemoryManager* const manager)
304
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
306
const XMLByte* tmpFlush = buffer;
308
while (byteCount > 0)
310
DWORD bytesWritten = 0;
311
if (!::WriteFile(f, tmpFlush, (DWORD)byteCount, &bytesWritten, 0))
312
ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager);
314
tmpFlush+=bytesWritten;
315
byteCount-=bytesWritten;
321
WindowsFileMgr::getFullPath(const XMLCh* const srcPath, MemoryManager* const manager)
324
// If we are on NT, then use wide character APIs, else use ASCII APIs.
325
// We have to do it manually since we are only built in ASCII mode from
326
// the standpoint of the APIs.
330
// Use a local buffer that is big enough for the largest legal path
331
const unsigned int bufSize = 1024;
332
XMLCh tmpPath[bufSize + 1];
335
if (!::GetFullPathNameW((LPCWSTR)srcPath, bufSize, (LPWSTR)tmpPath, (LPWSTR*)&namePart))
338
// Return a copy of the path
339
return XMLString::replicate(tmpPath, manager);
343
// Transcode the incoming string
344
char* tmpSrcPath = XMLString::transcode(srcPath, manager);
345
ArrayJanitor<char> janSrcPath(tmpSrcPath, manager);
347
// Use a local buffer that is big enough for the largest legal path
348
const unsigned int bufSize = 511;
349
char tmpPath[511 + 1];
352
if (!::GetFullPathNameA(tmpSrcPath, bufSize, tmpPath, &namePart))
355
// Return a transcoded copy of the path
356
return XMLString::transcode(tmpPath, manager);
362
WindowsFileMgr::getCurrentDirectory(MemoryManager* const manager)
365
// If we are on NT, then use wide character APIs, else use ASCII APIs.
366
// We have to do it manually since we are only built in ASCII mode from
367
// the standpoint of the APIs.
371
// Use a local buffer that is big enough for the largest legal path
372
const unsigned int bufSize = 1024;
373
XMLCh tmpPath[bufSize + 1];
375
if (!::GetCurrentDirectoryW(bufSize, (LPWSTR)tmpPath))
378
// Return a copy of the path
379
return XMLString::replicate(tmpPath, manager);
383
// Use a local buffer that is big enough for the largest legal path
384
const unsigned int bufSize = 511;
385
char tmpPath[511 + 1];
387
if (!::GetCurrentDirectoryA(bufSize, tmpPath))
390
// Return a transcoded copy of the path
391
return XMLString::transcode(tmpPath, manager);
397
WindowsFileMgr::isRelative(const XMLCh* const toCheck, MemoryManager* const /*manager*/)
399
// Check for pathological case of empty path
400
if (!toCheck || !toCheck[0])
404
// If its starts with a drive, then it cannot be relative. Note that
405
// we checked the drive not being empty above, so worst case its one
406
// char long and the check of the 1st char will fail because its really
409
if (toCheck[1] == chColon)
411
if (((toCheck[0] >= chLatin_A) && (toCheck[0] <= chLatin_Z))
412
|| ((toCheck[0] >= chLatin_a) && (toCheck[0] <= chLatin_z)))
419
// If it starts with a double slash, then it cannot be relative since
420
// it's a remote file.
422
if (isBackSlash(toCheck[0]))
425
// Else assume its a relative path
430
XERCES_CPP_NAMESPACE_END