Coverage Report

Created: 2026-10-28 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libe-book/src/lib/PDBLZ77Stream.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 "libebook_utils.h"
14
#include "EBOOKMemoryStream.h"
15
#include "PDBLZ77Stream.h"
16
17
using std::vector;
18
19
namespace libebook
20
{
21
22
namespace
23
{
24
25
void unpack(librevenge::RVNGInputStream *const stream, vector<unsigned char> &buffer)
26
2.22k
{
27
559k
  while (!stream->isEnd())
28
557k
  {
29
557k
    const unsigned char c = readU8(stream);
30
31
557k
    if ((c == 0x0) || ((c >= 0x9) && (c <= 0x7f)))
32
204k
    {
33
204k
      buffer.push_back(c);
34
204k
    }
35
353k
    else if ((c >= 0x1) && (c <= 0x8))
36
6.11k
    {
37
6.11k
      if (stream->isEnd()) // there is not enough bytes remaining
38
2
        throw GenericException();         // in the current record
39
40
24.7k
      for (unsigned char i = 0; i != c; ++i)
41
18.6k
        buffer.push_back(readU8(stream));
42
6.11k
    }
43
347k
    else if ((c >= 0x80) && (c <= 0xbf))
44
287k
    {
45
287k
      if (stream->isEnd()) // it's not possible to read another byte
46
3
        throw GenericException();    // from the current record
47
48
287k
      const unsigned byte1 = c & 0x3f; // drop the leftmost 2 bits
49
287k
      const unsigned byte2 = readU8(stream);
50
51
287k
      const unsigned combined = (byte1 << 8) | byte2;
52
      // combined contains 14 valid bits. Split them to 11 bits of
53
      // distance and 3 bits of length.
54
287k
      const unsigned distance = (combined & 0xfff8) >> 3;
55
287k
      const unsigned length = (combined & 0x7) + 3;
56
57
      // TODO: It's probably better idea to just ignore this and
58
      // continue reading with the next byte. The worst that can
59
      // happen is a missing piece of text.
60
287k
      if (distance > buffer.size()) // reading before this record
61
83
        throw GenericException();
62
287k
      if (0 == distance)
63
1
        throw GenericException();
64
65
287k
      if (length <= distance)
66
286k
      {
67
2.40M
        for (vector<unsigned char>::size_type i = buffer.size() - distance, last = i + length; i != last; ++i)
68
2.12M
          buffer.push_back(buffer[i]);
69
286k
      }
70
1.57k
      else
71
1.57k
      {
72
        // Apparently this is sometimes misused to construct sequences
73
        // of repeated characters, like ....
74
1.57k
        const char repeated = (char) *(buffer.end() - (int) distance);
75
1.57k
        buffer.insert(buffer.end(), length, (unsigned char) repeated);
76
1.57k
      }
77
287k
    }
78
59.6k
    else
79
59.6k
    {
80
59.6k
      buffer.push_back(' ');
81
59.6k
      buffer.push_back(c ^ 0x80);
82
59.6k
    }
83
557k
  }
84
2.22k
}
85
86
}
87
88
PDBLZ77Stream::PDBLZ77Stream(librevenge::RVNGInputStream *const stream)
89
2.22k
  : m_stream()
90
2.22k
{
91
2.22k
  assert(stream);
92
93
2.22k
  if (0 != stream->seek(0, librevenge::RVNG_SEEK_SET))
94
0
    throw EndOfStreamException();
95
96
2.22k
  vector<unsigned char> unpacked;
97
2.22k
  unpack(stream, unpacked);
98
99
2.22k
  if (unpacked.empty())
100
6
    throw GenericException();
101
102
2.21k
  m_stream.reset(new EBOOKMemoryStream(&unpacked[0], (unsigned) unpacked.size()));
103
2.21k
}
104
105
PDBLZ77Stream::~PDBLZ77Stream()
106
2.12k
{
107
2.12k
}
108
109
bool PDBLZ77Stream::isStructured()
110
0
{
111
0
  return false;
112
0
}
113
114
unsigned PDBLZ77Stream::subStreamCount()
115
0
{
116
0
  return 0;
117
0
}
118
119
const char *PDBLZ77Stream::subStreamName(unsigned)
120
0
{
121
0
  return nullptr;
122
0
}
123
124
bool PDBLZ77Stream::existsSubStream(const char *)
125
0
{
126
0
  return false;
127
0
}
128
129
librevenge::RVNGInputStream *PDBLZ77Stream::getSubStreamByName(const char *)
130
0
{
131
0
  return nullptr;
132
0
}
133
134
librevenge::RVNGInputStream *PDBLZ77Stream::getSubStreamById(unsigned)
135
0
{
136
0
  return nullptr;
137
0
}
138
139
const unsigned char *PDBLZ77Stream::read(const unsigned long numBytes, unsigned long &numBytesRead)
140
911k
{
141
911k
  return m_stream->read(numBytes, numBytesRead);
142
911k
}
143
144
int PDBLZ77Stream::seek(long offset, const librevenge::RVNG_SEEK_TYPE seekType)
145
1.82k
{
146
1.82k
  return m_stream->seek(offset, seekType);
147
1.82k
}
148
149
long PDBLZ77Stream::tell()
150
3.81k
{
151
3.81k
  return m_stream->tell();
152
3.81k
}
153
154
bool PDBLZ77Stream::isEnd()
155
1.81M
{
156
1.81M
  return m_stream->isEnd();
157
1.81M
}
158
159
}
160
161
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */