Coverage Report

Created: 2025-10-28 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openbabel/include/openbabel/lineend.h
Line
Count
Source
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
0
    {
76
0
      setg(  &myBuffer , &myBuffer , &myBuffer  ) ; //ensure next character is from new position
77
0
      mySource->seekg(off, way);
78
0
      std::streampos ret = mySource->tellg();
79
//      sync();
80
0
      return ret;
81
0
    };
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
8.08k
    : mySource(source)
122
8.08k
  {
123
8.08k
    setg( &myBuffer , &myBuffer , &myBuffer ) ;
124
8.08k
  }
125
126
  //////////////////////////////////////////////////////////
127
  template< class Extractor >
128
  int
129
  FilteringInputStreambuf< Extractor >::underflow()
130
82.5M
  {
131
82.5M
    int result( EOF ) ;
132
82.5M
    if( gptr() < egptr() )
133
0
      result = *gptr() ;
134
82.5M
    else if ( mySource != nullptr )
135
82.5M
    {
136
82.5M
      result = myExtractor( *mySource ) ;
137
82.5M
      if ( result != EOF )
138
82.5M
      {
139
82.5M
        if( result < 0 || result > UCHAR_MAX )
140
0
          std::cerr << "FilteringInputStreambuf error" << std::endl;
141
82.5M
        myBuffer = result ;
142
82.5M
        setg( &myBuffer , &myBuffer , &myBuffer + 1 ) ;
143
82.5M
      }
144
82.5M
    }
145
82.5M
    return result ;
146
82.5M
  }
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
82.5M
  {
174
82.5M
    int ch( src.get() ) ;
175
82.5M
    switch (ch)
176
82.5M
    {
177
489
      case 13: //CR or CRLF
178
489
        if(src.peek() == 10)
179
211
          src.get(); //CRLF
180
        //fall through
181
1.24k
      case 10: //LF
182
1.24k
        return '\n';
183
0
        break;
184
82.5M
      default:
185
82.5M
        return ch;
186
82.5M
    }
187
82.5M
  }
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
8.08k
        FilteringInputStreambuf<Extractor>(&istream),std::istream(this) {}
205
8.08k
    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)