libzypp 17.37.17
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
18namespace 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
off_t seekTo(off_t off_r, std::ios_base::seekdir way_r, std::ios_base::openmode omode_r)
std::streamsize readData(char *buffer_r, std::streamsize maxcount_r)
bool writeData(const char *buffer_r, std::streamsize count_r)
bool canSeek(std::ios_base::seekdir way_r) const
bool openImpl(int fd, std::ios_base::openmode mode_r)
SimpleStreamBuf * open(OpenSpecType &&name_r, std::ios_base::openmode mode_r=std::ios_base::in)
pos_type seekoff(off_type off_r, std::ios_base::seekdir way_r, std::ios_base::openmode openMode) override
pos_type seekpos(pos_type pos_r, std::ios_base::openmode openMode) override
int_type overflow(int_type c=traits_type::eof()) override
SimpleStreamBuf(size_t bufsize_r=512)
Easy-to use interface to the ZYPP dependency resolver.