15 #include "pandaFileStreamBuf.h" 16 #include "memoryHook.h" 18 #include "textEncoder.h" 20 #ifdef USE_PANDAFILESTREAM 23 #include <sys/types.h> 29 PandaFileStreamBuf::NewlineMode PandaFileStreamBuf::_newline_mode = NM_native;
31 static const size_t file_buffer_size = 4096;
39 PandaFileStreamBuf() {
41 _open_mode = (ios::openmode)0;
53 _buffer = (
char *)PANDA_MALLOC_ARRAY(file_buffer_size * 2);
54 char *ebuf = _buffer + file_buffer_size * 2;
55 char *mbuf = _buffer + file_buffer_size;
56 setg(_buffer, mbuf, mbuf);
65 char *m = b + (t - b) / 2;
80 ~PandaFileStreamBuf() {
83 PANDA_FREE_ARRAY(_buffer);
92 void PandaFileStreamBuf::
93 open(
const char *filename, ios::openmode mode) {
100 if (_open_mode & ios::app) {
102 _open_mode |= ios::out;
108 if (_open_mode & ios::in) {
109 access |= GENERIC_READ;
111 if (_open_mode & ios::out) {
112 access |= GENERIC_WRITE;
115 DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
117 DWORD creation_disposition = 0;
118 if ((_open_mode & (ios::trunc | ios::out)) == (ios::trunc | ios::out)) {
119 creation_disposition = CREATE_ALWAYS;
120 }
else if (_open_mode & ios::out) {
121 creation_disposition = OPEN_ALWAYS;
123 creation_disposition = OPEN_EXISTING;
128 if (!(_open_mode & ios::out)) {
129 flags |= FILE_ATTRIBUTE_READONLY;
132 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) 134 flags |= FILE_FLAG_OVERLAPPED;
141 _handle = CreateFileW(wfilename.c_str(), access, share_mode,
142 NULL, creation_disposition, flags, NULL);
143 if (_handle != INVALID_HANDLE_VALUE) {
152 if ((_open_mode & (ios::in | ios::out)) == (ios::in | ios::out)) {
153 flags |= O_RDWR | O_CREAT;
154 }
else if (_open_mode & ios::in) {
156 }
else if (_open_mode & ios::out) {
157 flags |= O_WRONLY | O_CREAT;
160 if (_open_mode & ios::app) {
164 if ((_open_mode & (ios::trunc | ios::out)) == (ios::trunc | ios::out)) {
168 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) 173 _fd = ::open(_filename.c_str(), flags, 0666);
174 while (_fd == -1 && errno == EAGAIN) {
176 _fd = ::open(_filename.c_str(), flags, 0666);
198 void PandaFileStreamBuf::
199 attach(
const char *filename, HANDLE handle, ios::openmode mode) {
202 _filename = filename;
206 if (_open_mode & ios::app) {
208 _open_mode |= ios::out;
212 if (_handle != INVALID_HANDLE_VALUE) {
231 void PandaFileStreamBuf::
232 attach(
const char *filename,
int fd, ios::openmode mode) {
235 _filename = filename;
239 if (_open_mode & ios::app) {
241 _open_mode |= ios::out;
257 bool PandaFileStreamBuf::
267 void PandaFileStreamBuf::
273 if (_handle != NULL) {
274 CloseHandle(_handle);
285 _open_mode = (ios::openmode)0;
290 pbump(pbase() - pptr());
291 gbump(egptr() - gptr());
299 streampos PandaFileStreamBuf::
300 seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
301 streampos result = -1;
303 if (!(_open_mode & ios::binary)) {
306 if (off != 0 || dir != ios::beg) {
316 if (which & ios::in) {
318 size_t n = egptr() - gptr();
322 streampos cur_pos = _gpos;
323 streampos new_pos = cur_pos;
328 new_pos = (streampos)off;
332 new_pos = (streampos)(cur_pos + off);
340 GetFileSizeEx(_handle, &li);
341 new_pos = (streampos)li.QuadPart + off;
346 off_t li = lseek(_fd, off, SEEK_END);
347 if (li == (
size_t)-1) {
350 new_pos = (size_t)li;
365 if (which & ios::out) {
367 size_t n = pptr() - pbase();
368 streampos cur_pos = _ppos + (streamoff)n;
369 streampos new_pos = cur_pos;
374 new_pos = (streampos)off;
378 new_pos = (streampos)(cur_pos + off);
386 GetFileSizeEx(_handle, &li);
387 new_pos = (streampos)li.QuadPart + off;
391 new_pos = lseek(_fd, off, SEEK_END);
392 if (new_pos == (streampos)-1) {
425 streampos PandaFileStreamBuf::
426 seekpos(streampos pos, ios_openmode which) {
427 return seekoff(pos, ios::beg, which);
436 int PandaFileStreamBuf::
440 size_t n = pptr() - pbase();
442 size_t wrote = write_chars(pbase(), n);
443 pbump(-(streamoff)wrote);
449 if (okflag && ch != EOF) {
450 if (pptr() != epptr()) {
472 int PandaFileStreamBuf::
474 size_t n = pptr() - pbase();
476 size_t wrote = write_chars(pbase(), n);
477 pbump(-(streamoff)wrote);
491 int PandaFileStreamBuf::
494 if (gptr() >= egptr()) {
498 size_t buffer_size = egptr() - eback();
499 gbump(-(streamoff)buffer_size);
501 size_t num_bytes = buffer_size;
502 size_t read_count = read_chars(gptr(), buffer_size);
504 if (read_count != num_bytes) {
506 if (read_count == 0) {
512 assert(read_count < num_bytes);
513 size_t delta = num_bytes - read_count;
514 memmove(gptr() + delta, gptr(), read_count);
519 return (
unsigned char)*gptr();
529 size_t PandaFileStreamBuf::
530 read_chars(
char *start,
size_t length) {
531 if (length == 0 || !_is_open) {
539 if (_open_mode & ios::binary) {
542 return read_chars_raw(start, length);
547 if (_newline_mode == NM_binary) {
549 return read_chars_raw(start, length);
552 char *buffer = (
char *)alloca(length);
557 read_length = length - 1;
558 if (_last_read_nl != 0) {
566 read_length = read_chars_raw(buffer, read_length);
567 final_length = decode_newlines(start, length, buffer, read_length);
571 }
while (read_length != 0 && final_length == 0);
582 size_t PandaFileStreamBuf::
583 write_chars(
const char *start,
size_t length) {
590 size_t n = egptr() - gptr();
596 if (_open_mode & ios::binary) {
599 return write_chars_raw(start, length);
605 NewlineMode this_newline_mode = _newline_mode;
606 if (this_newline_mode == NM_native) {
608 this_newline_mode = NM_msdos;
611 this_newline_mode = NM_unix;
615 if (this_newline_mode == NM_binary) {
616 return write_chars_raw(start, length);
619 size_t buffer_length = length;
620 if (this_newline_mode == NM_msdos) {
625 char *buffer = (
char *)alloca(buffer_length);
628 switch (this_newline_mode) {
630 write_length = encode_newlines_msdos(buffer, buffer_length, start, length);
634 write_length = encode_newlines_mac(buffer, buffer_length, start, length);
638 write_length = encode_newlines_unix(buffer, buffer_length, start, length);
642 if (write_length == write_chars_raw(buffer, write_length)) {
658 size_t PandaFileStreamBuf::
659 read_chars_raw(
char *start,
size_t length) {
666 OVERLAPPED overlapped;
667 memset(&overlapped, 0,
sizeof(overlapped));
669 gpos.QuadPart = _gpos;
670 overlapped.Offset = gpos.LowPart;
671 overlapped.OffsetHigh = gpos.HighPart;
673 DWORD bytes_read = 0;
674 BOOL success = ReadFile(_handle, start, length, &bytes_read, &overlapped);
677 DWORD error = GetLastError();
678 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
686 }
else if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) {
691 <<
"Error reading " << length
692 <<
" bytes from " << _filename <<
", windows error code 0x" << hex
693 << error << dec <<
".\n";
697 success = GetOverlappedResult(_handle, &overlapped, &bytes_read,
false);
704 if (lseek(_fd, _gpos, SEEK_SET) == -1) {
706 <<
"Error seeking to position " << _gpos <<
" in " << _filename <<
"\n";
710 int result = ::read(_fd, start, length);
712 if (errno == EAGAIN) {
716 <<
"Error reading " << length <<
" bytes from " << _filename <<
"\n";
719 result = ::read(_fd, start, length);
736 size_t PandaFileStreamBuf::
737 write_chars_raw(
const char *start,
size_t length) {
738 if (length == 0 || !_is_open) {
744 OVERLAPPED overlapped;
745 memset(&overlapped, 0,
sizeof(overlapped));
747 ppos.QuadPart = _ppos;
748 overlapped.Offset = ppos.LowPart;
749 overlapped.OffsetHigh = ppos.HighPart;
751 if (_open_mode & ios::app) {
752 overlapped.Offset = -1;
753 overlapped.OffsetHigh = -1;
756 DWORD bytes_written = 0;
757 BOOL success = WriteFile(_handle, start, length, &bytes_written, &overlapped);
760 DWORD error = GetLastError();
761 if (error == ERROR_IO_INCOMPLETE || error == ERROR_IO_PENDING) {
769 }
else if (error == ERROR_BROKEN_PIPE) {
771 cerr <<
"Pipe closed on " << _filename <<
"\n";
772 return bytes_written;
775 <<
"Error writing " << length
776 <<
" bytes to " << _filename <<
", windows error code 0x" << hex
777 << error << dec <<
". Disk full?\n";
778 return bytes_written;
781 success = GetOverlappedResult(_handle, &overlapped, &bytes_written,
false);
783 assert(bytes_written == length);
784 _ppos += bytes_written;
789 if (!(_open_mode & ios::app)) {
790 if (lseek(_fd, _ppos, SEEK_SET) == -1) {
792 <<
"Error seeking to position " << _ppos <<
" in " << _filename <<
"\n";
797 size_t remaining = length;
798 while (remaining > 0) {
799 int result = ::write(_fd, start, remaining);
801 if (errno == EAGAIN) {
805 <<
"Error writing " << remaining <<
" bytes to " << _filename <<
"\n";
806 return length - remaining;
832 size_t PandaFileStreamBuf::
833 decode_newlines(
char *dest,
size_t dest_length,
834 const char *source,
size_t source_length) {
835 const char *p = source;
838 if (source_length == 0) {
841 switch (_last_read_nl) {
845 assert(q < dest + dest_length);
854 while (p < source + source_length) {
855 assert(q < dest + dest_length);
858 switch (_last_read_nl) {
867 _last_read_nl =
'\n';
871 _last_read_nl =
'\n';
877 switch (_last_read_nl) {
886 _last_read_nl =
'\r';
890 _last_read_nl =
'\r';
896 switch (_last_read_nl) {
906 assert(q < dest + dest_length);
925 size_t PandaFileStreamBuf::
926 encode_newlines_msdos(
char *dest,
size_t dest_length,
927 const char *source,
size_t source_length) {
928 const char *p = source;
931 while (p < source + source_length) {
932 assert(q < dest + dest_length);
936 assert(q < dest + dest_length);
968 size_t PandaFileStreamBuf::
969 encode_newlines_unix(
char *dest,
size_t dest_length,
970 const char *source,
size_t source_length) {
971 const char *p = source;
974 while (p < source + source_length) {
975 assert(q < dest + dest_length);
998 size_t PandaFileStreamBuf::
999 encode_newlines_mac(
char *dest,
size_t dest_length,
1000 const char *source,
size_t source_length) {
1001 const char *p = source;
1004 while (p < source + source_length) {
1005 assert(q < dest + dest_length);
1026 operator << (ostream &out, PandaFileStreamBuf::NewlineMode newline_mode) {
1027 switch (newline_mode) {
1028 case PandaFileStreamBuf::NM_native:
1029 return out <<
"native";
1031 case PandaFileStreamBuf::NM_binary:
1032 return out <<
"binary";
1034 case PandaFileStreamBuf::NM_msdos:
1035 return out <<
"msdos";
1037 case PandaFileStreamBuf::NM_unix:
1038 return out <<
"unix";
1040 case PandaFileStreamBuf::NM_mac:
1041 return out <<
"mac";
1045 <<
"Invalid NewlineMode value: " << (int)newline_mode <<
"\n";
1050 operator >> (istream &in, PandaFileStreamBuf::NewlineMode &newline_mode) {
1054 if (word ==
"native") {
1055 newline_mode = PandaFileStreamBuf::NM_native;
1056 }
else if (word ==
"binary") {
1057 newline_mode = PandaFileStreamBuf::NM_binary;
1058 }
else if (word ==
"msdos") {
1059 newline_mode = PandaFileStreamBuf::NM_msdos;
1060 }
else if (word ==
"unix") {
1061 newline_mode = PandaFileStreamBuf::NM_unix;
1062 }
else if (word ==
"mac") {
1063 newline_mode = PandaFileStreamBuf::NM_mac;
1066 <<
"Invalid NewlineMode value: " << word <<
"\n";
1067 newline_mode = PandaFileStreamBuf::NM_native;
1073 #endif // USE_PANDAFILESTREAM This class can be used to convert text between multiple representations, e.g.
const wstring & get_wtext() const
Returns the text associated with the TextEncoder, as a wide-character string.
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.
void set_text(const string &text)
Changes the text that is stored in the encoder.