source: icXML/icXML-devel/src/xercesc/util/FileManagers/WindowsFileMgr.cpp @ 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: 12.8 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: WindowsFileMgr.cpp 556533 2007-07-16 07:36:41Z amassari $
20 */
21
22#include <windows.h>
23
24#include <xercesc/util/FileManagers/WindowsFileMgr.hpp>
25#include <xercesc/util/Janitor.hpp>
26#include <icxercesc/util/XMLString.hpp>
27#include <xercesc/util/XMLUniDefs.hpp>
28
29#ifndef INVALID_SET_FILE_POINTER
30#define INVALID_SET_FILE_POINTER ((DWORD)-1)
31#endif
32
33XERCES_CPP_NAMESPACE_BEGIN
34
35static bool isBackSlash(XMLCh c) {
36    return c == chBackSlash ||
37           c == chYenSign   ||
38           c == chWonSign;
39}
40
41WindowsFileMgr::WindowsFileMgr()
42{
43    // Figure out if we are on NT and save that flag for later use
44    OSVERSIONINFO   OSVer;
45    OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
46    ::GetVersionEx(&OSVer);
47    _onNT = (OSVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
48}
49
50
51WindowsFileMgr::~WindowsFileMgr()
52{
53}
54
55
56FileHandle
57WindowsFileMgr::fileOpen(const XMLCh* fileName, bool toWrite, MemoryManager* const manager)
58{
59    // Watch for obvious wierdness
60    if (!fileName)
61        return 0;
62
63    //
64    //  We have to play a little trick here. If its /x:.....
65    //  style fully qualified path, we have to toss the leading /
66    //  character.
67    //
68    const XMLCh* nameToOpen = fileName;
69    if (*fileName == chForwardSlash)
70    {
71        if (XMLString::stringLen(fileName) > 3)
72        {
73            if (*(fileName + 2) == chColon)
74            {
75                const XMLCh chDrive = *(fileName + 1);
76                if (((chDrive >= chLatin_A) && (chDrive <= chLatin_Z))
77                ||  ((chDrive >= chLatin_a) && (chDrive <= chLatin_z)))
78                {
79                    nameToOpen = fileName + 1;
80                }
81            }
82
83            // Similarly for UNC paths
84            if ( *(fileName + 1) == *(fileName + 2) &&
85                 (*(fileName + 1) == chForwardSlash ||
86                  *(fileName + 1) == chBackSlash) )
87            {
88                nameToOpen = fileName + 1;
89            }
90        }
91    }
92
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.
98    //
99    //  Unicode Yen or Won signs as directory separators will fail.
100    //
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.
103    //
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.
110    //
111    XMLCh *tmpUName = 0;
112
113    const XMLCh* srcPtr = nameToOpen;
114    while (*srcPtr)
115    {
116        if (*srcPtr == chYenSign ||
117            *srcPtr == chWonSign)
118            break;
119        srcPtr++;
120    }
121
122    //
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.
125    //
126    if (*srcPtr)
127    {
128        tmpUName = XMLString::replicate(nameToOpen, manager);
129
130        XMLCh* tmpPtr = tmpUName;
131        while (*tmpPtr)
132        {
133            if (*tmpPtr == chYenSign ||
134                *tmpPtr == chWonSign)
135                *tmpPtr = chForwardSlash;
136            tmpPtr++;
137        }
138        nameToOpen = tmpUName;
139    }
140    FileHandle retVal = 0;
141    if (_onNT)
142    {
143        retVal = ::CreateFileW
144            (
145            (LPCWSTR) nameToOpen
146            , toWrite?GENERIC_WRITE:GENERIC_READ
147            , FILE_SHARE_READ
148            , 0
149            , toWrite?CREATE_ALWAYS:OPEN_EXISTING
150            , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
151            , 0
152            );
153    }
154    else
155    {
156        //
157        //  We are Win 95 / 98.  Take the Unicode file name back to (char *)
158        //    so that we can open it.
159        //
160        char* tmpName = XMLString::transcode(nameToOpen, manager);
161        retVal = ::CreateFileA
162            (
163            tmpName
164            , toWrite?GENERIC_WRITE:GENERIC_READ
165            , FILE_SHARE_READ
166            , 0
167            , toWrite?CREATE_ALWAYS:OPEN_EXISTING
168            , toWrite?FILE_ATTRIBUTE_NORMAL:FILE_FLAG_SEQUENTIAL_SCAN
169            , 0
170            );
171        manager->deallocate(tmpName);//delete [] tmpName;
172    }
173
174    if (tmpUName)
175        manager->deallocate(tmpUName);//delete [] tmpUName;
176
177    if (retVal == INVALID_HANDLE_VALUE)
178        return 0;
179
180    return retVal;
181}
182
183
184FileHandle
185WindowsFileMgr::fileOpen(const char* path, bool toWrite, MemoryManager* const manager)
186{
187    XMLCh* tmpFileName = XMLString::transcode(path, manager);
188    ArrayJanitor<XMLCh> janText(tmpFileName, manager);
189    return fileOpen(tmpFileName, toWrite, manager);
190}
191
192
193FileHandle
194WindowsFileMgr::openStdIn(MemoryManager* const manager)
195{
196    //
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.
201    //
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);
206    }
207
208    HANDLE retHandle;
209    if (!::DuplicateHandle
210    (
211        ::GetCurrentProcess()
212        , stdInOrg
213        , ::GetCurrentProcess()
214        , &retHandle
215        , 0
216        , FALSE
217        , DUPLICATE_SAME_ACCESS))
218    {
219        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotDupHandle, manager);
220    }
221    return retHandle;
222}
223
224
225void
226WindowsFileMgr::fileClose(FileHandle f, MemoryManager* const manager)
227{
228    if (!f)
229                ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
230
231    if (!::CloseHandle(f))
232        ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotCloseFile, manager);
233}
234
235
236void
237WindowsFileMgr::fileReset(FileHandle f, MemoryManager* const manager)
238{
239    if (!f)
240                ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
241
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);
245}
246
247
248XMLFilePos
249WindowsFileMgr::curPos(FileHandle f, MemoryManager* const manager)
250{
251    if (!f)
252                ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
253                 
254    // Get the current position
255    LONG high=0;
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);
259
260    return (((XMLFilePos)high) << 32) | low;
261}
262
263
264XMLFilePos
265WindowsFileMgr::fileSize(FileHandle f, MemoryManager* const manager)
266{
267    if (!f)
268                ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
269       
270    DWORD high=0;
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);
275
276    return (((XMLFilePos)high) << 32) | low;
277}
278
279
280XMLSize_t
281WindowsFileMgr::fileRead(FileHandle f, XMLSize_t byteCount, XMLByte* buffer, MemoryManager* const manager)
282{
283    if (!f || !buffer)
284                ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
285               
286    DWORD bytesRead = 0;
287    if (!::ReadFile(f, buffer, (DWORD)byteCount, &bytesRead, 0))
288    {
289        //
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.
292        //
293        if (::GetLastError() != ERROR_BROKEN_PIPE)
294            ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotReadFromFile, manager);
295    }
296    return (unsigned int)bytesRead;
297}
298
299
300void
301WindowsFileMgr::fileWrite(FileHandle f, XMLSize_t byteCount, const XMLByte* buffer, MemoryManager* const manager)
302{
303    if (!f || !buffer)
304                ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::CPtr_PointerIsZero, manager);
305
306    const XMLByte* tmpFlush = buffer;
307
308    while (byteCount > 0)
309    {
310        DWORD bytesWritten = 0;
311        if (!::WriteFile(f, tmpFlush, (DWORD)byteCount, &bytesWritten, 0))
312            ThrowXMLwithMemMgr(XMLPlatformUtilsException, XMLExcepts::File_CouldNotWriteToFile, manager);
313
314        tmpFlush+=bytesWritten;
315        byteCount-=bytesWritten;
316    }
317}
318
319
320XMLCh*
321WindowsFileMgr::getFullPath(const XMLCh* const srcPath, MemoryManager* const manager)
322{
323    //
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.
327    //
328    if (_onNT)
329    {
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];
333
334        XMLCh* namePart = 0;
335        if (!::GetFullPathNameW((LPCWSTR)srcPath, bufSize, (LPWSTR)tmpPath, (LPWSTR*)&namePart))
336            return 0;
337
338        // Return a copy of the path
339        return XMLString::replicate(tmpPath, manager);
340    }
341     else
342    {
343        // Transcode the incoming string
344        char* tmpSrcPath = XMLString::transcode(srcPath, manager);
345        ArrayJanitor<char> janSrcPath(tmpSrcPath, manager);
346
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];
350
351        char* namePart = 0;
352        if (!::GetFullPathNameA(tmpSrcPath, bufSize, tmpPath, &namePart))
353            return 0;
354
355        // Return a transcoded copy of the path
356        return XMLString::transcode(tmpPath, manager);
357    }
358}
359
360
361XMLCh*
362WindowsFileMgr::getCurrentDirectory(MemoryManager* const manager)
363{
364    //
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.
368    //
369    if (_onNT)
370    {
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];
374
375        if (!::GetCurrentDirectoryW(bufSize, (LPWSTR)tmpPath))
376            return 0;
377
378        // Return a copy of the path
379        return XMLString::replicate(tmpPath, manager);
380    }
381     else
382    {
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];
386
387        if (!::GetCurrentDirectoryA(bufSize, tmpPath))
388            return 0;
389
390        // Return a transcoded copy of the path
391        return XMLString::transcode(tmpPath, manager);
392    }
393}
394
395
396bool
397WindowsFileMgr::isRelative(const XMLCh* const toCheck, MemoryManager* const /*manager*/)
398{
399    // Check for pathological case of empty path
400    if (!toCheck || !toCheck[0])
401        return false;
402
403    //
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
407    //  a null character.
408    //
409    if (toCheck[1] == chColon)
410    {
411        if (((toCheck[0] >= chLatin_A) && (toCheck[0] <= chLatin_Z))
412        ||  ((toCheck[0] >= chLatin_a) && (toCheck[0] <= chLatin_z)))
413        {
414            return false;
415        }
416    }
417
418    //
419    //  If it starts with a double slash, then it cannot be relative since
420    //  it's a remote file.
421    //
422    if (isBackSlash(toCheck[0]))
423        return false;
424
425    // Else assume its a relative path
426    return true;
427}
428
429
430XERCES_CPP_NAMESPACE_END
431
Note: See TracBrowser for help on using the repository browser.