/src/openbabel/include/openbabel/lineend.h
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | lineend.h - Stream buffer for filtering line endings, converting \r or \r\n -> \n |
3 | | |
4 | | Copyright (C) 1998 by James Kanze |
5 | | Copyright (C) 2007 by Chris Morley |
6 | | |
7 | | This file is part of the Open Babel project. |
8 | | For more information, see <http://openbabel.org/> |
9 | | |
10 | | This program is free software; you can redistribute it and/or modify |
11 | | it under the terms of the GNU General Public License as published by |
12 | | the Free Software Foundation version 2 of the License. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, but |
15 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | General Public License for more details. |
18 | | ***********************************************************************/ |
19 | | |
20 | | #ifndef OB_LINEEND_H |
21 | | #define OB_LINEEND_H |
22 | | |
23 | | #include <streambuf> |
24 | | #include <climits> |
25 | | |
26 | | #ifndef OBCONV |
27 | | #define OBCONV |
28 | | #endif |
29 | | |
30 | | namespace OpenBabel |
31 | | { |
32 | | |
33 | | /*! \class FilteringInputStreambuf lineend.h <openbabel/lineend.h> |
34 | | \brief Delivers characters from an istream or streambuf from a source |
35 | | while filtering |
36 | | |
37 | | Based on an article by James Kanze, "Filtering Streambufs" |
38 | | http://kanze.james.neuf.fr/articles/fltrsbf1.html |
39 | | |
40 | | A FilteringInputStreambuf delivers characters on request to an istream |
41 | | or a destination rdbuf(). It receives them from a source rdbuf. |
42 | | In doing the transfer it filters them in a way decided by the class |
43 | | specified in template parameter Extractor. |
44 | | |
45 | | seekg and tellg requests from the stream are passed through to source rdbuf. |
46 | | This allows return to a position in the input data that was previously noted. |
47 | | This is adequate to allow OpenBabel's fastsearch indexing, but may |
48 | | not be good enough for some other applications that use random access. |
49 | | |
50 | | A class LineEndingExtractor converts DOS and MAC line endings to the |
51 | | UNIX line ending. |
52 | | |
53 | | This filtering process is potentially extendable, with a chain of |
54 | | FilteringInputStreambufs each carrying out its filtering task. |
55 | | For instance a decompression streambuf could feed a LineEnding filter, |
56 | | which in tern was read by an input stream. |
57 | | */ |
58 | | template< class Extractor > |
59 | | class FilteringInputStreambuf : public std::streambuf |
60 | | { |
61 | | public: |
62 | | FilteringInputStreambuf( |
63 | | std::istream* source = nullptr) ; |
64 | | virtual ~FilteringInputStreambuf() |
65 | | { |
66 | | //sync(); comment out so can be deleted in OBConversion destructor |
67 | | }; |
68 | 0 | virtual int overflow( int ) {return EOF;}; |
69 | | virtual int underflow() ; |
70 | | virtual int sync() ; |
71 | | |
72 | | //Pass the random acess functions to the source rdbuf and synchronize |
73 | | virtual std::streampos seekoff(std::streamoff off, std::ios_base::seekdir way, |
74 | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) |
75 | 1.92k | { |
76 | 1.92k | setg( &myBuffer , &myBuffer , &myBuffer ) ; //ensure next character is from new position |
77 | 1.92k | mySource->seekg(off, way); |
78 | 1.92k | std::streampos ret = mySource->tellg(); |
79 | | // sync(); |
80 | 1.92k | return ret; |
81 | 1.92k | }; |
82 | | |
83 | | virtual std::streampos seekpos(std::streampos sp, |
84 | | std::ios_base::openmode which = std::ios_base::in | std::ios_base::out ) |
85 | 0 | { |
86 | 0 | setg( &myBuffer , &myBuffer , &myBuffer ) ; |
87 | | //slight hack - if mySource has read past the end, won't let us seek |
88 | | //and there's no good way to propagate a clear to the original stream |
89 | 0 | mySource->clear(); |
90 | 0 | mySource->seekg(sp); |
91 | 0 | std::streampos ret = mySource->tellg(); |
92 | | // sync(); |
93 | 0 | return ret; |
94 | 0 | }; |
95 | | |
96 | | /// Returns current source. |
97 | | std::istream* GetSource()const |
98 | | { |
99 | | return mySource; |
100 | | }; |
101 | | |
102 | | ///Changes the source |
103 | | void SetSource(std::istream* newsource) |
104 | | { |
105 | | mySource = newsource; |
106 | | setg( &myBuffer , &myBuffer , &myBuffer + 1 ) ; |
107 | | } |
108 | | |
109 | | // Extractor& extractor() {return myExtractor;}; |
110 | | |
111 | | private: |
112 | | std::istream* mySource ; |
113 | | Extractor myExtractor ; |
114 | | char myBuffer ; |
115 | | } ; |
116 | | |
117 | | //******************************************************* |
118 | | template< class Extractor > |
119 | | FilteringInputStreambuf< Extractor >::FilteringInputStreambuf( |
120 | | std::istream* source ) |
121 | 16.5k | : mySource(source) |
122 | 16.5k | { |
123 | 16.5k | setg( &myBuffer , &myBuffer , &myBuffer ) ; |
124 | 16.5k | } |
125 | | |
126 | | ////////////////////////////////////////////////////////// |
127 | | template< class Extractor > |
128 | | int |
129 | | FilteringInputStreambuf< Extractor >::underflow() |
130 | 156M | { |
131 | 156M | int result( EOF ) ; |
132 | 156M | if( gptr() < egptr() ) |
133 | 0 | result = *gptr() ; |
134 | 156M | else if ( mySource != nullptr ) |
135 | 156M | { |
136 | 156M | result = myExtractor( *mySource ) ; |
137 | 156M | if ( result != EOF ) |
138 | 156M | { |
139 | 156M | if( result < 0 || result > UCHAR_MAX ) |
140 | 0 | std::cerr << "FilteringInputStreambuf error" << std::endl; |
141 | 156M | myBuffer = result ; |
142 | 156M | setg( &myBuffer , &myBuffer , &myBuffer + 1 ) ; |
143 | 156M | } |
144 | 156M | } |
145 | 156M | return result ; |
146 | 156M | } |
147 | | |
148 | | ////////////////////////////////////////////////////// |
149 | | template< class Extractor > |
150 | | int |
151 | | FilteringInputStreambuf< Extractor >::sync() |
152 | 0 | { |
153 | 0 | int result( 0 ) ; |
154 | 0 | if ( mySource != nullptr ) |
155 | 0 | { |
156 | 0 | if ( gptr() < egptr() ) |
157 | 0 | { //have read something but not provided it |
158 | 0 | mySource->putback(*gptr() ) ; |
159 | 0 | setg( &myBuffer , &myBuffer , &myBuffer ) ; |
160 | 0 | } |
161 | 0 | result = mySource->sync(); |
162 | 0 | } |
163 | 0 | return result ; |
164 | 0 | } |
165 | | |
166 | | //********************************************* |
167 | | /// \class LineEndingExtractor lineend.h <openbabel/lineend.h> |
168 | | /// \brief Replaces CRLF (DOS) and CR (Mac OS 9) line endings by LF (POSIX) |
169 | | class OBCONV LineEndingExtractor |
170 | | { |
171 | | public: |
172 | | int operator()( std::istream& src ) |
173 | 156M | { |
174 | 156M | int ch( src.get() ) ; |
175 | 156M | switch (ch) |
176 | 156M | { |
177 | 551k | case 13: //CR or CRLF |
178 | 551k | if(src.peek() == 10) |
179 | 3.18k | src.get(); //CRLF |
180 | | //fall through |
181 | 1.85M | case 10: //LF |
182 | 1.85M | return '\n'; |
183 | 0 | break; |
184 | 155M | default: |
185 | 155M | return ch; |
186 | 156M | } |
187 | 156M | } |
188 | 0 | void finalize( std::streambuf& ) {} |
189 | | }; |
190 | | |
191 | | /*! \class FilteringInputStream lineend.h <openbabel/lineend.h> |
192 | | \brief A stream interface for FilteringInputStreambuf |
193 | | */ |
194 | | template <class Extractor > |
195 | | class FilteringInputStream : |
196 | | virtual private FilteringInputStreambuf<Extractor>, |
197 | | public std::istream |
198 | | { |
199 | | public: |
200 | | typedef std::istream& istream_reference; |
201 | | typedef std::istream istream_type; |
202 | | |
203 | | explicit FilteringInputStream(istream_reference istream): |
204 | 16.5k | FilteringInputStreambuf<Extractor>(&istream),std::istream(this) {} |
205 | 16.5k | virtual ~FilteringInputStream() {} |
206 | | |
207 | | }; |
208 | | |
209 | | } //namespace |
210 | | |
211 | | #endif //OB_LINEEND_H |
212 | | //! \file lineend.h |
213 | | //! \brief Translate line endings automatically (UNIX, Classic Mac, DOS) |