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=&currentPage=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