summaryrefslogtreecommitdiff
path: root/src/include/mime-inputsource.h
blob: f383e88c761d9ef6a09dd51122807228d446a0d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
 *  @file mime-inputsource.h
 *  @brief  The base class of the MIME input source
 *  @author Andreas Aardal Hanssen
 *  @date 2002-2005
 */

#ifndef mime_inputsource_h_included
#define mime_inputsource_h_included

#include <string.h>

#include <unistd.h>

namespace Binc {

  class MimeInputSource {
  public:
    inline MimeInputSource(int fd, unsigned int start = 0);
    virtual inline ~MimeInputSource();

    virtual inline bool fillInputBuffer();
    virtual inline void reset();

    inline void seek(unsigned int offset);
    inline bool getChar(char *c);
    inline void ungetChar();
    inline int getFileDescriptor() const;

    inline unsigned int getOffset() const;

  private:
    int fd;
    char data[16384];
    unsigned int offset;
    unsigned int tail;
    unsigned int head;
    unsigned int start;
    char lastChar;
  };

  inline MimeInputSource::MimeInputSource(int fd, unsigned int start)
  {
    this->fd = fd;
    this->start = start;
    offset = 0;
    tail = 0;
    head = 0;
    lastChar = '\0';
    memset(data, '\0', sizeof(data));

    seek(start);
  }

  inline MimeInputSource::~MimeInputSource() {}

  inline bool MimeInputSource::fillInputBuffer()
  {
    char raw[4096];
    ssize_t nbytes = read(fd, raw, sizeof(raw));
    if (nbytes <= 0) {
      // FIXME: If ferror(crlffile) we should log this.
      return false;
    }

    for (ssize_t i = 0; i < nbytes; ++i) {
      const char c = raw[i];
      if (c == '\r') {
        if (lastChar == '\r') {
          data[tail++ & (0x4000 - 1)] = '\r';
          data[tail++ & (0x4000 - 1)] = '\n';
        }
      } else if (c == '\n') {
        data[tail++ & (0x4000 - 1)] = '\r';
        data[tail++ & (0x4000 - 1)] = '\n';
      } else {
        if (lastChar == '\r') {
          data[tail++ & (0x4000 - 1)] = '\r';
          data[tail++ & (0x4000 - 1)] = '\n';
        }
        data[tail++ & (0x4000 - 1)] = c;
      }

      lastChar = c;
    }

    return true;
  }

  inline void MimeInputSource::reset()
  {
    offset = head = tail = 0;
    lastChar = '\0';

    if (fd != -1) lseek(fd, 0, SEEK_SET);
  }

  inline void MimeInputSource::seek(unsigned int seekToOffset)
  {
    if (offset > seekToOffset) reset();

    char c;
    int n = 0;
    while (seekToOffset > offset) {
      if (!getChar(&c)) break;
      ++n;
    }
  }

  inline bool MimeInputSource::getChar(char *c)
  {
    if (head == tail && !fillInputBuffer()) return false;

    *c = data[head++ & (0x4000 - 1)];
    ++offset;
    return true;
  }

  inline void MimeInputSource::ungetChar()
  {
    --head;
    --offset;
  }

  inline int MimeInputSource::getFileDescriptor() const
  {
    return fd;
  }

  inline unsigned int MimeInputSource::getOffset() const
  {
    return offset;
  }
}

extern Binc::MimeInputSource *mimeSource;

#endif