19#ifdef USE_PANDAFILESTREAM
38PandaFileStreamBuf::NewlineMode PandaFileStreamBuf::_newline_mode = NM_native;
40static const size_t file_buffer_size = 4096;
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);
95void PandaFileStreamBuf::
96open(
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;
141 encoder.
set_encoding(Filename::get_filesystem_encoding());
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);
197void PandaFileStreamBuf::
198attach(
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) {
226void PandaFileStreamBuf::
227attach(
const char *filename,
int fd, ios::openmode mode) {
230 _filename = filename;
234 if (_open_mode & ios::app) {
236 _open_mode |= ios::out;
250bool PandaFileStreamBuf::
258void PandaFileStreamBuf::
264 if (_handle !=
nullptr) {
265 CloseHandle(_handle);
270 if (::close(_fd) < 0) {
274 char *str = (
char *)alloca(_filename.size() + 32);
275 sprintf(str,
"close(%d \"%s\")", _fd, _filename.c_str());
284 _open_mode = (ios::openmode)0;
289 pbump(pbase() - pptr());
290 gbump(egptr() - gptr());
296streampos PandaFileStreamBuf::
297seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
298 streampos result = -1;
300 if (!(_open_mode & ios::binary)) {
303 if (off != 0 || dir != ios::beg) {
313 if (which & ios::in) {
315 size_t n = egptr() - gptr();
319 streampos cur_pos = _gpos;
320 streampos new_pos = cur_pos;
325 new_pos = (streampos)off;
329 new_pos = (streampos)(cur_pos + off);
337 GetFileSizeEx(_handle, &li);
338 new_pos = (streampos)li.QuadPart + off;
343 off_t li = lseek(_fd, off, SEEK_END);
344 if (li == (off_t)-1 || (
sizeof(off_t) == 8 && li == 0x7fffffffffffffff)) {
347 new_pos = (size_t)li;
362 if (which & ios::out) {
364 size_t n = pptr() - pbase();
365 streampos cur_pos = _ppos + (streamoff)n;
366 streampos new_pos = cur_pos;
371 new_pos = (streampos)off;
375 new_pos = (streampos)(cur_pos + off);
383 GetFileSizeEx(_handle, &li);
384 new_pos = (streampos)li.QuadPart + off;
388 new_pos = lseek(_fd, off, SEEK_END);
389 if (new_pos == (streampos)-1) {
417streampos PandaFileStreamBuf::
418seekpos(streampos pos, ios_openmode which) {
419 return seekoff(pos, ios::beg, which);
426int PandaFileStreamBuf::
430 size_t n = pptr() - pbase();
432 size_t wrote = write_chars(pbase(), n);
433 pbump(-(streamoff)wrote);
439 if (okflag && ch != EOF) {
440 if (pptr() != epptr()) {
460int PandaFileStreamBuf::
462 size_t n = pptr() - pbase();
464 size_t wrote = write_chars(pbase(), n);
465 pbump(-(streamoff)wrote);
477int PandaFileStreamBuf::
480 if (gptr() >= egptr()) {
484 size_t buffer_size = egptr() - eback();
485 gbump(-(streamoff)buffer_size);
487 size_t num_bytes = buffer_size;
488 size_t read_count = read_chars(gptr(), buffer_size);
490 if (read_count != num_bytes) {
492 if (read_count == 0) {
498 assert(read_count < num_bytes);
499 size_t delta = num_bytes - read_count;
500 memmove(gptr() + delta, gptr(), read_count);
505 return (
unsigned char)*gptr();
512size_t PandaFileStreamBuf::
513read_chars(
char *start,
size_t length) {
514 if (length == 0 || !_is_open) {
522 if (_open_mode & ios::binary) {
524 return read_chars_raw(start, length);
529 if (_newline_mode == NM_binary) {
531 return read_chars_raw(start, length);
534 char *buffer = (
char *)alloca(length);
539 read_length = length - 1;
540 if (_last_read_nl != 0) {
548 read_length = read_chars_raw(buffer, read_length);
549 final_length = decode_newlines(start, length, buffer, read_length);
553 }
while (read_length != 0 && final_length == 0);
561size_t PandaFileStreamBuf::
562write_chars(
const char *start,
size_t length) {
569 size_t n = egptr() - gptr();
575 if (_open_mode & ios::binary) {
577 return write_chars_raw(start, length);
583 NewlineMode this_newline_mode = _newline_mode;
584 if (this_newline_mode == NM_native) {
586 this_newline_mode = NM_msdos;
589 this_newline_mode = NM_unix;
593 if (this_newline_mode == NM_binary) {
594 return write_chars_raw(start, length);
597 size_t buffer_length = length;
598 if (this_newline_mode == NM_msdos) {
603 char *buffer = (
char *)alloca(buffer_length);
606 switch (this_newline_mode) {
608 write_length = encode_newlines_msdos(buffer, buffer_length, start, length);
612 write_length = encode_newlines_mac(buffer, buffer_length, start, length);
616 write_length = encode_newlines_unix(buffer, buffer_length, start, length);
620 if (write_length == write_chars_raw(buffer, write_length)) {
633size_t PandaFileStreamBuf::
634read_chars_raw(
char *start,
size_t length) {
641 OVERLAPPED overlapped;
642 memset(&overlapped, 0,
sizeof(overlapped));
644 gpos.QuadPart = _gpos;
645 overlapped.Offset = gpos.LowPart;
646 overlapped.OffsetHigh = gpos.HighPart;
648 DWORD bytes_read = 0;
649 BOOL success = ReadFile(_handle, start, length, &bytes_read, &overlapped);
652 DWORD error = GetLastError();
653 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
661 }
else if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) {
666 <<
"Error reading " << length
667 <<
" bytes from " << _filename <<
", windows error code 0x" << hex
668 << error << dec <<
".\n";
672 success = GetOverlappedResult(_handle, &overlapped, &bytes_read,
false);
679 if (lseek(_fd, _gpos, SEEK_SET) == -1) {
681 <<
"Error seeking to position " << _gpos <<
" in " << _filename <<
"\n";
685 int result = ::read(_fd, start, length);
687 if (errno == EAGAIN) {
691 <<
"Error reading " << length <<
" bytes from " << _filename <<
"\n";
694 result = ::read(_fd, start, length);
709size_t PandaFileStreamBuf::
710write_chars_raw(
const char *start,
size_t length) {
711 if (length == 0 || !_is_open) {
717 OVERLAPPED overlapped;
718 memset(&overlapped, 0,
sizeof(overlapped));
720 ppos.QuadPart = _ppos;
721 overlapped.Offset = ppos.LowPart;
722 overlapped.OffsetHigh = ppos.HighPart;
724 if (_open_mode & ios::app) {
725 overlapped.Offset = -1;
726 overlapped.OffsetHigh = -1;
729 DWORD bytes_written = 0;
730 BOOL success = WriteFile(_handle, start, length, &bytes_written, &overlapped);
733 DWORD error = GetLastError();
734 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
742 }
else if (error == ERROR_BROKEN_PIPE) {
744 cerr <<
"Pipe closed on " << _filename <<
"\n";
745 return bytes_written;
748 <<
"Error writing " << length
749 <<
" bytes to " << _filename <<
", windows error code 0x" << hex
750 << error << dec <<
". Disk full?\n";
751 return bytes_written;
754 success = GetOverlappedResult(_handle, &overlapped, &bytes_written,
false);
756 assert(bytes_written == length);
757 _ppos += bytes_written;
762 if (!(_open_mode & ios::app)) {
763 if (lseek(_fd, _ppos, SEEK_SET) == -1) {
765 <<
"Error seeking to position " << _ppos <<
" in " << _filename <<
"\n";
770 size_t remaining = length;
771 while (remaining > 0) {
772 int result = ::write(_fd, start, remaining);
774 if (errno == EAGAIN) {
778 <<
"Error writing " << remaining <<
" bytes to " << _filename <<
"\n";
779 return length - remaining;
801size_t PandaFileStreamBuf::
802decode_newlines(
char *dest,
size_t dest_length,
803 const char *source,
size_t source_length) {
804 const char *p = source;
807 if (source_length == 0) {
809 switch (_last_read_nl) {
813 assert(q < dest + dest_length);
822 while (p < source + source_length) {
823 assert(q < dest + dest_length);
826 switch (_last_read_nl) {
835 _last_read_nl =
'\n';
839 _last_read_nl =
'\n';
845 switch (_last_read_nl) {
854 _last_read_nl =
'\r';
858 _last_read_nl =
'\r';
864 switch (_last_read_nl) {
874 assert(q < dest + dest_length);
891size_t PandaFileStreamBuf::
892encode_newlines_msdos(
char *dest,
size_t dest_length,
893 const char *source,
size_t source_length) {
894 const char *p = source;
897 while (p < source + source_length) {
898 assert(q < dest + dest_length);
902 assert(q < dest + dest_length);
931size_t PandaFileStreamBuf::
932encode_newlines_unix(
char *dest,
size_t dest_length,
933 const char *source,
size_t source_length) {
934 const char *p = source;
937 while (p < source + source_length) {
938 assert(q < dest + dest_length);
959size_t PandaFileStreamBuf::
960encode_newlines_mac(
char *dest,
size_t dest_length,
961 const char *source,
size_t source_length) {
962 const char *p = source;
965 while (p < source + source_length) {
966 assert(q < dest + dest_length);
987operator << (ostream &out, PandaFileStreamBuf::NewlineMode newline_mode) {
988 switch (newline_mode) {
989 case PandaFileStreamBuf::NM_native:
990 return out <<
"native";
992 case PandaFileStreamBuf::NM_binary:
993 return out <<
"binary";
995 case PandaFileStreamBuf::NM_msdos:
996 return out <<
"msdos";
998 case PandaFileStreamBuf::NM_unix:
999 return out <<
"unix";
1001 case PandaFileStreamBuf::NM_mac:
1002 return out <<
"mac";
1006 <<
"Invalid NewlineMode value: " << (int)newline_mode <<
"\n";
1011operator >> (istream &in, PandaFileStreamBuf::NewlineMode &newline_mode) {
1015 if (word ==
"native") {
1016 newline_mode = PandaFileStreamBuf::NM_native;
1017 }
else if (word ==
"binary") {
1018 newline_mode = PandaFileStreamBuf::NM_binary;
1019 }
else if (word ==
"msdos") {
1020 newline_mode = PandaFileStreamBuf::NM_msdos;
1021 }
else if (word ==
"unix") {
1022 newline_mode = PandaFileStreamBuf::NM_unix;
1023 }
else if (word ==
"mac") {
1024 newline_mode = PandaFileStreamBuf::NM_mac;
1027 <<
"Invalid NewlineMode value: " << word <<
"\n";
1028 newline_mode = PandaFileStreamBuf::NM_native;
This class can be used to convert text between multiple representations, e.g.
set_text
Changes the text that is stored in the encoder.
void set_encoding(Encoding encoding)
Specifies how the string set via set_text() is to be interpreted.
const std::wstring & get_wtext() const
Returns the text associated with the TextEncoder, as a wide-character string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.