Coverage Report

Created: 2026-07-20 07:04

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
18.8k
{
33
18.8k
  if (0x78 != readU8(input)) // not a zlib stream
34
21
    throw ZlibStreamException();
35
36
18.8k
  const bool uncompressed = Z_NO_COMPRESSION == readU8(input);
37
38
18.8k
  auto begin = (unsigned long) input->tell();
39
18.8k
  input->seek(0, librevenge::RVNG_SEEK_END);
40
18.8k
  auto end = (unsigned long) input->tell();
41
18.8k
  unsigned long compressedSize = end - begin;
42
18.8k
  input->seek((long) begin, librevenge::RVNG_SEEK_SET);
43
44
18.8k
  if (0 == compressedSize) // No data?!
45
2
    throw ZlibStreamException();
46
47
18.8k
  unsigned long numBytesRead = 0;
48
18.8k
  auto *compressedData = const_cast<unsigned char *>(input->read(compressedSize, numBytesRead));
49
50
18.8k
  if (uncompressed)
51
1.10k
  {
52
1.10k
    if (numBytesRead != compressedSize)
53
0
      throw ZlibStreamException();
54
1.10k
    return new EBOOKMemoryStream(compressedData, static_cast<unsigned>(compressedSize));
55
1.10k
  }
56
17.7k
  else
57
17.7k
  {
58
17.7k
    int ret;
59
17.7k
    z_stream strm;
60
61
    /* allocate inflate state */
62
17.7k
    strm.zalloc = Z_NULL;
63
17.7k
    strm.zfree = Z_NULL;
64
17.7k
    strm.opaque = Z_NULL;
65
17.7k
    strm.avail_in = 0;
66
17.7k
    strm.next_in = Z_NULL;
67
17.7k
    ret = inflateInit2(&strm,-MAX_WBITS);
68
17.7k
    if (ret != Z_OK)
69
0
      throw ZlibStreamException();
70
71
17.7k
    strm.avail_in = (unsigned)numBytesRead;
72
17.7k
    strm.next_in = (Bytef *)compressedData;
73
17.7k
    strm.total_out = 0;
74
75
17.7k
    vector<unsigned char> data(2 * compressedSize);
76
77
103k
    while (true)
78
103k
    {
79
103k
      strm.next_out = reinterpret_cast<Bytef *>(&data[strm.total_out]);
80
103k
      strm.avail_out = uInt(data.size() - strm.total_out);
81
103k
      ret = inflate(&strm, Z_SYNC_FLUSH);
82
83
103k
      if (Z_STREAM_END == ret)
84
9.39k
        break;
85
94.3k
      if ((Z_OK == ret) && (0 == strm.avail_in) && (0 < strm.avail_out)) // end of stream too
86
7.54k
        break;
87
86.7k
      if (Z_OK != ret)
88
801
      {
89
801
        (void)inflateEnd(&strm);
90
801
        throw ZlibStreamException();
91
801
      }
92
93
85.9k
      data.resize(data.size() + compressedSize);
94
85.9k
    }
95
96
16.9k
    (void)inflateEnd(&strm);
97
98
16.9k
    return new EBOOKMemoryStream(&data[0], (unsigned) strm.total_out);
99
17.7k
  }
100
18.8k
}
101
102
}
103
104
EBOOKZlibStream::EBOOKZlibStream(librevenge::RVNGInputStream *const stream)
105
18.8k
  : m_stream()
106
18.8k
{
107
18.8k
  assert(stream);
108
109
18.8k
  if (0 != stream->seek(0, librevenge::RVNG_SEEK_SET))
110
0
    throw EndOfStreamException();
111
112
18.8k
  m_stream.reset(getInflatedStream(stream));
113
18.8k
}
114
115
EBOOKZlibStream::~EBOOKZlibStream()
116
18.0k
{
117
18.0k
}
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
133M
{
151
133M
  return m_stream->read(numBytes, numBytesRead);
152
133M
}
153
154
int EBOOKZlibStream::seek(long offset, const librevenge::RVNG_SEEK_TYPE seekType)
155
373k
{
156
373k
  return m_stream->seek(offset, seekType);
157
373k
}
158
159
long EBOOKZlibStream::tell()
160
558k
{
161
558k
  return m_stream->tell();
162
558k
}
163
164
bool EBOOKZlibStream::isEnd()
165
262M
{
166
262M
  return m_stream->isEnd();
167
262M
}
168
169
}
170
171
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */