1 /*
2 * Copyright (c) 1999
3 * Silicon Graphics Computer Systems, Inc.
4 *
5 * Copyright (c) 1999
6 * Boris Fomitchev
7 *
8 * This material is provided "as is", with absolutely no warranty expressed
9 * or implied. Any use is at your own risk.
10 *
11 * Permission to use or copy this software for any purpose is hereby granted
12 * without fee, provided the above notices are retained on all copies.
13 * Permission to modify the code and to distribute modified code is granted,
14 * provided the above notices are retained, and a notice that the code was
15 * modified is included with the above copyright notice.
16 *
17 */
18
19 #include <fstream>
20
21 #if !defined (_STLP_WCE)
22 # ifdef __BORLANDC__
23 # include <cfcntl.h> // For _O_RDONLY, etc
24 # else
25 # include <io.h> // For _get_osfhandle
26 # include <fcntl.h> // For _O_RDONLY, etc
27 # endif
28 # include <sys/stat.h> // For _fstat
29 #endif
30
31 #define _TEXTBUF_SIZE 0x1000
32
33 const _STLP_fd INVALID_STLP_FD = INVALID_HANDLE_VALUE;
34
35 #if !defined (INVALID_SET_FILE_POINTER)
36 # define INVALID_SET_FILE_POINTER 0xffffffff
37 #endif
38
39 #ifndef O_ACCMODE
40 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
41 #endif
42
43 _STLP_BEGIN_NAMESPACE
44
45 #if !defined(__MSL__) && !defined(_STLP_WCE)
flag_to_openmode(int mode)46 static ios_base::openmode flag_to_openmode(int mode) {
47 ios_base::openmode ret = ios_base::__default_mode;
48
49 switch (mode & O_ACCMODE) {
50 case O_RDONLY:
51 ret = ios_base::in; break;
52 case O_WRONLY:
53 ret = ios_base::out; break;
54 case O_RDWR:
55 ret = ios_base::in | ios_base::out; break;
56 }
57
58 if (mode & O_APPEND)
59 ret |= ios_base::app;
60
61 if (mode & O_BINARY)
62 ret |= ios_base::binary;
63
64 return ret;
65 }
66 #endif
67
68 _STLP_MOVE_TO_PRIV_NAMESPACE
69
70 // Helper functions for _Filebuf_base.
71
__is_regular_file(_STLP_fd fd)72 static bool __is_regular_file(_STLP_fd fd) {
73 BY_HANDLE_FILE_INFORMATION info;
74
75 // Return true if the file handle isn't a directory.
76 return GetFileInformationByHandle(fd, &info) &&
77 ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
78 }
79
80 // Number of characters in the file.
__file_size(_STLP_fd fd)81 static streamoff __file_size(_STLP_fd fd) {
82 streamoff ret = 0;
83
84 LARGE_INTEGER li;
85 li.LowPart = GetFileSize(fd, (unsigned long*) &li.HighPart);
86 if (li.LowPart != INVALID_FILE_SIZE || GetLastError() == NO_ERROR)
87 ret = li.QuadPart;
88
89 return ret;
90 }
91
92 _STLP_MOVE_TO_STD_NAMESPACE
93
94 // Visual C++ and Intel use this, but not Metrowerks
95 // Also MinGW, msvcrt.dll (but not crtdll.dll) dependent version
96 #if (defined (_STLP_MSVC_LIB) && !defined (_STLP_WCE)) || \
97 (defined (__MINGW32__) && defined (__MSVCRT__))
98
99 // fcntl(fileno, F_GETFL) for Microsoft library
100 // 'semi-documented' defines:
101 # define IOINFO_L2E 5
102 # define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
103 # define _pioinfo(i) ( __pioinfo[(i) >> IOINFO_L2E] + \
104 ((i) & (IOINFO_ARRAY_ELTS - 1)) )
105 # define FAPPEND 0x20 // O_APPEND flag
106 # define FTEXT 0x80 // O_TEXT flag
107 // end of 'semi-documented' defines
108
109 // 'semi-documented' internal structure
110 extern "C" {
111 struct ioinfo {
112 long osfhnd; // the real os HANDLE
113 char osfile; // file handle flags
114 char pipech; // pipe buffer
115 # if defined (_MT)
116 // multi-threaded locking
117 int lockinitflag;
118 CRITICAL_SECTION lock;
119 # endif
120 };
121 # if defined (__MINGW32__)
122 __MINGW_IMPORT ioinfo * __pioinfo[];
123 # else
124 extern _CRTIMP ioinfo * __pioinfo[];
125 # endif
126 } // extern "C"
127 // end of 'semi-documented' declarations
128
129 static ios_base::openmode _get_osfflags(int fd, HANDLE oshandle) {
130 char dosflags = 0;
131 if (fd >= 0)
132 dosflags = _pioinfo(fd)->osfile;
133 //else
134 //the file will be considered as open in binary mode with no append attribute
135 // end of 'semi-documented' stuff
136
137 int mode = 0;
138 if (dosflags & FAPPEND)
139 mode |= O_APPEND;
140
141 if (dosflags & FTEXT)
142 mode |= O_TEXT;
143 else
144 mode |= O_BINARY;
145
146 // For Read/Write access we have to guess
147 DWORD dummy, dummy2;
148 BOOL writeOk = WriteFile(oshandle, &dummy2, 0, &dummy, 0);
149 BOOL readOk = ReadFile(oshandle, &dummy2, 0, &dummy, NULL);
150 if (writeOk && readOk)
151 mode |= O_RDWR;
152 else if (readOk)
153 mode |= O_RDONLY;
154 else
155 mode |= O_WRONLY;
156
157 return flag_to_openmode(mode);
158 }
159
160 #elif defined (__DMC__)
161
162 # define FHND_APPEND 0x04
163 # define FHND_DEVICE 0x08
164 # define FHND_TEXT 0x10
165
166 extern "C" unsigned char __fhnd_info[_NFILE];
167
168 static ios_base::openmode _get_osfflags(int fd, HANDLE oshandle) {
169 int mode = 0;
170
171 if (__fhnd_info[fd] & FHND_APPEND)
172 mode |= O_APPEND;
173
174 if (__fhnd_info[fd] & FHND_TEXT == 0)
175 mode |= O_BINARY;
176
177 for (FILE *fp = &_iob[0]; fp < &_iob[_NFILE]; fp++) {
178 if ((fileno(fp) == fd) && (fp->_flag & (_IOREAD | _IOWRT | _IORW))) {
179 const int osflags = fp->_flag;
180
181 if ((osflags & _IOREAD) && !(osflags & _IOWRT) && !(osflags & _IORW))
182 mode |= O_RDONLY;
183 else if ((osflags & _IOWRT) && !(osflags & _IOREAD) && !(osflags & _IORW))
184 mode |= O_WRONLY;
185 else
186 mode |= O_RDWR;
187 break;
188 }
189 }
190
191 return flag_to_openmode(mode);
192 }
193 #endif
194
195 size_t _Filebuf_base::_M_page_size = 4096;
196
_Filebuf_base()197 _Filebuf_base::_Filebuf_base()
198 : _M_file_id(INVALID_STLP_FD),
199 _M_openmode(0),
200 _M_is_open(false),
201 _M_should_close(false),
202 _M_view_id(0)
203 {}
204
_S_initialize()205 void _Filebuf_base::_S_initialize() {
206 SYSTEM_INFO SystemInfo;
207 GetSystemInfo(&SystemInfo);
208 _M_page_size = SystemInfo.dwPageSize;
209 // might be .dwAllocationGranularity
210 }
211
212 // Return the size of the file. This is a wrapper for stat.
213 // Returns zero if the size cannot be determined or is ill-defined.
_M_file_size()214 streamoff _Filebuf_base::_M_file_size() {
215 return _STLP_PRIV __file_size(_M_file_id);
216 }
217
_M_open(const char * name,ios_base::openmode openmode,long permission)218 bool _Filebuf_base::_M_open(const char* name, ios_base::openmode openmode,
219 long permission) {
220 _STLP_fd file_no;
221
222 if (_M_is_open)
223 return false;
224
225 DWORD dwDesiredAccess, dwCreationDisposition;
226 bool doTruncate = false;
227
228 switch (openmode & (~ios_base::ate & ~ios_base::binary)) {
229 case ios_base::out:
230 case ios_base::out | ios_base::trunc:
231 dwDesiredAccess = GENERIC_WRITE;
232 dwCreationDisposition = OPEN_ALWAYS;
233 // boris : even though it is very non-intuitive, standard
234 // requires them both to behave same.
235 doTruncate = true;
236 break;
237 case ios_base::out | ios_base::app:
238 dwDesiredAccess = GENERIC_WRITE;
239 dwCreationDisposition = OPEN_ALWAYS;
240 break;
241 case ios_base::in:
242 dwDesiredAccess = GENERIC_READ;
243 dwCreationDisposition = OPEN_EXISTING;
244 permission = 0; // Irrelevant unless we're writing.
245 break;
246 case ios_base::in | ios_base::out:
247 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
248 dwCreationDisposition = OPEN_EXISTING;
249 break;
250 case ios_base::in | ios_base::out | ios_base::trunc:
251 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
252 dwCreationDisposition = OPEN_ALWAYS;
253 doTruncate = true;
254 break;
255 default: // The above are the only combinations of
256 return false; // flags allowed by the C++ standard.
257 }
258
259 DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
260
261 #if defined(_STLP_USE_WIDE_INTERFACE)
262 file_no = CreateFile (_STLP_PRIV __ASCIIToWide(name).c_str(),
263 #else
264 file_no = CreateFileA(name,
265 #endif
266 dwDesiredAccess, dwShareMode, 0,
267 dwCreationDisposition, permission, 0);
268
269 if (file_no == INVALID_STLP_FD)
270 return false;
271
272 if (
273 #if !defined (_STLP_WCE)
274 GetFileType(file_no) == FILE_TYPE_DISK &&
275 #endif
276 ((doTruncate && SetEndOfFile(file_no) == 0) ||
277 (((openmode & ios_base::ate) != 0) &&
278 (SetFilePointer(file_no, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)))) {
279 CloseHandle(file_no);
280 return false;
281 }
282
283 _M_is_open = true;
284 _M_file_id = file_no;
285 _M_should_close = _M_is_open;
286 _M_openmode = openmode;
287
288 if (_M_is_open)
289 _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
290
291 return (_M_is_open != 0);
292 }
293
_M_open(const char * name,ios_base::openmode openmode)294 bool _Filebuf_base::_M_open(const char* name, ios_base::openmode openmode) {
295 // This doesn't really grant everyone in the world read/write
296 // access. On Unix, file-creation system calls always clear
297 // bits that are set in the umask from the permissions flag.
298 return this->_M_open(name, openmode, FILE_ATTRIBUTE_NORMAL);
299 }
300
_M_open(_STLP_fd __id,ios_base::openmode init_mode)301 bool _Filebuf_base::_M_open(_STLP_fd __id, ios_base::openmode init_mode) {
302 #if (defined (_STLP_MSVC_LIB) && !defined (_STLP_WCE)) || \
303 (defined (__MINGW32__) && defined (__MSVCRT__)) || defined (__DMC__)
304
305 if (_M_is_open || __id == INVALID_STLP_FD)
306 return false;
307
308 if (init_mode != ios_base::__default_mode)
309 _M_openmode = init_mode;
310 else
311 _M_openmode = _get_osfflags(-1, __id);
312
313 _M_is_open = true;
314 _M_file_id = __id;
315 _M_should_close = false;
316 _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
317
318 return true;
319 #else
320 (void)__id;
321 (void)init_mode; // dwa 4/27/00 - suppress unused parameter warning
322
323 // not available for the API
324 return false;
325
326 #endif
327 }
328
329 // Associated the filebuf with a file descriptor pointing to an already-
330 // open file. Mode is set to be consistent with the way that the file
331 // was opened.
_M_open(int file_no,ios_base::openmode init_mode)332 bool _Filebuf_base::_M_open(int file_no, ios_base::openmode init_mode) {
333 if (_M_is_open || file_no < 0)
334 return false;
335
336 #if (defined (_STLP_MSVC_LIB) && !defined (_STLP_WCE)) || \
337 (defined (__MINGW32__) && defined (__MSVCRT__)) || defined (__DMC__)
338
339 HANDLE oshandle = (HANDLE)_get_osfhandle(file_no);
340 if (oshandle == INVALID_STLP_FD)
341 return false;
342
343 if (init_mode != ios_base::__default_mode)
344 _M_openmode = init_mode;
345 else
346 _M_openmode = _get_osfflags(file_no, oshandle);
347
348 _M_file_id = oshandle;
349 _M_is_open = true;
350 _M_should_close = false;
351 _M_regular_file = _STLP_PRIV __is_regular_file(_M_file_id);
352 return true;
353 #else
354 _STLP_MARK_PARAMETER_AS_UNUSED(&init_mode)
355 // not available for the API
356 return false;
357 #endif
358 }
359
_M_close()360 bool _Filebuf_base::_M_close() {
361 if (!_M_is_open)
362 return false;
363
364 bool ok;
365
366 if (!_M_should_close)
367 ok = true;
368 else {
369 if (_M_file_id != INVALID_STLP_FD) {
370 ok = (CloseHandle(_M_file_id) != 0);
371 }
372 else {
373 ok = false;
374 }
375 }
376
377 _M_is_open = _M_should_close = false;
378 _M_openmode = 0;
379 return ok;
380 }
381
382
383 #define _STLP_LF 10
384 #define _STLP_CR 13
385 #define _STLP_CTRLZ 26
386
387 // Read up to n characters into a buffer. Return value is number of
388 // characters read.
_M_read(char * buf,ptrdiff_t n)389 ptrdiff_t _Filebuf_base::_M_read(char* buf, ptrdiff_t n) {
390 ptrdiff_t readen = 0;
391 //Here cast to size_t is safe as n cannot be negative.
392 size_t chunkSize = (min)(size_t(0xffffffff), __STATIC_CAST(size_t, n));
393 // The following, while validating that we are still able to extract chunkSize
394 // charaters to the buffer, avoids extraction of too small chunk of datas
395 // which would be counter performant.
396 while (__STATIC_CAST(size_t, (n - readen)) >= chunkSize) {
397 DWORD numberOfBytesRead;
398 ReadFile(_M_file_id, buf + readen, __STATIC_CAST(DWORD, chunkSize), &numberOfBytesRead, 0);
399
400 if (numberOfBytesRead == 0)
401 break;
402
403 if (!(_M_openmode & ios_base::binary)) {
404 // translate CR-LFs to LFs in the buffer
405 char *to = buf + readen;
406 char *from = to;
407 char *last = from + numberOfBytesRead - 1;
408 for (; from <= last && *from != _STLP_CTRLZ; ++from) {
409 if (*from != _STLP_CR)
410 *to++ = *from;
411 else { // found CR
412 if (from < last) { // not at buffer end
413 if (*(from + 1) != _STLP_LF)
414 *to++ = _STLP_CR;
415 }
416 else { // last char is CR, peek for LF
417 char peek = ' ';
418 DWORD NumberOfBytesPeeked;
419 ReadFile(_M_file_id, (LPVOID)&peek, 1, &NumberOfBytesPeeked, 0);
420 if (NumberOfBytesPeeked != 0) {
421 if (peek != _STLP_LF) { //not a <CR><LF> combination
422 *to++ = _STLP_CR;
423 if ((to < buf + n) && (peek != _STLP_CR))
424 //We have enough place to store peek and it is no a special
425 //_STLP_CR character, we can store it.
426 *to++ = peek;
427 else
428 SetFilePointer(_M_file_id, (LONG)-1, 0, FILE_CURRENT);
429 }
430 else {
431 // A <CR><LF> combination, we keep the <LF>:
432 *to++ = _STLP_LF;
433 }
434 }
435 else {
436 /* This case is tedious, we could
437 * - put peek back in the file but this would then generate an infinite loop
438 * - report an error as we don't know if in a future call to ReadFile we won't then
439 * get a <LF>. Doing so would make all files with a <CR> last an invalid file
440 * for STLport, a hard solution for STLport clients.
441 * - store the <CR> in the returned buffer, the chosen solution, even if in this
442 * case we could miss a <CR><LF> combination.
443 */
444 *to++ = _STLP_CR;
445 }
446 }
447 } // found CR
448 } // for
449 readen = to - buf;
450 // seek back to TEXT end of file if hit CTRL-Z
451 if (from <= last) { // terminated due to CTRLZ
452 SetFilePointer(_M_file_id, -(LONG)((last + 1) - from), 0, FILE_CURRENT);
453 break;
454 }
455 }
456 else
457 readen += numberOfBytesRead;
458 }
459 return readen;
460 }
461
462 // Write n characters from a buffer. Return value: true if we managed
463 // to write the entire buffer, false if we didn't.
_M_write(char * buf,ptrdiff_t n)464 bool _Filebuf_base::_M_write(char* buf, ptrdiff_t n) {
465 for (;;) {
466 ptrdiff_t written;
467
468 //In the following implementation we are going to cast most of the ptrdiff_t
469 //values in size_t to work with coherent unsigned values. Doing so make code
470 //more simple especially in the min function call.
471
472 // In append mode, every write does an implicit seek to the end
473 // of the file.
474 if (_M_openmode & ios_base::app)
475 _M_seek(0, ios_base::end);
476
477 if (_M_openmode & ios_base::binary) {
478 // binary mode
479 size_t bytes_to_write = (size_t)n;
480 DWORD NumberOfBytesWritten;
481 written = 0;
482 for (; bytes_to_write != 0;) {
483 WriteFile(_M_file_id, buf + written,
484 __STATIC_CAST(DWORD, (min)(size_t(0xffffffff), bytes_to_write)),
485 &NumberOfBytesWritten, 0);
486 if (NumberOfBytesWritten == 0)
487 return false;
488 bytes_to_write -= NumberOfBytesWritten;
489 written += NumberOfBytesWritten;
490 }
491 }
492 else {
493 char textbuf[_TEXTBUF_SIZE + 1]; // extra 1 in case LF at end
494 char * nextblock = buf, * ptrtextbuf = textbuf;
495 char * endtextbuf = textbuf + _TEXTBUF_SIZE;
496 char * endblock = buf + n;
497 ptrdiff_t nextblocksize = (min) (n, (ptrdiff_t)_TEXTBUF_SIZE);
498 char * nextlf;
499
500 while ( (nextblocksize > 0) &&
501 (nextlf = (char *)memchr(nextblock, _STLP_LF, nextblocksize)) != 0) {
502 ptrdiff_t linelength = nextlf - nextblock;
503 memcpy(ptrtextbuf, nextblock, linelength);
504 ptrtextbuf += linelength;
505 nextblock += (linelength + 1);
506 * ptrtextbuf ++ = _STLP_CR;
507 * ptrtextbuf ++ = _STLP_LF;
508 nextblocksize = (min) (ptrdiff_t(endblock - nextblock),
509 (max) (ptrdiff_t(0), ptrdiff_t(endtextbuf - ptrtextbuf)));
510 }
511 // write out what's left, > condition is here since for LF at the end ,
512 // endtextbuf may get < ptrtextbuf ...
513 if (nextblocksize > 0) {
514 memcpy(ptrtextbuf, nextblock, nextblocksize);
515 ptrtextbuf += nextblocksize;
516 nextblock += nextblocksize;
517 }
518 // now write out the translated buffer
519 char * writetextbuf = textbuf;
520 for (size_t NumberOfBytesToWrite = (size_t)(ptrtextbuf - textbuf);
521 NumberOfBytesToWrite;) {
522 DWORD NumberOfBytesWritten;
523 WriteFile((HANDLE)_M_file_id, writetextbuf,
524 __STATIC_CAST(DWORD, (min)(size_t(0xffffffff), NumberOfBytesToWrite)),
525 &NumberOfBytesWritten, 0);
526 if (!NumberOfBytesWritten) // write shortfall
527 return false;
528 writetextbuf += NumberOfBytesWritten;
529 NumberOfBytesToWrite -= NumberOfBytesWritten;
530 }
531 // count non-translated characters
532 written = (nextblock - buf);
533 }
534
535 if (n == written)
536 return true;
537 else if (written > 0 && written < n) {
538 n -= written;
539 buf += written;
540 }
541 else
542 return false;
543 }
544 }
545
546 // Wrapper for lseek or the like.
_M_seek(streamoff offset,ios_base::seekdir dir)547 streamoff _Filebuf_base::_M_seek(streamoff offset, ios_base::seekdir dir) {
548 streamoff result = -1;
549 int whence;
550
551 switch(dir) {
552 case ios_base::beg:
553 if (offset < 0 /* || offset > _M_file_size() */ )
554 return streamoff(-1);
555 whence = FILE_BEGIN;
556 break;
557 case ios_base::cur:
558 whence = FILE_CURRENT;
559 break;
560 case ios_base::end:
561 if (/* offset > 0 || */ -offset > _M_file_size() )
562 return streamoff(-1);
563 whence = FILE_END;
564 break;
565 default:
566 return streamoff(-1);
567 }
568
569 LARGE_INTEGER li;
570 li.QuadPart = offset;
571 li.LowPart = SetFilePointer(_M_file_id, li.LowPart, &li.HighPart, whence);
572 if (li.LowPart != INVALID_SET_FILE_POINTER || GetLastError() == NO_ERROR)
573 result = li.QuadPart;
574
575 return result;
576 }
577
578
579 // Attempts to memory-map len bytes of the current file, starting
580 // at position offset. Precondition: offset is a multiple of the
581 // page size. Postcondition: return value is a null pointer if the
582 // memory mapping failed. Otherwise the return value is a pointer to
583 // the memory-mapped file and the file position is set to offset.
_M_mmap(streamoff offset,streamoff len)584 void* _Filebuf_base::_M_mmap(streamoff offset, streamoff len) {
585 void* base;
586 _M_view_id = CreateFileMapping(_M_file_id, (PSECURITY_ATTRIBUTES)0 ,
587 PAGE_READONLY, 0 /* len >> 32 */ ,
588 0 /* len & 0xFFFFFFFF */ , // low-order DWORD of size
589 0);
590
591 if (_M_view_id) {
592 #if 0
593 /*
594 printf("view %x created from file %x, error = %d, size = %d, map_offset = %d map_len = %d\n",
595 _M_view_id, _M_file_id, GetLastError(),
596 (int)cur_filesize, ULL(offset) & 0xffffffff, len);
597 */
598 #endif
599 LARGE_INTEGER li;
600 li.QuadPart = offset;
601 base = MapViewOfFile(_M_view_id, FILE_MAP_READ, li.HighPart, li.LowPart,
602 #if !defined (__DMC__)
603 __STATIC_CAST(SIZE_T, len));
604 #else
605 __STATIC_CAST(DWORD, len));
606 #endif
607 // check if mapping succeded and is usable
608 if (base == 0 || _M_seek(offset + len, ios_base::beg) < 0) {
609 this->_M_unmap(base, len);
610 base = 0;
611 }
612 } else
613 base = 0;
614
615 return base;
616 }
617
_M_unmap(void * base,streamoff len)618 void _Filebuf_base::_M_unmap(void* base, streamoff len) {
619 // precondition : there is a valid mapping at the moment
620 if (base != NULL)
621 UnmapViewOfFile(base);
622 // destroy view handle as well
623 if (_M_view_id != NULL)
624 CloseHandle(_M_view_id);
625 _M_view_id = NULL;
626 (void)len; //unused variable
627 }
628
629 _STLP_END_NAMESPACE
630