~ubuntu-branches/ubuntu/precise/xerces-c/precise

« back to all changes in this revision

Viewing changes to src/xercesc/util/FileManagers/WindowsFileMgr.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jay Berkenbilt
  • Date: 2009-02-22 16:52:23 UTC
  • Revision ID: james.westby@ubuntu.com-20090222165223-klimp8u8m73yn9zp
Tags: upstream-3.0.1
ImportĀ upstreamĀ versionĀ 3.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <xercesc/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
 
 
33
XERCES_CPP_NAMESPACE_BEGIN
 
34
 
 
35
static bool isBackSlash(XMLCh c) {
 
36
    return c == chBackSlash ||
 
37
           c == chYenSign   ||
 
38
           c == chWonSign;
 
39
}
 
40
 
 
41
WindowsFileMgr::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
 
 
51
WindowsFileMgr::~WindowsFileMgr()
 
52
{
 
53
}
 
54
 
 
55
 
 
56
FileHandle
 
57
WindowsFileMgr::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
 
 
184
FileHandle
 
185
WindowsFileMgr::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
 
 
193
FileHandle
 
194
WindowsFileMgr::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
 
 
225
void
 
226
WindowsFileMgr::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
 
 
236
void
 
237
WindowsFileMgr::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
 
 
248
XMLFilePos
 
249
WindowsFileMgr::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
 
 
264
XMLFilePos
 
265
WindowsFileMgr::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
 
 
280
XMLSize_t
 
281
WindowsFileMgr::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
 
 
300
void
 
301
WindowsFileMgr::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
 
 
320
XMLCh*
 
321
WindowsFileMgr::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
 
 
361
XMLCh*
 
362
WindowsFileMgr::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
 
 
396
bool
 
397
WindowsFileMgr::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
 
 
430
XERCES_CPP_NAMESPACE_END
 
431