File: file.cpp

package info (click to toggle)
groops 0%2Bgit20250907%2Bds-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 11,140 kB
  • sloc: cpp: 135,607; fortran: 1,603; makefile: 20
file content (260 lines) | stat: -rw-r--r-- 6,768 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/***********************************************/
/**
* @file file.cpp
*
* read and write files.
*
* @author Torsten Mayer-Guerr
* @date 2017-12-06
*
*/
/***********************************************/

#include <cstring>
#include "base/importStd.h"
#include "base/constants.h"
#include "base/string.h"
#include "external/compress.h"
#include "file.h"

/***** CLASS ***********************************/

#ifdef GROOPS_DISABLE_Z
#else

namespace zlib
{
#include <zlib.h>
}

// This is a reimplementation of gzstream (Deepak Bandyopadhyay, Lutz Kettner)
class StreambufGZ : public std::streambuf
{
private:
  static constexpr int bufferSize = 47+256;    // size of data buff
  // totals 512 bytes under g++ for igzstream at the end.

  zlib::gzFile       file;               // file handle for compressed file
  char               buffer[bufferSize]; // data buffer
  Bool               opened;             // open/close state of stream
  std::ios::openmode mode;               // I/O mode

  StreambufGZ::int_type flush_buffer();

public:
  StreambufGZ();
 ~StreambufGZ() {close();}

  bool is_open() const {return opened;}

  StreambufGZ *open(const FileName &fileName, std::ios::openmode openMode);
  StreambufGZ *close();

  virtual StreambufGZ::int_type underflow() override;
  virtual StreambufGZ::int_type overflow(StreambufGZ::int_type c) override;
  virtual StreambufGZ::int_type sync() override;
};

/***********************************************/

// Separate the writing of the buffer from overflow() and sync() operation.
StreambufGZ::int_type StreambufGZ::flush_buffer()
{
  auto w = pptr() - pbase();
  if(zlib::gzwrite(file, pbase(), w) != w)
    return traits_type::eof();
  pbump(-w);
  return w;
}

/***********************************************/

StreambufGZ::StreambufGZ() : opened(FALSE)
{
  setp(buffer, buffer+(bufferSize-1));
  setg(buffer+4, buffer+4, buffer+4); // beginning of putback area, read position, end position
  // ASSERT: both input & output capabilities will not be used together
}

/***********************************************/

StreambufGZ *StreambufGZ::open(const FileName &fileName, std::ios::openmode openMode)
{
  if(is_open())
    return nullptr;
  mode = openMode;
  // no append nor read/write mode
  if((mode & std::ios::ate) || (mode & std::ios::app) || ((mode & std::ios::in) && (mode & std::ios::out)))
    throw(Exception("openMode combination not allowed for .gz files"));
  file = zlib::gzopen(fileName.c_str(), (mode & std::ios::out) ? "wb" : "rb");
  if(!file)
    return nullptr;
  opened = TRUE;
  return this;
}

/***********************************************/

StreambufGZ *StreambufGZ::close()
{
  if(is_open())
  {
    sync();
    opened = FALSE;
    if(zlib::gzclose(file) == Z_OK)
      return this;
  }
  return nullptr;
}

/***********************************************/

// used for input buffer only
StreambufGZ::int_type StreambufGZ::underflow()
{
  if(gptr() && (gptr() < egptr()))
    return traits_type::to_int_type(*gptr());

  if(!(mode & std::ios::in) || !opened)
    return traits_type::eof();

  // Josuttis' implementation of inbuf
  auto n_putback = gptr() - eback();
  if(n_putback > 4)
    n_putback = 4;
  memcpy(buffer+(4-n_putback), gptr()-n_putback, n_putback);

  auto num = zlib::gzread(file, buffer+4, bufferSize-4);
  if(num <= 0) // ERROR or EOF
    return traits_type::eof();

  // reset buffer pointers
  setg(buffer+(4-n_putback), buffer+4, buffer+4+num); // beginning of putback area, read position, end of buffer

  return traits_type::to_int_type(*gptr()); // return next character
}

/***********************************************/

// used for output buffer only
StreambufGZ::int_type StreambufGZ::overflow(StreambufGZ::int_type c)
{
  if(!(mode & std::ios::out) || !opened)
    return traits_type::eof();
  if(c != traits_type::eof())
  {
    *pptr() = c;
    pbump(1);
  }
  if(flush_buffer() == traits_type::eof())
    return traits_type::eof();
  return c;
}

/***********************************************/

StreambufGZ::int_type StreambufGZ::sync()
{
  if(pptr() && (pptr() > pbase()) && (flush_buffer() == traits_type::eof()))
    return -1;
  return 0;
}

#endif // LIB_Z

/***********************************************/
/***** CLASS ***********************************/
/***********************************************/

StreamBase::StreamBase() : buffer(nullptr), canSeek_(FALSE) {}
StreamBase::~StreamBase() {close();}

/***********************************************/

void StreamBase::open(const FileName &fileName, std::ios::openmode openMode)
{
  try
  {
    close();
    if(fileName.empty())
      return;
    this->fileName_ = fileName;
    this->canSeek_  = TRUE;

    // determine format from extension
    std::string fileFormat = String::upperCase(fileName.packExtension());

    // determine format from magic bytes if possible
    if(openMode == std::ios::in)
    {
      std::ifstream file(fileName.c_str(), std::ios::binary);
      unsigned char magic[2] = {0};
      file.read(reinterpret_cast<char*>(magic), sizeof(magic));
      const unsigned char magicCompress[2] = {0x1f, 0x9d};
      const unsigned char magicZlib[2]     = {0x1f, 0x8b};
      if(std::memcmp(magic, magicZlib, sizeof(magic)) == 0)
        fileFormat = "GZ";
      else if(std::memcmp(magic, magicCompress, sizeof(magic)) == 0)
        fileFormat = "Z";
    }

    if(fileFormat == "GZ")
    {
#ifdef GROOPS_DISABLE_Z
      throw(Exception("compiled without Z library"));
#else
      buffer = new StreambufGZ();
      std::ios::init(buffer);
      if(!static_cast<StreambufGZ*>(buffer)->open(fileName, openMode))
        clear(rdstate() | std::ios::badbit);
      canSeek_ = FALSE;
#endif
    }
    else if(fileFormat == "Z")
    {
      if(openMode != std::ios::in)
        throw(Exception("old .Z compress implemented for input only"));

      buffer = new std::stringbuf(decompress_file(fileName.c_str()));
      std::ios::init(buffer);
    }
    else
    {
      buffer = new std::filebuf();
      std::ios::init(buffer);
      if(!static_cast<std::filebuf*>(buffer)->open(fileName.str(), openMode))
        clear(rdstate() | std::ios::badbit);
    }

    if(!good())
      throw(Exception("error by opening file"));
    exceptions(std::ios::badbit);
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW_EXTRA("filename=<"+fileName.str()+">", e)
  }
}

/***********************************************/

void StreamBase::close()
{
  try
  {
    if(buffer)
    {
      delete buffer;
      buffer = nullptr;
      std::ios::init(nullptr);
    }
    fileName_ = FileName();
    canSeek_  = FALSE;
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW_EXTRA("filename=<"+fileName_.str()+">", e)
  }
}

/***********************************************/