Coverage Report

Created: 2026-07-20 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libzmf/src/lib/BMIHeader.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is a part of the libzmf 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 "BMIHeader.h"
11
#include <algorithm>
12
13
namespace libzmf
14
{
15
16
BMIHeader::BMIHeader()
17
92.7k
  : m_signature()
18
92.7k
  , m_size(0)
19
92.7k
  , m_startOffset(0)
20
92.7k
  , m_width(0)
21
92.7k
  , m_height(0)
22
92.7k
  , m_isPaletteMode(false)
23
92.7k
  , m_colorDepth(0)
24
92.7k
  , m_offsets()
25
92.7k
{
26
92.7k
}
27
28
bool BMIHeader::load(const RVNGInputStreamPtr &input)
29
92.7k
{
30
  // don't allow multiple calls
31
92.7k
  if (m_signature.length() > 0)
32
0
    throw GenericException();
33
34
92.7k
  m_startOffset = input->tell();
35
36
92.7k
  unsigned sigLen = 9;
37
92.7k
  m_signature.assign(reinterpret_cast<const char *>(readNBytes(input, sigLen)), sigLen);
38
39
92.7k
  m_width = readU16(input);
40
92.7k
  m_height = readU16(input);
41
42
92.7k
  m_isPaletteMode = static_cast<bool>(readU16(input));
43
44
92.7k
  m_colorDepth = readU16(input);
45
92.7k
  if (!(m_colorDepth == 1 || m_colorDepth == 4 || m_colorDepth == 8 || m_colorDepth == 24))
46
4.66k
  {
47
4.66k
    ZMF_DEBUG_MSG(("Invalid color depth %d\n", m_colorDepth));
48
4.66k
    return false;
49
4.66k
  }
50
51
88.0k
  skip(input, 2);
52
53
88.0k
  uint16_t offsetCount = readU16(input);
54
88.0k
  if (offsetCount == 0 || offsetCount > 6)
55
71
    return false;
56
57
87.9k
  if (m_isPaletteMode)
58
33.9k
  {
59
33.9k
    skip(input, 4 * paletteColorCount());
60
33.9k
  }
61
62
87.9k
  readOffsets(input, offsetCount);
63
64
87.9k
  return true;
65
88.0k
}
66
67
bool BMIHeader::isSupported() const
68
87.6k
{
69
87.6k
  return m_signature == "ZonerBMIa";
70
87.6k
}
71
unsigned BMIHeader::size() const
72
81.6k
{
73
81.6k
  return m_size;
74
81.6k
}
75
76
unsigned BMIHeader::startOffset() const
77
169k
{
78
169k
  return m_startOffset;
79
169k
}
80
81
unsigned BMIHeader::width() const
82
989
{
83
989
  return m_width;
84
989
}
85
86
unsigned BMIHeader::height() const
87
989
{
88
989
  return m_height;
89
989
}
90
91
bool BMIHeader::isPaletteMode() const
92
33.9k
{
93
33.9k
  return m_isPaletteMode;
94
33.9k
}
95
96
unsigned BMIHeader::colorDepth() const
97
33.9k
{
98
33.9k
  return m_colorDepth;
99
33.9k
}
100
101
unsigned BMIHeader::paletteColorCount() const
102
33.9k
{
103
33.9k
  return isPaletteMode() ? (1 << colorDepth()) : 0;
104
33.9k
}
105
106
const std::vector<BMIOffset> &BMIHeader::offsets() const
107
78.5k
{
108
78.5k
  return m_offsets;
109
78.5k
}
110
111
void BMIHeader::readOffsets(const RVNGInputStreamPtr &input, uint16_t offsetCount)
112
87.7k
{
113
585k
  for (unsigned i = 0; i < offsetCount; i++)
114
498k
  {
115
498k
    BMIOffset off;
116
117
498k
    auto type = readU16(input);
118
498k
    off.start = readU32(input);
119
120
498k
    switch (type)
121
498k
    {
122
96.3k
    case 0x1:
123
96.3k
      off.type = BMIStreamType::BITMAP;
124
96.3k
      break;
125
79.1k
    case 0xff:
126
79.1k
      off.type = BMIStreamType::END_OF_FILE;
127
79.1k
      m_size = off.start;
128
79.1k
      break;
129
322k
    default:
130
322k
      off.type = BMIStreamType::UNKNOWN;
131
322k
      break;
132
498k
    }
133
134
498k
    m_offsets.push_back(off);
135
498k
  }
136
137
87.6k
  std::sort(m_offsets.begin(), m_offsets.end(), [](const BMIOffset &a, const BMIOffset &b)
138
849k
  {
139
849k
    return (a.start < b.start);
140
849k
  });
141
142
87.6k
  m_offsets.erase(std::unique(m_offsets.begin(), m_offsets.end()), m_offsets.end());
143
144
480k
  for (size_t i = 0; i < m_offsets.size() - 1; i++)
145
392k
  {
146
392k
    m_offsets[i].end = m_offsets[i + 1].start;
147
392k
  }
148
87.6k
}
149
150
namespace
151
{
152
153
bool reconcileValue(unsigned &v1, unsigned &v2, unsigned &v3)
154
16.5k
{
155
16.5k
  if (v1 == v2)
156
8.48k
  {
157
8.48k
    if (v2 != v3)
158
8.07k
      v3 = v1;
159
8.48k
  }
160
8.03k
  else if (v1 == v3)
161
816
  {
162
816
    v2 = v1;
163
816
  }
164
7.21k
  else if (v2 == v3)
165
4.29k
  {
166
4.29k
    v1 = v2;
167
4.29k
  }
168
2.92k
  else
169
2.92k
  {
170
2.92k
    return false;
171
2.92k
  }
172
13.5k
  return true;
173
16.5k
}
174
175
}
176
177
bool BMIHeader::reconcileWidth(unsigned &colorWidth, unsigned &transparencyWidth)
178
9.25k
{
179
9.25k
  return reconcileValue(m_width, colorWidth, transparencyWidth);
180
9.25k
}
181
182
bool BMIHeader::reconcileHeight(unsigned &colorHeight, unsigned &transparencyHeight)
183
7.25k
{
184
7.25k
  return reconcileValue(m_height, colorHeight, transparencyHeight);
185
7.25k
}
186
187
}
188
189
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */