Coverage Report

Created: 2026-01-17 06:10

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
769
    : mySource(source)
122
769
  {
123
769
    setg( &myBuffer , &myBuffer , &myBuffer ) ;
124
769
  }
125
126
  //////////////////////////////////////////////////////////
127
  template< class Extractor >
128
  int
129
  FilteringInputStreambuf< Extractor >::underflow()
130
106M
  {
131
106M
    int result( EOF ) ;
132
106M
    if( gptr() < egptr() )
133
0
      result = *gptr() ;
134
106M
    else if ( mySource != nullptr )
135
106M
    {
136
106M
      result = myExtractor( *mySource ) ;
137
106M
      if ( result != EOF )
138
106M
      {
139
106M
        if( result < 0 || result > UCHAR_MAX )
140
0
          std::cerr << "FilteringInputStreambuf error" << std::endl;
141
106M
        myBuffer = result ;
142
106M
        setg( &myBuffer , &myBuffer , &myBuffer + 1 ) ;
143
106M
      }
144
106M
    }
145
106M
    return result ;
146
106M
  }
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
106M
  {
174
106M
    int ch( src.get() ) ;
175
106M
    switch (ch)
176
106M
    {
177
435k
      case 13: //CR or CRLF
178
435k
        if(src.peek() == 10)
179
1.57k
          src.get(); //CRLF
180
        //fall through
181
2.37M
      case 10: //LF
182
2.37M
        return '\n';
183
0
        break;
184
104M
      default:
185
104M
        return ch;
186
106M
    }
187
106M
  }
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
769
        FilteringInputStreambuf<Extractor>(&istream),std::istream(this) {}
205
769
    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)