Coverage Report

Created: 2026-09-06 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libe-book/src/lib/EBOOKZlibStream.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libe-book project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include <cassert>
11
#include <vector>
12
13
#include <zlib.h>
14
15
#include "libebook_utils.h"
16
#include "EBOOKMemoryStream.h"
17
#include "EBOOKZlibStream.h"
18
19
using std::vector;
20
21
namespace libebook
22
{
23
24
namespace
25
{
26
27
class ZlibStreamException
28
{
29
};
30
31
EBOOKMemoryStream *getInflatedStream(librevenge::RVNGInputStream *const input)
32
16.9k
{
33
16.9k
  if (0x78 != readU8(input)) // not a zlib stream
34
19
    throw ZlibStreamException();
35
36
16.9k
  const bool uncompressed = Z_NO_COMPRESSION == readU8(input);
37
38
16.9k
  auto begin = (unsigned long) input->tell();
39
16.9k
  input->seek(0, librevenge::RVNG_SEEK_END);
40
16.9k
  auto end = (unsigned long) input->tell();
41
16.9k
  unsigned long compressedSize = end - begin;
42
16.9k
  input->seek((long) begin, librevenge::RVNG_SEEK_SET);
43
44
16.9k
  if (0 == compressedSize) // No data?!
45
1
    throw ZlibStreamException();
46
47
16.9k
  unsigned long numBytesRead = 0;
48
16.9k
  auto *compressedData = const_cast<unsigned char *>(input->read(compressedSize, numBytesRead));
49
50
16.9k
  if (uncompressed)
51
1.09k
  {
52
1.09k
    if (numBytesRead != compressedSize)
53
0
      throw ZlibStreamException();
54
1.09k
    return new EBOOKMemoryStream(compressedData, static_cast<unsigned>(compressedSize));
55
1.09k
  }
56
15.8k
  else
57
15.8k
  {
58
15.8k
    int ret;
59
15.8k
    z_stream strm;
60
61
    /* allocate inflate state */
62
15.8k
    strm.zalloc = Z_NULL;
63
15.8k
    strm.zfree = Z_NULL;
64
15.8k
    strm.opaque = Z_NULL;
65
15.8k
    strm.avail_in = 0;
66
15.8k
    strm.next_in = Z_NULL;
67
15.8k
    ret = inflateInit2(&strm,-MAX_WBITS);
68
15.8k
    if (ret != Z_OK)
69
0
      throw ZlibStreamException();
70
71
15.8k
    strm.avail_in = (unsigned)numBytesRead;
72
15.8k
    strm.next_in = (Bytef *)compressedData;
73
15.8k
    strm.total_out = 0;
74
75
15.8k
    vector<unsigned char> data(2 * compressedSize);
76
77
92.5k
    while (true)
78
92.5k
    {
79
92.5k
      strm.next_out = reinterpret_cast<Bytef *>(&data[strm.total_out]);
80
92.5k
      strm.avail_out = uInt(data.size() - strm.total_out);
81
92.5k
      ret = inflate(&strm, Z_SYNC_FLUSH);
82
83
92.5k
      if (Z_STREAM_END == ret)
84
7.81k
        break;
85
84.7k
      if ((Z_OK == ret) && (0 == strm.avail_in) && (0 < strm.avail_out)) // end of stream too
86
7.42k
        break;
87
77.3k
      if (Z_OK != ret)
88
593
      {
89
593
        (void)inflateEnd(&strm);
90
593
        throw ZlibStreamException();
91
593
      }
92
93
76.7k
      data.resize(data.size() + compressedSize);
94
76.7k
    }
95
96
15.2k
    (void)inflateEnd(&strm);
97
98
15.2k
    return new EBOOKMemoryStream(&data[0], (unsigned) strm.total_out);
99
15.8k
  }
100
16.9k
}
101
102
}
103
104
EBOOKZlibStream::EBOOKZlibStream(librevenge::RVNGInputStream *const stream)
105
16.9k
  : m_stream()
106
16.9k
{
107
16.9k
  assert(stream);
108
109
16.9k
  if (0 != stream->seek(0, librevenge::RVNG_SEEK_SET))
110
0
    throw EndOfStreamException();
111
112
16.9k
  m_stream.reset(getInflatedStream(stream));
113
16.9k
}
114
115
EBOOKZlibStream::~EBOOKZlibStream()
116
16.3k
{
117
16.3k
}
118
119
bool EBOOKZlibStream::isStructured()
120
0
{
121
0
  return false;
122
0
}
123
124
unsigned EBOOKZlibStream::subStreamCount()
125
0
{
126
0
  return 0;
127
0
}
128
129
const char *EBOOKZlibStream::subStreamName(unsigned)
130
0
{
131
0
  return nullptr;
132
0
}
133
134
bool EBOOKZlibStream::existsSubStream(const char *)
135
0
{
136
0
  return false;
137
0
}
138
139
librevenge::RVNGInputStream *EBOOKZlibStream::getSubStreamByName(const char *)
140
0
{
141
0
  return nullptr;
142
0
}
143
144
librevenge::RVNGInputStream *EBOOKZlibStream::getSubStreamById(unsigned)
145
0
{
146
0
  return nullptr;
147
0
}
148
149
const unsigned char *EBOOKZlibStream::read(const unsigned long numBytes, unsigned long &numBytesRead)
150
1.25M
{
151
1.25M
  return m_stream->read(numBytes, numBytesRead);
152
1.25M
}
153
154
int EBOOKZlibStream::seek(long offset, const librevenge::RVNG_SEEK_TYPE seekType)
155
278k
{
156
278k
  return m_stream->seek(offset, seekType);
157
278k
}
158
159
long EBOOKZlibStream::tell()
160
507k
{
161
507k
  return m_stream->tell();
162
507k
}
163
164
bool EBOOKZlibStream::isEnd()
165
2.42M
{
166
2.42M
  return m_stream->isEnd();
167
2.42M
}
168
169
}
170
171
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */