19 #ifdef USE_PANDAFILESTREAM
22 #include <sys/types.h>
38 PandaFileStreamBuf::NewlineMode PandaFileStreamBuf::_newline_mode = NM_native;
40 static const size_t file_buffer_size = 4096;
46 PandaFileStreamBuf() {
48 _open_mode = (ios::openmode)0;
60 _buffer = (
char *)PANDA_MALLOC_ARRAY(file_buffer_size * 2);
61 char *ebuf = _buffer + file_buffer_size * 2;
62 char *mbuf = _buffer + file_buffer_size;
63 setg(_buffer, mbuf, mbuf);
72 char *m = b + (t - b) / 2;
85 ~PandaFileStreamBuf() {
88 PANDA_FREE_ARRAY(_buffer);
95 void PandaFileStreamBuf::
96 open(
const char *filename, ios::openmode mode) {
103 if (_open_mode & ios::app) {
105 _open_mode |= ios::out;
111 if (_open_mode & ios::in) {
112 access |= GENERIC_READ;
114 if (_open_mode & ios::out) {
115 access |= GENERIC_WRITE;
118 DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
120 DWORD creation_disposition = 0;
121 if ((_open_mode & (ios::trunc | ios::out)) == (ios::trunc | ios::out)) {
122 creation_disposition = CREATE_ALWAYS;
123 }
else if (_open_mode & ios::out) {
124 creation_disposition = OPEN_ALWAYS;
126 creation_disposition = OPEN_EXISTING;
131 if (!(_open_mode & ios::out)) {
132 flags |= FILE_ATTRIBUTE_READONLY;
135 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
137 flags |= FILE_FLAG_OVERLAPPED;
143 std::wstring wfilename = encoder.
get_wtext();
144 _handle = CreateFileW(wfilename.c_str(), access, share_mode,
145 nullptr, creation_disposition, flags,
nullptr);
146 if (_handle != INVALID_HANDLE_VALUE) {
155 if ((_open_mode & (ios::in | ios::out)) == (ios::in | ios::out)) {
156 flags |= O_RDWR | O_CREAT;
157 }
else if (_open_mode & ios::in) {
159 }
else if (_open_mode & ios::out) {
160 flags |= O_WRONLY | O_CREAT;
163 if (_open_mode & ios::app) {
167 if ((_open_mode & (ios::trunc | ios::out)) == (ios::trunc | ios::out)) {
171 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
176 _fd = ::open(_filename.c_str(), flags, 0666);
177 while (_fd == -1 && errno == EAGAIN) {
179 _fd = ::open(_filename.c_str(), flags, 0666);
197 void PandaFileStreamBuf::
198 attach(
const char *filename, HANDLE handle, ios::openmode mode) {
201 _filename = filename;
205 if (_open_mode & ios::app) {
207 _open_mode |= ios::out;
211 if (_handle != INVALID_HANDLE_VALUE) {
226 void PandaFileStreamBuf::
227 attach(
const char *filename,
int fd, ios::openmode mode) {
230 _filename = filename;
234 if (_open_mode & ios::app) {
236 _open_mode |= ios::out;
250 bool PandaFileStreamBuf::
258 void PandaFileStreamBuf::
264 if (_handle !=
nullptr) {
265 CloseHandle(_handle);
276 _open_mode = (ios::openmode)0;
281 pbump(pbase() - pptr());
282 gbump(egptr() - gptr());
288 streampos PandaFileStreamBuf::
289 seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
290 streampos result = -1;
292 if (!(_open_mode & ios::binary)) {
295 if (off != 0 || dir != ios::beg) {
305 if (which & ios::in) {
307 size_t n = egptr() - gptr();
311 streampos cur_pos = _gpos;
312 streampos new_pos = cur_pos;
317 new_pos = (streampos)off;
321 new_pos = (streampos)(cur_pos + off);
329 GetFileSizeEx(_handle, &li);
330 new_pos = (streampos)li.QuadPart + off;
335 off_t li = lseek(_fd, off, SEEK_END);
336 if (li == (off_t)-1) {
339 new_pos = (size_t)li;
354 if (which & ios::out) {
356 size_t n = pptr() - pbase();
357 streampos cur_pos = _ppos + (streamoff)n;
358 streampos new_pos = cur_pos;
363 new_pos = (streampos)off;
367 new_pos = (streampos)(cur_pos + off);
375 GetFileSizeEx(_handle, &li);
376 new_pos = (streampos)li.QuadPart + off;
380 new_pos = lseek(_fd, off, SEEK_END);
381 if (new_pos == (streampos)-1) {
409 streampos PandaFileStreamBuf::
410 seekpos(streampos pos, ios_openmode which) {
411 return seekoff(pos, ios::beg, which);
418 int PandaFileStreamBuf::
422 size_t n = pptr() - pbase();
424 size_t wrote = write_chars(pbase(), n);
425 pbump(-(streamoff)wrote);
431 if (okflag && ch != EOF) {
432 if (pptr() != epptr()) {
452 int PandaFileStreamBuf::
454 size_t n = pptr() - pbase();
456 size_t wrote = write_chars(pbase(), n);
457 pbump(-(streamoff)wrote);
469 int PandaFileStreamBuf::
472 if (gptr() >= egptr()) {
476 size_t buffer_size = egptr() - eback();
477 gbump(-(streamoff)buffer_size);
479 size_t num_bytes = buffer_size;
480 size_t read_count = read_chars(gptr(), buffer_size);
482 if (read_count != num_bytes) {
484 if (read_count == 0) {
490 assert(read_count < num_bytes);
491 size_t delta = num_bytes - read_count;
492 memmove(gptr() + delta, gptr(), read_count);
497 return (
unsigned char)*gptr();
504 size_t PandaFileStreamBuf::
505 read_chars(
char *start,
size_t length) {
506 if (length == 0 || !_is_open) {
514 if (_open_mode & ios::binary) {
516 return read_chars_raw(start, length);
521 if (_newline_mode == NM_binary) {
523 return read_chars_raw(start, length);
526 char *buffer = (
char *)alloca(length);
531 read_length = length - 1;
532 if (_last_read_nl != 0) {
540 read_length = read_chars_raw(buffer, read_length);
541 final_length = decode_newlines(start, length, buffer, read_length);
545 }
while (read_length != 0 && final_length == 0);
553 size_t PandaFileStreamBuf::
554 write_chars(
const char *start,
size_t length) {
561 size_t n = egptr() - gptr();
567 if (_open_mode & ios::binary) {
569 return write_chars_raw(start, length);
575 NewlineMode this_newline_mode = _newline_mode;
576 if (this_newline_mode == NM_native) {
578 this_newline_mode = NM_msdos;
581 this_newline_mode = NM_unix;
585 if (this_newline_mode == NM_binary) {
586 return write_chars_raw(start, length);
589 size_t buffer_length = length;
590 if (this_newline_mode == NM_msdos) {
595 char *buffer = (
char *)alloca(buffer_length);
598 switch (this_newline_mode) {
600 write_length = encode_newlines_msdos(buffer, buffer_length, start, length);
604 write_length = encode_newlines_mac(buffer, buffer_length, start, length);
608 write_length = encode_newlines_unix(buffer, buffer_length, start, length);
612 if (write_length == write_chars_raw(buffer, write_length)) {
625 size_t PandaFileStreamBuf::
626 read_chars_raw(
char *start,
size_t length) {
633 OVERLAPPED overlapped;
634 memset(&overlapped, 0,
sizeof(overlapped));
636 gpos.QuadPart = _gpos;
637 overlapped.Offset = gpos.LowPart;
638 overlapped.OffsetHigh = gpos.HighPart;
640 DWORD bytes_read = 0;
641 BOOL success = ReadFile(_handle, start, length, &bytes_read, &overlapped);
644 DWORD error = GetLastError();
645 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
653 }
else if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) {
658 <<
"Error reading " << length
659 <<
" bytes from " << _filename <<
", windows error code 0x" << hex
660 << error << dec <<
".\n";
664 success = GetOverlappedResult(_handle, &overlapped, &bytes_read,
false);
671 if (lseek(_fd, _gpos, SEEK_SET) == -1) {
673 <<
"Error seeking to position " << _gpos <<
" in " << _filename <<
"\n";
677 int result = ::read(_fd, start, length);
679 if (errno == EAGAIN) {
683 <<
"Error reading " << length <<
" bytes from " << _filename <<
"\n";
686 result = ::read(_fd, start, length);
701 size_t PandaFileStreamBuf::
702 write_chars_raw(
const char *start,
size_t length) {
703 if (length == 0 || !_is_open) {
709 OVERLAPPED overlapped;
710 memset(&overlapped, 0,
sizeof(overlapped));
712 ppos.QuadPart = _ppos;
713 overlapped.Offset = ppos.LowPart;
714 overlapped.OffsetHigh = ppos.HighPart;
716 if (_open_mode & ios::app) {
717 overlapped.Offset = -1;
718 overlapped.OffsetHigh = -1;
721 DWORD bytes_written = 0;
722 BOOL success = WriteFile(_handle, start, length, &bytes_written, &overlapped);
725 DWORD error = GetLastError();
726 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
734 }
else if (error == ERROR_BROKEN_PIPE) {
736 cerr <<
"Pipe closed on " << _filename <<
"\n";
737 return bytes_written;
740 <<
"Error writing " << length
741 <<
" bytes to " << _filename <<
", windows error code 0x" << hex
742 << error << dec <<
". Disk full?\n";
743 return bytes_written;
746 success = GetOverlappedResult(_handle, &overlapped, &bytes_written,
false);
748 assert(bytes_written == length);
749 _ppos += bytes_written;
754 if (!(_open_mode & ios::app)) {
755 if (lseek(_fd, _ppos, SEEK_SET) == -1) {
757 <<
"Error seeking to position " << _ppos <<
" in " << _filename <<
"\n";
762 size_t remaining = length;
763 while (remaining > 0) {
764 int result = ::write(_fd, start, remaining);
766 if (errno == EAGAIN) {
770 <<
"Error writing " << remaining <<
" bytes to " << _filename <<
"\n";
771 return length - remaining;
793 size_t PandaFileStreamBuf::
794 decode_newlines(
char *dest,
size_t dest_length,
795 const char *source,
size_t source_length) {
796 const char *p = source;
799 if (source_length == 0) {
801 switch (_last_read_nl) {
805 assert(q < dest + dest_length);
814 while (p < source + source_length) {
815 assert(q < dest + dest_length);
818 switch (_last_read_nl) {
827 _last_read_nl =
'\n';
831 _last_read_nl =
'\n';
837 switch (_last_read_nl) {
846 _last_read_nl =
'\r';
850 _last_read_nl =
'\r';
856 switch (_last_read_nl) {
866 assert(q < dest + dest_length);
883 size_t PandaFileStreamBuf::
884 encode_newlines_msdos(
char *dest,
size_t dest_length,
885 const char *source,
size_t source_length) {
886 const char *p = source;
889 while (p < source + source_length) {
890 assert(q < dest + dest_length);
894 assert(q < dest + dest_length);
923 size_t PandaFileStreamBuf::
924 encode_newlines_unix(
char *dest,
size_t dest_length,
925 const char *source,
size_t source_length) {
926 const char *p = source;
929 while (p < source + source_length) {
930 assert(q < dest + dest_length);
951 size_t PandaFileStreamBuf::
952 encode_newlines_mac(
char *dest,
size_t dest_length,
953 const char *source,
size_t source_length) {
954 const char *p = source;
957 while (p < source + source_length) {
958 assert(q < dest + dest_length);
979 operator << (ostream &out, PandaFileStreamBuf::NewlineMode newline_mode) {
980 switch (newline_mode) {
981 case PandaFileStreamBuf::NM_native:
982 return out <<
"native";
984 case PandaFileStreamBuf::NM_binary:
985 return out <<
"binary";
987 case PandaFileStreamBuf::NM_msdos:
988 return out <<
"msdos";
990 case PandaFileStreamBuf::NM_unix:
991 return out <<
"unix";
993 case PandaFileStreamBuf::NM_mac:
998 <<
"Invalid NewlineMode value: " << (int)newline_mode <<
"\n";
1003 operator >> (istream &in, PandaFileStreamBuf::NewlineMode &newline_mode) {
1007 if (word ==
"native") {
1008 newline_mode = PandaFileStreamBuf::NM_native;
1009 }
else if (word ==
"binary") {
1010 newline_mode = PandaFileStreamBuf::NM_binary;
1011 }
else if (word ==
"msdos") {
1012 newline_mode = PandaFileStreamBuf::NM_msdos;
1013 }
else if (word ==
"unix") {
1014 newline_mode = PandaFileStreamBuf::NM_unix;
1015 }
else if (word ==
"mac") {
1016 newline_mode = PandaFileStreamBuf::NM_mac;
1019 <<
"Invalid NewlineMode value: " << word <<
"\n";
1020 newline_mode = PandaFileStreamBuf::NM_native;
1026 #endif // USE_PANDAFILESTREAM