libzypp  17.35.11
simplestreambuf.h
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #ifndef ZYPP_CORE_BASE_SIMPLESTREAMBUF_H_DEFINED
13 #define ZYPP_CORE_BASE_SIMPLESTREAMBUF_H_DEFINED
14 
15 #include <streambuf>
16 #include <vector>
17 
18 namespace zypp {
19  namespace detail {
20 
53  template<typename Impl>
54  class SimpleStreamBuf : public std::streambuf, public Impl
55  {
56 
57  public:
58 
59  SimpleStreamBuf( size_t bufsize_r = 512) : _buffer( bufsize_r ) { }
60  ~SimpleStreamBuf() override { close(); }
61 
62  template <typename OpenSpecType>
63  SimpleStreamBuf * open( OpenSpecType &&name_r, std::ios_base::openmode mode_r = std::ios_base::in ) {
64 
65  if ( !this->openImpl( std::forward<OpenSpecType>(name_r), mode_r ) )
66  return nullptr;
67 
68  if ( this->canRead() ) {
69  setp( NULL, NULL );
70  setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
71  } else {
72  setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]) );
73  setg( NULL, NULL, NULL );
74  }
75 
76  return this;
77  }
78 
80 
81  if ( !this->isOpen() )
82  return nullptr;
83 
84  if ( this->canWrite() )
85  sync();
86 
87  if ( !this->closeImpl() )
88  return nullptr;
89 
90  return this;
91  }
92 
93  protected:
94 
95  int sync() override {
96  int ret = 0;
97  if ( pbase() < pptr() ) {
98  const int_type res = overflow();
99  if ( traits_type::eq_int_type( res, traits_type::eof() ) )
100  ret = -1;
101  }
102  return ret;
103  }
104 
105  int_type overflow( int_type c = traits_type::eof() ) override {
106  int_type ret = traits_type::eof();
107  if ( this->canWrite() ) {
108  if ( ! traits_type::eq_int_type( c, traits_type::eof() ) )
109  {
110  *pptr() = traits_type::to_char_type( c );
111  pbump(1);
112  }
113  if ( pbase() <= pptr() )
114  {
115  if ( this->writeData( pbase(), pptr() - pbase() ) )
116  {
117  setp( &(_buffer[0]), &(_buffer[_buffer.size()-1]) );
118  ret = traits_type::not_eof( c );
119  }
120  // else: error writing the file
121  }
122  }
123  return ret;
124  }
125 
126  int_type underflow() override {
127  int_type ret = traits_type::eof();
128  if ( this->canRead() )
129  {
130  if ( gptr() < egptr() )
131  return traits_type::to_int_type( *gptr() );
132 
133  const std::streamsize got = this->readData( &(_buffer[0]), _buffer.size() );
134  if ( got > 0 )
135  {
136  setg( &(_buffer[0]), &(_buffer[0]), &(_buffer.data()[got]) );
137  ret = traits_type::to_int_type( *gptr() );
138  }
139  else if ( got == 0 )
140  {
141  // EOF
142  setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
143  }
144  // else: error reading the file
145  }
146  return ret;
147  }
148 
149  pos_type seekpos( pos_type pos_r, std::ios_base::openmode openMode ) override {
150  return seekoff( off_type(pos_r), std::ios_base::beg, openMode );
151  }
152 
153 
154  pos_type seekoff( off_type off_r, std::ios_base::seekdir way_r, std::ios_base::openmode openMode ) override {
155  pos_type ret = pos_type(off_type(-1));
156  if ( !this->canSeek( way_r) )
157  return ret;
158 
159  if ( this->isOpen() ) {
160  if ( openMode == std::ios_base::out ) {
161  //write the buffer out and invalidate it , no need to keep it around
162  if ( !this->canWrite() || sync() != 0 )
163  return ret;
164 
165  ret = this->seekTo( off_r, way_r, openMode );
166 
167  } else if ( openMode == std::ios_base::in ) {
168  if ( !this->canRead() )
169  return ret;
170 
171  //current physical FP, should point to end of buffer
172  const off_type buffEndOff = this->tell();
173 
174  if ( buffEndOff != off_type(-1) ) {
175  if ( way_r == std::ios_base::end ) {
176  setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
177  ret = this->seekTo( off_r, way_r, openMode );
178  }
179 
180  const off_type bufLen = egptr() - eback();
181  const off_type bufStartFileOff = buffEndOff - bufLen;
182  const off_type currPtrFileOffset = buffEndOff - ( egptr() - gptr() );
183  off_type newFOff = off_r;
184 
185  // Transform into ios_base::beg and seek.
186  if ( way_r == std::ios_base::cur ) {
187  newFOff += currPtrFileOffset;
188  way_r = std::ios_base::beg;
189  }
190 
191  //check if a seek would go out of the buffers boundaries
192  if ( way_r == std::ios_base::beg ) {
193  if ( bufStartFileOff <= newFOff && newFOff <= buffEndOff ) {
194  // Still inside buffer, adjust gptr and
195  // calculate new position.
196  setg( eback(),
197  eback() + ( newFOff - bufStartFileOff ),
198  egptr() );
199  ret = pos_type( newFOff );
200  } else {
201  // Invalidate buffer and seek.
202  setg( &(_buffer[0]), &(_buffer[0]), &(_buffer[0]) );
203  ret = this->seekTo( off_r, way_r, openMode );
204  }
205  }
206  }
207  }
208  }
209  return ret;
210  }
211 
212  private:
213  using buffer_type = std::vector<char>;
215  };
216  }
217 }
218 #endif
SimpleStreamBuf(size_t bufsize_r=512)
int_type underflow() override
pos_type seekpos(pos_type pos_r, std::ios_base::openmode openMode) override
int_type overflow(int_type c=traits_type::eof()) override
std::vector< char > buffer_type
pos_type seekoff(off_type off_r, std::ios_base::seekdir way_r, std::ios_base::openmode openMode) override
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
SimpleStreamBuf * open(OpenSpecType &&name_r, std::ios_base::openmode mode_r=std::ios_base::in)