Coverage Report

Created: 2025-07-13 06:44

/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)