1 /***************************************************************************
2 io.cpp - GDL classes for file io
3 -------------------
4 begin : July 22 2002
5 copyright : (C) 2002 by Marc Schellens
6 email : m_schellens@users.sf.net
7 ***************************************************************************/
8
9 /* *************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "includefirst.hpp"
19
20 #include <cstdio> // std::remove(...)
21
22 #include "objects.hpp"
23 #include "io.hpp"
24 #ifdef __MINGW32__
25 #include <unistd.h> // for close()
26 #endif
27
28 #if defined(_WIN32) && !defined(__CYGWIN__)
29 #define NS_INT16SZ 2
30 #define NS_INADDRSZ 4
31 #define NS_IN6ADDRSZ 16
32 #ifndef EAFNOSUPPORT
33 #define EAFNOSUPPORT 9901
34 #endif
35
inet_pton4(const char * src,unsigned char * dst)36 static int inet_pton4(const char *src, unsigned char *dst) {
37 static const char digits[] = "0123456789";
38 int saw_digit, octets, ch;
39 unsigned char tmp[NS_INADDRSZ], *tp;
40
41 saw_digit = 0;
42 octets = 0;
43 *(tp = tmp) = 0;
44 while ((ch = *src++) != ' ') {
45 const char *pch;
46
47 if ((pch = strchr(digits, ch)) != NULL) {
48 unsigned int iNew = (unsigned int) (*tp * 10 + (pch - digits));
49
50 if (iNew > 255) return (0);
51 *tp = iNew;
52 if (!saw_digit) {
53 if (++octets > 4) return (0);
54 saw_digit = 1;
55 }
56 } else if (ch == '.' && saw_digit) {
57 if (octets == 4) return (0);
58 *++tp = 0;
59 saw_digit = 0;
60 } else {
61 return (0);
62 }
63 }
64
65 if (octets < 4) return (0);
66
67 memcpy(dst, tmp, NS_INADDRSZ);
68
69 return (1);
70 }
71
inet_pton6(const char * src,unsigned char * dst)72 static int inet_pton6(const char *src, unsigned char * dst) {
73 static const char xdigits_l[] = "0123456789abcdef",
74 xdigits_u[] = "0123456789ABCDEF";
75 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
76 const char *xdigits, *curtok;
77 int ch, saw_xdigit;
78 unsigned int val;
79
80 memset((tp = tmp), ' ', NS_IN6ADDRSZ);
81 endp = tp + NS_IN6ADDRSZ;
82 colonp = NULL;
83
84 // Leading :: requires some special handling.
85 if (*src == ':' && *++src != ':') return (0);
86
87 curtok = src;
88 saw_xdigit = 0;
89 val = 0;
90 while ((ch = *src++) != ' ') {
91 const char *pch;
92
93 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
94 pch = strchr((xdigits = xdigits_u), ch);
95
96 if (pch != NULL) {
97 val <<= 4;
98 val |= (pch - xdigits);
99 if (val > 0xffff) return (0);
100 saw_xdigit = 1;
101 continue;
102 }
103
104 if (ch == ':') {
105 curtok = src;
106 if (!saw_xdigit) {
107 if (colonp) return (0);
108 colonp = tp;
109 continue;
110 }
111
112 if (tp + NS_INT16SZ > endp) return (0);
113
114 *tp++ = (unsigned char) (val >> 8) & 0xff;
115 *tp++ = (unsigned char) val & 0xff;
116 saw_xdigit = 0;
117 val = 0;
118 continue;
119 }
120
121 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) {
122 tp += NS_INADDRSZ;
123 saw_xdigit = 0;
124 break; /* ' ' was seen by inet_pton4(). */
125 }
126 return (0);
127 }
128
129 if (saw_xdigit) {
130 if (tp + NS_INT16SZ > endp) return (0);
131
132 *tp++ = (unsigned char) (val >> 8) & 0xff;
133 *tp++ = (unsigned char) val & 0xff;
134 }
135
136 if (colonp != NULL) {
137 // Since some memmove()'s erroneously fail to handle overlapping regions, we'll do the shift by hand.
138 const int n = (int) (tp - colonp);
139 int i;
140
141 for (i = 1; i <= n; i++) {
142 endp[-i] = colonp[n - i];
143 colonp[n - i] = 0;
144 }
145 tp = endp;
146 }
147
148 if (tp != endp) return (0);
149
150 memcpy(dst, tmp, NS_IN6ADDRSZ);
151 return (1);
152 }
153
inet_pton(int af,const char * src,void * dst)154 int inet_pton(int af, const char *src, void *dst) {
155 switch (af) {
156 case AF_INET:
157 return inet_pton4(src, (unsigned char *) dst);
158 case AF_INET6:
159 return inet_pton6(src, (unsigned char *) dst);
160 default:
161 errno = EAFNOSUPPORT;
162 return (-1);
163 }
164 }
165 // This source code is from http://blog.naver.com/PostView.nhn?blogId=websearch&logNo=70089324416&parentCategoryNo=4&viewDate=¤tPage=1&listtype=0
166 #endif
167
168
169 using namespace std;
170
StreamInfo(ios * searchStream)171 const string StreamInfo(ios* searchStream) {
172 if (dynamic_cast<istringstream*> (searchStream) != NULL)
173 return "Unit: 0, <stdin> (redirected)";
174
175 if (searchStream == &cin) return "Unit: 0, <stdin>";
176 if (searchStream == &cout) return "Unit: -1, <stdout>";
177 if (searchStream == &cerr) return "Unit: -2, <stderr>";
178 for (SizeT i = 0; i < fileUnits.size(); i++) {
179 if (fileUnits[ i].anyStream != NULL && fileUnits[ i].anyStream->FStream() == searchStream) {
180 return "Unit: " + i2s(i + 1) + ", File: " + fileUnits[ i].Name();
181 }
182 }
183 return "Internal error: Stream not found.";
184 }
185
Close()186 void AnyStream::Close() {
187 if (fStream != NULL && fStream->is_open()) {
188 fStream->close();
189 fStream->clear();
190 }
191 if (igzStream != NULL && igzStream->rdbuf()->is_open()) {
192 igzStream->close();
193 igzStream->clear();
194 }
195 if (ogzStream != NULL && ogzStream->rdbuf()->is_open()) {
196 ogzStream->close();
197 ogzStream->clear();
198 }
199 }
200
Open(const std::string & name_,ios_base::openmode mode_,bool compress_)201 void AnyStream::Open(const std::string& name_,
202 ios_base::openmode mode_, bool compress_) {
203 if (compress_) {
204
205 delete fStream;
206 fStream = NULL;
207
208 if ((mode_ & std::ios::out)) {
209 if (ogzStream == NULL)
210 ogzStream = new ogzstream();
211
212 ogzStream->open(name_.c_str(), mode_ & ~std::ios::in);
213
214 if (ogzStream->fail()) {
215 delete ogzStream;
216 ogzStream = NULL;
217 throw GDLIOException("Error opening compressed file for output.");
218 }
219 } else {
220 delete ogzStream;
221 ogzStream = NULL;
222 }
223 if ((mode_ & std::ios::in) && !(mode_ & std::ios::out)) {
224 if (igzStream == NULL)
225 igzStream = new igzstream();
226
227 igzStream->open(name_.c_str(), mode_ & ~std::ios::out);
228
229 if (igzStream->fail()) {
230 delete igzStream;
231 igzStream = NULL;
232 throw GDLIOException("Error opening compressed file for input.");
233 }
234 } else {
235 delete igzStream;
236 igzStream = NULL;
237 }
238 } else {
239 delete igzStream;
240 igzStream = NULL;
241 delete ogzStream;
242 ogzStream = NULL;
243
244 if (fStream == NULL)
245 fStream = new fstream();
246
247 fStream->open(name_.c_str(), mode_);
248
249 if (fStream->fail()) {
250 delete fStream;
251 fStream = NULL;
252 if (((mode_ | ios_base::in) != 0) && ((mode_ | ios_base::out) == 0))
253 throw GDLIOException(-265, "Error opening file for reading.");
254 throw GDLIOException(-1, "Error opening file.");
255 }
256 }
257 }
258
ClearEof()259 void AnyStream::ClearEof() {
260 if (fStream && fStream->eof()) fStream->clear();
261 if (igzStream && igzStream->eof()) igzStream->clear();
262 if (ogzStream && ogzStream->eof()) ogzStream->clear();
263 }
264
Write(char * buf,std::streamsize nBytes)265 void AnyStream::Write(char* buf, std::streamsize nBytes) {
266 if (fStream != NULL) {
267 fStream->write(buf, nBytes);
268 } else if (ogzStream != NULL) {
269 ogzStream->write(buf, nBytes);
270 } else assert(0);
271 }
272
Read(char * buf,std::streamsize nBytes)273 void AnyStream::Read(char* buf, std::streamsize nBytes) {
274 if (fStream != NULL) {
275 fStream->read(buf, nBytes);
276 } else if (igzStream != NULL) {
277 igzStream->read(buf, nBytes);
278 } else assert(0);
279 }
Gcount()280 std::streamsize AnyStream::Gcount() {
281 if (fStream != NULL) {
282 return fStream->gcount();
283 } else if (igzStream != NULL) {
284 return igzStream->gcount();
285 } else assert(0);
286 throw; // getting rid of compiler warning
287 }
288
Good()289 bool AnyStream::Good() {
290 if (fStream != NULL)
291 return fStream->good();
292 else if (igzStream != NULL && ogzStream != NULL)
293 return igzStream->good() && ogzStream->good();
294 else if (igzStream != NULL)
295 return igzStream->good();
296 else if (ogzStream != NULL)
297 return ogzStream->good();
298 else {
299 assert(false);
300 throw; // getting rid of compiler warning
301 }
302 }
303
EofRaw()304 bool AnyStream::EofRaw() {
305 if (fStream != NULL) {
306 return fStream->eof();
307 }
308 if (igzStream != NULL) {
309 return igzStream->eof();
310 }
311 return true;
312 }
313
SeekEof()314 void AnyStream::SeekEof() {
315 if (fStream == NULL && igzStream == NULL && ogzStream == NULL)
316 throw GDLException("Inner file unit is not open.");
317
318 if (fStream != NULL) {
319 fStream->seekp(0, std::ios_base::end);
320 fStream->seekg(0, std::ios_base::end);
321 } else if (igzStream != NULL) {
322 igzStream->seekg(0, std::ios_base::end);
323 } else if (ogzStream != NULL) {
324 ogzStream->seekp(0, std::ios_base::end);
325 }
326 }
327
Eof()328 bool AnyStream::Eof() {
329 if (fStream == NULL && igzStream == NULL && ogzStream == NULL)
330 throw GDLException("Inner file unit is not open.");
331
332 if (fStream != NULL) {
333 fStream->clear(); // clear old EOF
334
335 fStream->peek(); // trigger EOF if at EOF
336
337 return fStream->eof();
338 }
339 if (igzStream != NULL) {
340 igzStream->clear(); // clear old EOF
341
342 igzStream->peek(); // trigger EOF if at EOF
343
344 return igzStream->eof();
345 }
346 return true;
347 }
348
Seek(std::streampos pos)349 void AnyStream::Seek(std::streampos pos) {
350 if (fStream == NULL && igzStream == NULL && ogzStream == NULL)
351 throw GDLException("inner file unit is not open.");
352
353 if (fStream != NULL) {
354 if (fStream->eof())
355 fStream->clear();
356
357 fStream->rdbuf()->pubseekpos(pos, std::ios_base::in | std::ios_base::out);
358 }
359 if (igzStream != NULL) {
360 if (igzStream->eof())
361 igzStream->clear();
362
363 igzStream->seekg(pos);
364 // igzStream->rdbuf()->pubseekpos( pos, std::ios_base::in);
365 }
366 if (ogzStream != NULL) {
367 if (ogzStream->eof())
368 ogzStream->clear();
369
370 ogzStream->seekp(pos);
371 // ogzStream->rdbuf()->pubseekpos( pos, std::ios_base::out);
372 }
373 }
374
Skip(std::streampos pos,bool doThrow)375 DLong64 AnyStream::Skip(std::streampos pos, bool doThrow) {
376 if (fStream == NULL && igzStream == NULL && ogzStream == NULL)
377 throw GDLException("inner file unit is not open.");
378
379 if (fStream != NULL) {
380 if (fStream->eof())
381 fStream->clear();
382
383 std::streampos cur=fStream->tellg();
384 fStream->ignore(pos);
385 if ( doThrow && fStream->eof()) throw GDLException("End of file encountered.");
386 DLong64 ret=fStream->tellg()-cur;
387 return ret;
388 }
389 if (igzStream != NULL) {
390 if (igzStream->eof())
391 igzStream->clear();
392
393 std::streampos cur=igzStream->tellg();
394 igzStream->ignore(pos);
395 if ( doThrow && igzStream->eof()) throw GDLException("End of file encountered.");
396 DLong64 ret=igzStream->tellg()-cur;
397 return ret;
398 }
399 return 0;
400 }
401
SkipLines(DLong nlines,bool doThrow)402 DLong AnyStream::SkipLines(DLong nlines, bool doThrow) {
403 if (fStream == NULL && igzStream == NULL && ogzStream == NULL)
404 throw GDLException("inner file unit is not open.");
405 if (fStream != NULL) {
406 if (fStream->eof())
407 fStream->clear();
408 DLong i = 0;
409 for (; i < nlines; ++i) {
410 fStream->ignore(std::numeric_limits<ptrdiff_t>::max(), '\n');
411 if (fStream->eof()) {
412 if (doThrow) throw GDLException("End of file encountered.");
413 else break;
414 }
415 }
416 return i;
417 }
418 if (igzStream != NULL) {
419 if (igzStream->eof())
420 igzStream->clear();
421 DLong i = 0;
422 for (; i < nlines; ++i) {
423 igzStream->ignore(std::numeric_limits<ptrdiff_t>::max(), '\n');
424 if (igzStream->eof()) {
425 if (doThrow) throw GDLException("End of file encountered.");
426 else break;
427 }
428 }
429 return i;
430 }
431 return 0;
432
433 }
434
Size()435 std::streampos AnyStream::Size() {
436 if (fStream != NULL) {
437 std::streampos cur = Tell();
438 std::streampos end = fStream->rdbuf()->pubseekoff(0, std::ios_base::end);
439 fStream->rdbuf()->pubseekpos(cur, std::ios_base::in | std::ios_base::out);
440 return end;
441 } else {
442 if (igzStream != NULL) {
443 std::streampos cur = igzStream->tellg(); //->rdbuf()->pubseekoff(0, std::ios_base::cur);
444 std::streampos end = igzStream->rdbuf()->pubseekoff(0, std::ios_base::end);
445 igzStream->rdbuf()->pubseekpos(cur, std::ios_base::in);
446 return end;
447 }
448 if (ogzStream != NULL) {
449 std::streampos cur = ogzStream->tellp(); //rdbuf()->pubseekoff(0, std::ios_base::cur);
450 std::streampos end = ogzStream->rdbuf()->pubseekoff(0, std::ios_base::end);
451 ogzStream->rdbuf()->pubseekpos(cur, std::ios_base::out);
452 return end;
453 } else {
454 assert(false);
455 throw; // getting rid of compiler warning
456 }
457 }
458 }
459
Tell()460 std::streampos AnyStream::Tell() {
461 if (fStream != NULL)
462 return ( fStream->tellg());
463 else if (igzStream != NULL)
464 return igzStream->tellg(); //rdbuf()->pubseekoff( 0, std::ios_base::cur, std::ios_base::in);
465 else if (ogzStream != NULL)
466 return ogzStream->tellp(); //rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out);
467 else {
468 assert(false);
469 throw; // getting rid of compiler warning
470 }
471 }
472
SeekPad(std::streampos pos)473 void AnyStream::SeekPad(std::streampos pos) {
474 if (fStream == NULL && ogzStream == NULL)
475 throw GDLException("File unit is not open.");
476 if (fStream != NULL) {
477 if (fStream->eof())
478 fStream->clear();
479
480 std::streampos fSize = Size();
481 if (pos > fSize) Pad(pos - fSize);
482
483 fStream->rdbuf()->pubseekpos(pos, std::ios_base::in | std::ios_base::out);
484 } else {
485 if (ogzStream->eof())
486 ogzStream->clear();
487
488 std::streampos fSize = Size();
489 if (pos > fSize) Pad(pos - fSize);
490
491 ogzStream->rdbuf()->pubseekpos(pos, std::ios_base::in | std::ios_base::out);
492 }
493 }
494
Open(const string & name_,ios_base::openmode mode_,bool swapEndian_,bool dOC,bool xdr_,SizeT width_,bool f77_,bool compress_)495 void GDLStream::Open(const string& name_,
496 ios_base::openmode mode_,
497 bool swapEndian_, bool dOC, bool xdr_,
498 SizeT width_,
499 bool f77_, bool compress_) {
500 string expName = name_;
501 WordExp(expName);
502
503 f77 = f77_;
504
505 // if( f77_)
506 // throw GDLException("F77_UNFORMATTED format not supported.");
507
508 // if( (fStream != NULL && fStream->is_open()) || (igzStream != NULL && igzStream->rdbuf()->is_open()) || (ogzStream != NULL && ogzStream->rdbuf()->is_open()))
509 if (anyStream != NULL && anyStream->IsOpen())
510 throw GDLIOException("File unit is already open.");
511
512 if (anyStream == NULL)
513 anyStream = new AnyStream();
514
515 name = expName;
516 mode = mode_;
517 compress = compress_;
518
519 anyStream->Open(expName, mode_, compress_);
520
521 swapEndian = swapEndian_;
522 deleteOnClose = dOC;
523
524 if (xdr_)
525 xdrs = new XDR;
526
527 lastSeekPos = 0;
528 lastRecord = 0;
529 lastRecordStart = 0;
530 width = width_;
531 }
532
Socket(const string & host,DUInt port,bool swapEndian_,DDouble c_timeout_,DDouble r_timeout_,DDouble w_timeout_)533 void GDLStream::Socket(const string& host,
534 DUInt port, bool swapEndian_,
535 DDouble c_timeout_, DDouble r_timeout_,
536 DDouble w_timeout_) {
537 if (iSocketStream == NULL)
538 iSocketStream = new istringstream;
539
540 if (recvBuf == NULL)
541 recvBuf = new string;
542
543 name = host;
544
545 sockNum = socket(AF_INET, SOCK_STREAM, 0);
546
547 c_timeout = c_timeout_;
548 r_timeout = r_timeout_;
549 w_timeout = w_timeout_;
550
551 int on = 1;
552 if (setsockopt(sockNum, SOL_SOCKET, SO_REUSEADDR,
553 (const char*) &on, sizeof (on)) == -1) {
554 throw GDLIOException("Error opening file.");
555 }
556
557 sockaddr_in m_addr;
558 m_addr.sin_family = AF_INET;
559 m_addr.sin_port = htons(port);
560
561 // Convert host to IPv4 format
562 struct hostent *h;
563 if ((h = gethostbyname(host.c_str())) == NULL) { // get the host info
564 throw GDLIOException("Unable to lookup host.");
565 }
566
567 // cout << inet_ntoa(*((struct in_addr *)h->h_addr)) << endl;
568
569 int status = inet_pton(AF_INET, inet_ntoa(*((struct in_addr *) h->h_addr)),
570 &m_addr.sin_addr);
571
572 status = connect(sockNum, (sockaddr *) & m_addr, sizeof (m_addr));
573
574 swapEndian = swapEndian_;
575
576 // BIG limit on socket send width to avoid leading \n in CheckNL
577 width = 32768;
578 }
579
Flush()580 void AnyStream::Flush() {
581 if (fStream != NULL) {
582 fStream->flush();
583 }
584 if (ogzStream != NULL) {
585 ogzStream->flush();
586 }
587 }
588
Flush()589 void GDLStream::Flush() {
590 if (anyStream != NULL) {
591 anyStream->Flush();
592 }
593 }
594
Close()595 void GDLStream::Close() {
596 if (anyStream != NULL) {
597 anyStream->Close();
598 if (deleteOnClose)
599 std::remove(name.c_str());
600 }
601 name = "";
602 f77 = false;
603 swapEndian = false;
604 compress = false;
605 deleteOnClose = false;
606
607 delete xdrs;
608 xdrs = NULL;
609
610 width = defaultStreamWidth;
611
612 sockNum = -1;
613 c_timeout = 0.0;
614 r_timeout = 0.0;
615 w_timeout = 0.0;
616
617 #ifdef HAVE_EXT_STDIO_FILEBUF_H
618 // GGH: ggh hack to implement SPAWN keyword UNIT
619 // Do housekeeping before closure
620 if (readbuf_frb_destroy_on_close_p != NULL) {
621 readbuf_frb_destroy_on_close_p->~stdio_filebuf();
622 readbuf_frb_destroy_on_close_p = NULL;
623 }
624 if (readbuf_bsrb_destroy_on_close_p != NULL) {
625 readbuf_bsrb_destroy_on_close_p->~basic_streambuf();
626 readbuf_bsrb_destroy_on_close_p = NULL;
627 }
628 if (fd_close_on_close != -1) {
629 close(fd_close_on_close);
630 fd_close_on_close = -1;
631 }
632 #endif
633
634 }
635
Free()636 void GDLStream::Free() {
637 Close();
638
639 delete anyStream;
640 anyStream = NULL;
641
642 delete iSocketStream;
643 iSocketStream = NULL;
644
645 delete recvBuf;
646 recvBuf = NULL;
647
648 getLunLock = false;
649 }
650
IgzStream()651 igzstream& GDLStream::IgzStream() {
652 if (anyStream == NULL || anyStream->IgzStream() == NULL || !anyStream->IsOpen())
653 throw GDLIOException("File unit is not open for compressed reading or writing.");
654 if (!(mode & ios::in))
655 throw GDLIOException("File unit is not open for reading.");
656 return *anyStream->IgzStream();
657 }
658
OgzStream()659 ogzstream& GDLStream::OgzStream() {
660 if (anyStream == NULL || anyStream->OgzStream() == NULL || !anyStream->IsOpen())
661 throw GDLIOException("File unit is not open for compressed reading or writing.");
662 if (!(mode & ios::out))
663 throw GDLIOException("File unit is not open for compressed writing.");
664 return *anyStream->OgzStream();
665 }
666
IStream()667 fstream& GDLStream::IStream() {
668 if (anyStream == NULL || anyStream->FStream() == NULL || !anyStream->IsOpen())
669 throw GDLIOException("File unit is not open.");
670 if (!(mode & ios::in))
671 throw GDLIOException("File unit is not open for reading.");
672 return *anyStream->FStream();
673 }
674
OStream()675 fstream& GDLStream::OStream() {
676 if (anyStream == NULL || anyStream->FStream() == NULL || !anyStream->IsOpen())
677 throw GDLIOException("File unit is not open.");
678 if (!(mode & ios::out))
679 throw GDLIOException("File unit is not open for writing.");
680 return *anyStream->FStream();
681 }
682
ISocketStream()683 istringstream& GDLStream::ISocketStream() {
684 if (iSocketStream == NULL)
685 throw GDLIOException("Socket unit is not open.");
686 return *iSocketStream;
687 }
688
Pad(std::streamsize nBytes)689 void GDLStream::Pad(std::streamsize nBytes) {
690 if (anyStream != NULL)
691 anyStream->Pad(nBytes);
692 }
693
Pad(std::streamsize nBytes)694 void AnyStream::Pad(std::streamsize nBytes) {
695 const std::streamsize bufSize = 1024;
696 static char buf[ bufSize];
697 SizeT nBuf = nBytes / bufSize;
698 std::streamsize lastBytes = nBytes % bufSize;
699 if (fStream != NULL) {
700 for (SizeT i = 0; i < nBuf; ++i) fStream->write(buf, bufSize);
701 if (lastBytes > 0) fStream->write(buf, lastBytes);
702 } else if (ogzStream != NULL) {
703 for (SizeT i = 0; i < nBuf; ++i) ogzStream->write(buf, bufSize);
704 if (lastBytes > 0) ogzStream->write(buf, lastBytes);
705 }
706 }
707
F77Write(DULong tCount)708 void GDLStream::F77Write(DULong tCount) {
709 anyStream->ClearEof();
710
711 assert(sizeof ( DULong) == 4);
712 if (swapEndian) {
713 char swapTCount[ sizeof ( DULong)];
714 for (SizeT i = 0; i<sizeof ( DULong); ++i)
715 swapTCount[i] =
716 reinterpret_cast<char*> (&tCount)[ sizeof ( DULong) - 1 - i];
717 anyStream->Write(swapTCount, sizeof ( DULong));
718 } else {
719 anyStream->Write(reinterpret_cast<char*> (&tCount), sizeof ( DULong));
720 }
721
722 if (!anyStream->Good()) {
723 throw GDLIOException("Error writing F77_UNFORMATTED record data.");
724 }
725 }
726
F77ReadStart()727 DULong GDLStream::F77ReadStart() {
728 if (anyStream->EofRaw())
729 throw GDLIOException("End of file encountered.");
730
731 assert(sizeof ( DULong) == 4);
732 DULong tCountRd;
733 if (swapEndian) {
734 char swapTCount[ sizeof ( DULong)];
735 anyStream->Read(swapTCount, sizeof ( DULong));
736 for (SizeT i = 0; i<sizeof ( DULong); ++i)
737 reinterpret_cast<char*> (&tCountRd)[ sizeof ( DULong) - 1 - i] =
738 swapTCount[i];
739 } else {
740 anyStream->Read(reinterpret_cast<char*> (&tCountRd), sizeof ( DULong));
741 }
742
743 if (anyStream->EofRaw())
744 throw GDLIOException("End of file encountered.");
745
746 if (!anyStream->Good()) {
747 throw GDLIOException("Error reading F77_UNFORMATTED record data.");
748 }
749
750 lastRecord = tCountRd;
751 lastRecordStart = Tell();
752 return tCountRd;
753 }
754
F77ReadEnd()755 void GDLStream::F77ReadEnd() {
756 if (anyStream->EofRaw())
757 throw GDLIOException("End of file encountered.");
758
759 std::streampos actPos = Tell();
760 if (actPos > (lastRecordStart + lastRecord))
761 throw GDLIOException("Read past end of Record of F77_UNFORMATTED file.");
762
763 if (actPos < (lastRecordStart + lastRecord))
764 Seek(lastRecordStart + lastRecord);
765
766 DULong tCountRd;
767 if (swapEndian) {
768 char swapTCount[ sizeof ( DULong)];
769 anyStream->Read(swapTCount, sizeof ( DULong));
770 for (SizeT i = 0; i<sizeof ( DULong); ++i)
771 reinterpret_cast<char*> (&tCountRd)[ sizeof ( DULong) - 1 - i] = swapTCount[i];
772 } else {
773 anyStream->Read(reinterpret_cast<char*> (&tCountRd), sizeof ( DULong));
774 }
775
776 if (anyStream->EofRaw())
777 throw GDLIOException("End of file encountered.");
778
779 if (!anyStream->Good()) {
780 throw GDLIOException("Error reading F77_UNFORMATTED record data.");
781 }
782
783 if (lastRecord != static_cast<std::streampos> (tCountRd))
784 throw GDLIOException("Logical error in F77_UNFORMATTED file.");
785
786 }
787
Eof()788 bool GDLStream::Eof() {
789 if (anyStream == NULL)
790 throw GDLException("File unit is not open.");
791
792 return anyStream->Eof();
793 }
794
SeekEof()795 void GDLStream::SeekEof() {
796 if (anyStream == NULL)
797 throw GDLException("File unit is not open.");
798
799 anyStream->SeekEof();
800 lastSeekPos = anyStream->Tell();
801 }
802
Seek(std::streampos pos)803 void GDLStream::Seek(std::streampos pos) {
804 if (anyStream == NULL)
805 throw GDLException("File unit is not open.");
806 anyStream->Seek(pos);
807 lastSeekPos = pos;
808 }
809
Truncate()810 void GDLStream::Truncate() {
811 if (anyStream == NULL)
812 throw GDLException("File unit is not open.");
813 std::streampos currentPos = anyStream->Tell();
814 char* buffer = (char*) malloc(currentPos);
815 anyStream->Seek(0);
816 anyStream->Read(buffer, currentPos);
817 anyStream->Close();
818 anyStream->Open(name, fstream::out | fstream::trunc, compress);
819 lastSeekPos = 0;
820 lastRecord = 0;
821 lastRecordStart = 0;
822 anyStream->Write(buffer, currentPos);
823 anyStream->Close();
824 anyStream->Open(name, mode & ~fstream::trunc, compress); //write again but not trunc!
825 anyStream->Seek(currentPos);
826 lastSeekPos = anyStream->Tell();
827 free(buffer);
828 }
829
830 //should work with compressed files too
CopySomeTo(DLong64 nbytes,GDLStream & to,bool doThrow)831 DLong64 GDLStream::CopySomeTo(DLong64 nbytes, GDLStream& to, bool doThrow) {
832 DLong64 chunksize = 1000000; //1 megabyte
833 DLong64 nchunk = nbytes / chunksize;
834 ssize_t remainder = nbytes - (nchunk * chunksize);
835 char* buffer = (char*) malloc(chunksize);
836 bool earlyEnd = false;
837 std::streampos size = this->Size();
838 DLong64 ret = 0;
839 DLong64 n = 0;
840 //the first nchunk chunks...
841 for (int i = 0; i < nchunk; ++i) {
842 //current position in 'in'
843 std::streampos startpos = anyStream->Tell();
844 anyStream->Read(buffer, chunksize);
845 //perhaps we encountered end of file. The principle is that all the valid data has already been copied BEFORE end-of-file is reported
846 if (!anyStream->Good()) {
847 n = size - startpos; //error eof
848 earlyEnd = true;
849 to.anyStream->Write(buffer, n);
850 ret += n;
851 break; //no input bytes anymore!
852 }
853 to.anyStream->Write(buffer, chunksize);
854 ret += chunksize;
855 }
856 //remainder: idem except if early end
857 if (!earlyEnd) {
858 //current position in 'in'
859 std::streampos startpos = anyStream->Tell();
860 anyStream->Read(buffer, remainder);
861 if (!anyStream->Good()) {
862 n = size - startpos; //error eof
863 } else n = remainder;
864 to.anyStream->Write(buffer, n);
865 ret += n;
866 }
867 free(buffer);
868 if (doThrow && !anyStream->Good()) throw GDLException("End of file encountered. File: " + name);
869 return ret;
870 }
871 //Slow as does the copy byte per byte. Could be improved for normal files.
CopySomeLinesTo(DLong nlines,GDLStream & to,bool doThrow)872 DLong GDLStream::CopySomeLinesTo(DLong nlines, GDLStream& to, bool doThrow) {
873 DLong i=0;
874 for (; i < nlines; ++i) {
875 //current position in 'in'
876 char buf[32];
877 do {
878 anyStream->Read(buf,1);
879 if (!anyStream->Good()) {
880 if (doThrow) throw GDLException("End of file encountered. File: " + name);
881 return i;
882 }
883 to.anyStream->Write(buf, 1);
884 } while(buf[0]!='\n');
885 }
886 return i;
887 }
888
Skip(std::streampos pos,bool doThrow)889 DLong64 GDLStream::Skip(std::streampos pos, bool doThrow) {
890 if (anyStream == NULL)
891 throw GDLException("File unit is not open.");
892 DLong64 ret = anyStream->Skip(pos, doThrow);
893 lastSeekPos = anyStream->Tell();
894 return ret;
895 }
SkipLines(DLong nlines,bool doThrow)896 DLong GDLStream::SkipLines(DLong nlines, bool doThrow) {
897 if (anyStream == NULL)
898 throw GDLException("File unit is not open.");
899 DLong n = anyStream->SkipLines(nlines, doThrow);
900 lastSeekPos = anyStream->Tell();
901 return n;
902 }
903
SeekPad(std::streampos pos)904 void GDLStream::SeekPad(std::streampos pos) {
905 if (anyStream == NULL)
906 throw GDLException("File unit is not open.");
907 anyStream->SeekPad(pos);
908 lastSeekPos = pos;
909 }
910
911 // ============================================================================
912
913
914 #ifdef HAVE_EXT_STDIO_FILEBUF_H
915 // GGH ggh hack to implement SPAWN keyword UNIT
916
get_stream_readbuf_bsrb()917 std::basic_streambuf<char> *GDLStream::get_stream_readbuf_bsrb() {
918 return anyStream->fStream->std::ios::rdbuf();
919 }
920
set_stream_readbuf_bsrb_from_frb(__gnu_cxx::stdio_filebuf<char> * frb_p)921 int GDLStream::set_stream_readbuf_bsrb_from_frb(__gnu_cxx::stdio_filebuf<char> *frb_p) {
922 anyStream->fStream->std::ios::rdbuf(frb_p);
923 return 0;
924 }
925
set_readbuf_frb_destroy_on_close(__gnu_cxx::stdio_filebuf<char> * frb_p)926 int GDLStream::set_readbuf_frb_destroy_on_close(__gnu_cxx::stdio_filebuf<char> *frb_p) {
927 readbuf_frb_destroy_on_close_p = frb_p;
928 return 0;
929 }
930
set_readbuf_bsrb_destroy_on_close(std::basic_streambuf<char> * bsrb_p)931 int GDLStream::set_readbuf_bsrb_destroy_on_close(std::basic_streambuf<char> *bsrb_p) {
932 readbuf_bsrb_destroy_on_close_p = bsrb_p;
933 return 0;
934 }
935
set_fd_close_on_close(int fd)936 int GDLStream::set_fd_close_on_close(int fd) {
937 fd_close_on_close = fd;
938 return 0;
939 }
940 #endif
941
942 // gzstream, C++ iostream classes wrapping the zlib compression library.
943 // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner
944 //
945 // This library is free software; you can redistribute it and/or
946 // modify it under the terms of the GNU Lesser General Public
947 // License as published by the Free Software Foundation; either
948 // version 2.1 of the License, or (at your option) any later version.
949 //
950 // This library is distributed in the hope that it will be useful,
951 // but WITHOUT ANY WARRANTY; without even the implied warranty of
952 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
953 // Lesser General Public License for more details.
954 //
955 // You should have received a copy of the GNU Lesser General Public
956 // License along with this library; if not, write to the Free Software
957 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
958 // ============================================================================
959 //
960 // File : gzstream.C
961 // Author(s) : Deepak Bandyopadhyay, Lutz Kettner
962 //
963 // Standard streambuf implementation following Nicolai Josuttis, "The
964 // Standard C++ Library".
965 // ============================================================================
966
967 #ifdef GZSTREAM_NAMESPACE
968 namespace GZSTREAM_NAMESPACE {
969 #endif
970
971 // ----------------------------------------------------------------------------
972 // Internal classes to implement gzstream. See header file for user classes.
973 // ----------------------------------------------------------------------------
974
975 // --------------------------------------
976 // class gzstreambuf:
977 // --------------------------------------
978
open(const char * name,int open_mode)979 gzstreambuf* gzstreambuf::open(const char* name, int open_mode) {
980 if (is_open())
981 return (gzstreambuf*) 0;
982 position = 0;
983 mode = open_mode;
984 // no append nor read/write mode
985 if ((mode & std::ios::ate) || (mode & std::ios::app)
986 || ((mode & std::ios::in) && (mode & std::ios::out)))
987 return (gzstreambuf*) 0;
988 char fmode[10];
989 char* fmodeptr = fmode;
990 if (mode & std::ios::in)
991 *fmodeptr++ = 'r';
992 else if (mode & std::ios::out)
993 *fmodeptr++ = 'w';
994 *fmodeptr++ = 'b';
995 *fmodeptr = '\0';
996 file = gzopen(name, fmode);
997 if (file == 0)
998 return (gzstreambuf*) 0;
999 opened = 1;
1000 return this;
1001 }
1002
close()1003 gzstreambuf * gzstreambuf::close() {
1004 if (is_open()) { //reset buf to 0 position: solves bug #724
1005 setg(buffer + buf4, // beginning of putback area
1006 buffer + buf4, // read position
1007 buffer + buf4); // end position
1008 sync();
1009 opened = 0;
1010 position = 0;
1011 if (gzclose(file) == Z_OK)
1012 return this;
1013 }
1014 return (gzstreambuf*) 0;
1015 }
1016
underflow()1017 int gzstreambuf::underflow() { // used for input buffer only
1018 if (gptr() && (gptr() < egptr()))
1019 return * reinterpret_cast<unsigned char *> (gptr());
1020
1021 if (!(mode & std::ios::in) || !opened)
1022 return EOF;
1023 // Josuttis' implementation of inbuf
1024 int n_putback = gptr() - eback();
1025 if (n_putback > buf4)
1026 n_putback = buf4;
1027 memcpy(buffer + (buf4 - n_putback), gptr() - n_putback, n_putback);
1028
1029 int num = gzread(file, buffer + buf4, bufferSize - buf4);
1030 if (num <= 0) // ERROR or EOF
1031 return EOF;
1032
1033 // reset buffer pointers
1034 setg(buffer + (buf4 - n_putback), // beginning of putback area
1035 buffer + buf4, // read position
1036 buffer + buf4 + num); // end of buffer
1037
1038 // return next character
1039 return * reinterpret_cast<unsigned char *> (gptr());
1040 }
1041
flush_buffer()1042 int gzstreambuf::flush_buffer() {
1043 // Separate the writing of the buffer from overflow() and
1044 // sync() operation.
1045 int w = pptr() - pbase();
1046 if (gzwrite(file, pbase(), w) != w)
1047 return EOF;
1048 pbump(-w);
1049 return w;
1050 }
1051
overflow(int c)1052 int gzstreambuf::overflow(int c) { // used for output buffer only
1053 if (!(mode & std::ios::out) || !opened)
1054 return EOF;
1055 if (c != EOF) {
1056 *pptr() = c;
1057 pbump(1);
1058 }
1059 if (flush_buffer() == EOF)
1060 return EOF;
1061 return c;
1062 }
1063
sync()1064 int gzstreambuf::sync() {
1065 // Changed to use flush_buffer() instead of overflow( EOF)
1066 // which caused improper behavior with std::endl and flush(),
1067 // bug reported by Vincent Ricard.
1068 if (pptr() && pptr() > pbase()) {
1069 if (flush_buffer() == EOF)
1070 return -1;
1071 }
1072 return 0;
1073 }
1074
pubseekpos(std::streampos sp,std::ios_base::openmode which)1075 std::streampos gzstreambuf::pubseekpos(std::streampos sp, std::ios_base::openmode which) {
1076 if (is_open()) {
1077 // cerr<<"seeking "<<sp<<" when we are at "<<gztell(this->file)<<endl;
1078 if ((which & std::ios_base::in && this->mode & std::ios::in) || /* read mode : ok */
1079 (which & std::ios_base::out && this->mode & std::ios::out &&
1080 static_cast<z_off_t> (sp) >= gztell(this->file))) /* write mode : seek forward only */ {
1081 z_off_t off = gzseek(this->file, static_cast<z_off_t> (0), SEEK_SET); //absolutely necessary to rewind!!!
1082 position = 0;
1083 setg(buffer + buf4, buffer + buf4, buffer + buf4);
1084 if (sp != 0) off = gzseek(this->file, static_cast<z_off_t> (sp), SEEK_SET);
1085 // fprintf(stderr, "Seek: %d=pubseekpos(sp=%d)\n", off, static_cast<z_off_t> (sp));
1086 // GD. seems reset of buffer is needed only when rewinded at 0.
1087 if (which & std::ios_base::in && off == 0) setg(buffer + buf4, buffer + buf4, buffer + buf4);
1088 position = off;
1089 return off;
1090 } else {
1091 z_off_t off = static_cast<std::streampos> (gztell(this->file)); /* Just don't Seek, no error */
1092 // fprintf(stderr, "Tell: %d=pubseekpos(sp=%d)\n", off, static_cast<z_off_t> (sp));
1093 position = off;
1094 return off;
1095 }
1096 }
1097 // fprintf(stderr, "EOF: -1=pubseekpos(sp=%d)\n", static_cast<z_off_t> (sp));
1098 return -1;
1099 }
1100
pubseekoff(std::streamoff offIn,std::ios_base::seekdir way,std::ios_base::openmode which)1101 std::streampos gzstreambuf::pubseekoff(std::streamoff offIn, std::ios_base::seekdir way, std::ios_base::openmode which) {
1102 // debug aid
1103 // string str;
1104 // switch(way)
1105 // {
1106 // case std::ios_base::beg:
1107 // str="beg"; break;
1108 // case std::ios_base::cur:
1109 // str="cur"; break;
1110 // case std::ios_base::end:
1111 // str="end"; break;
1112 // }
1113 // string strw;
1114 // switch(which)
1115 // {
1116 // case std::ios_base::in:
1117 // strw="in"; break;
1118 // case std::ios_base::out:
1119 // strw="out"; break;
1120 // case std::ios_base::out|std::ios_base::in:
1121 // strw="in|out"; break;
1122 // }
1123 // fprintf(stderr, "offIn: %d, seekdir: %s, openmode %s\n" , offIn, str.c_str(), strw.c_str());
1124
1125 if (is_open() && way != std::ios_base::end) /* No seek with SEEK_END */
1126 {
1127 if ((which & std::ios_base::in && this->mode & std::ios::in) || /* read mode : ok */
1128 (which & std::ios_base::out && this->mode & std::ios::out && /* write mode : ok if */
1129 ((way == std::ios_base::cur && offIn >= 0) || /* SEEK_CUR with positive offset */
1130 (way == std::ios_base::beg && static_cast<z_off_t> (offIn) >= gztell(this->file))))) /* or SEEK_SET which go forward */ {
1131 z_off_t off = gzseek(this->file, static_cast<z_off_t> (offIn), (way == std::ios_base::beg ? SEEK_SET : SEEK_CUR));
1132 // fprintf(stderr, "Seek: %d=pubseekoff(offIn=%d,way=%s)\n", off, static_cast<z_off_t> (offIn), str.c_str());
1133 // GD. seems reset of buffer is needed only when rewinded at 0.
1134 if (which & std::ios_base::in && off == 0) setg(buffer + buf4, buffer + buf4, buffer + buf4);
1135 position = off;
1136 return off;
1137 } else {
1138 z_off_t off = static_cast<std::streampos> (gztell(this->file)); /* Just don't Seek, no error */
1139 // fprintf(stderr, "Just Tell: %d=pubseekoff(offIn=%d,way=%s)\n", off, static_cast<z_off_t> (offIn), str.c_str());
1140 position = off;
1141 return off;
1142 }
1143 } else if (is_open()) { //decompress, nothing else possible:
1144 z_off_t off=gztell(this->file);
1145 static char buf[32];
1146 int i=0;
1147 do {
1148 i=gzread(this->file,buf,32);
1149 if (i>0) off+=i;
1150 }
1151 while (i > 0);
1152 return off-1; //apparently reads a spurious EOF , maybe different on differents Oses?
1153 }
1154 // fprintf(stderr, "EOF: -1=pubseekoff(offIn=%d,way=%s)\n", static_cast<z_off_t> (offIn), str.c_str());
1155 return -1;
1156 }
1157
seeknext(int_type __delim)1158 std::streampos gzstreambuf::seeknext(int_type __delim) {
1159 if (is_open()) { //decompress and find char, nothing else possible:
1160 z_off_t off=gztell(this->file);
1161 static char buf[1];
1162 int i=0;
1163 do {
1164 i=gzread(this->file,buf,1);
1165 if (i==1 && buf[0]==__delim) break;
1166 if (i>0) off+=i;
1167 } while (i > 0);
1168 return off-1; // was 1 too much.
1169 }
1170 return -1;
1171 }
1172
1173 // --------------------------------------
1174 // class gzstreambase:
1175 // --------------------------------------
1176
gzstreambase(const char * name,int mode)1177 gzstreambase::gzstreambase(const char* name, int mode) {
1178 init(&buf);
1179 open(name, mode);
1180 }
1181
~gzstreambase()1182 gzstreambase::~gzstreambase() {
1183 buf.close();
1184 }
1185
open(const char * name,int open_mode)1186 void gzstreambase::open(const char* name, int open_mode) {
1187 if (!buf.open(name, open_mode))
1188 clear(rdstate() | std::ios::badbit);
1189 }
1190
close()1191 void gzstreambase::close() {
1192 if (buf.is_open())
1193 if (!buf.close())
1194 clear(rdstate() | std::ios::badbit);
1195 }
1196
1197 // --------------------------------------
1198 // class igzstream:
1199 // --------------------------------------
1200
seekg(std::streampos pos)1201 igzstream& igzstream::seekg(std::streampos pos) {
1202 if (rdbuf()->pubseekpos(pos, ios_base::in) == std::streampos(-1))
1203 this->setstate(std::ios_base::badbit);
1204 else this->setstate(std::ios_base::goodbit);
1205 return *this;
1206 }
1207
seekg(std::streamoff off,std::ios_base::seekdir dir)1208 igzstream& igzstream::seekg(std::streamoff off, std::ios_base::seekdir dir) {
1209 if (rdbuf()->pubseekoff(off, dir, ios_base::in) == std::streampos(-1))
1210 this->setstate(std::ios_base::badbit);
1211 else this->setstate(std::ios_base::goodbit);
1212 return *this;
1213 }
1214
ignore(std::streamsize __n)1215 igzstream& igzstream::ignore(std::streamsize __n) {
1216 if (rdbuf()->pubseekoff(__n, ios_base::cur, ios_base::in) == std::streampos(-1))
1217 this->setstate(std::ios_base::badbit);
1218 else this->setstate(std::ios_base::goodbit);
1219 return *this;
1220 }
ignore(std::streamsize __n,int_type __delim)1221 igzstream& igzstream::ignore(std::streamsize __n, int_type __delim) {
1222 if (rdbuf()->seeknext(__delim) == std::streampos(-1))
1223 this->setstate(std::ios_base::badbit);
1224 else this->setstate(std::ios_base::goodbit);
1225 return *this;
1226 }
tellg()1227 std::streampos igzstream::tellg(){
1228 return rdbuf()->pubseekoff( 0, std::ios_base::cur, std::ios_base::in);
1229 }
1230
1231 // --------------------------------------
1232 // class ogzstream:
1233 // --------------------------------------
1234
seekp(std::streampos pos)1235 ogzstream& ogzstream::seekp(std::streampos pos) {
1236 if (rdbuf()->pubseekpos(pos, ios_base::out) == std::streampos(-1))
1237 this->setstate(std::ios_base::badbit);
1238 else this->setstate(std::ios_base::goodbit);
1239 return *this;
1240 }
1241
seekp(std::streamoff off,std::ios_base::seekdir dir)1242 ogzstream& ogzstream::seekp(std::streamoff off, std::ios_base::seekdir dir) {
1243 if (rdbuf()->pubseekoff(off, dir, ios_base::out) == std::streampos(-1))
1244 this->setstate(std::ios_base::badbit);
1245 else this->setstate(std::ios_base::goodbit);
1246 return *this;
1247 }
tellp()1248 std::streampos ogzstream::tellp(){
1249 return rdbuf()->pubseekoff( 0, std::ios_base::cur, std::ios_base::in);
1250 }
1251 #ifdef GZSTREAM_NAMESPACE
1252 } // namespace GZSTREAM_NAMESPACE
1253 #endif
1254
1255 // ============================================================================
1256 // EOF //
1257
1258
1259