/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: */ |