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 PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class can be used to convert text between multiple representations, e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_text
Changes the text that is stored in the encoder.
static TextEncoder::Encoding get_filesystem_encoding()
Specifies the default encoding to be used for all subsequent Filenames objects.
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.