1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "box/heif_box.h"
17 #include "box/basic_box.h"
18 #include "box/item_data_box.h"
19 #include "box/item_info_box.h"
20 #include "box/item_property_box.h"
21 #include "box/item_property_aux_box.h"
22 #include "box/item_property_basic_box.h"
23 #include "box/item_property_color_box.h"
24 #include "box/item_property_hvcc_box.h"
25 #include "box/item_property_transform_box.h"
26 #include "box/item_ref_box.h"
27 #include "box/item_property_display_box.h"
28
29 #define MAKE_BOX_CASE(box_type, box_class_type) \
30 case fourcc_to_code(box_type): \
31 box = std::make_shared<box_class_type>(); \
32 break
33
34 namespace {
35 const uint8_t UUID_TYPE_BYTE_NUM = 16;
36 const uint8_t LARGE_BOX_SIZE_TAG = 1;
37 }
38
39 namespace OHOS {
40 namespace ImagePlugin {
ParseHeader(HeifStreamReader & reader)41 heif_error HeifBox::ParseHeader(HeifStreamReader &reader)
42 {
43 // box size bytes + box type bytes
44 if (!reader.CheckSize(UINT64_BYTES_NUM)) {
45 return heif_error_eof;
46 }
47
48 boxSize_ = reader.Read32();
49 boxType_ = reader.Read32();
50
51 headerSize_ = UINT64_BYTES_NUM;
52
53 if (boxSize_ == LARGE_BOX_SIZE_TAG) {
54 if (!reader.CheckSize(UINT64_BYTES_NUM)) {
55 return heif_error_eof;
56 }
57 boxSize_ = reader.Read64();
58 headerSize_ += UINT64_BYTES_NUM;
59 }
60
61 if (boxType_ == BOX_TYPE_UUID) {
62 if (!reader.CheckSize(UUID_TYPE_BYTE_NUM)) {
63 return heif_error_eof;
64 }
65
66 boxUuidType_.resize(UUID_TYPE_BYTE_NUM);
67 reader.GetStream()->Read(reinterpret_cast<char*>(boxUuidType_.data()), UUID_TYPE_BYTE_NUM);
68 headerSize_ += UUID_TYPE_BYTE_NUM;
69 }
70
71 return reader.GetError();
72 }
73
InferHeaderSize() const74 int HeifBox::InferHeaderSize() const
75 {
76 int headerSize = UINT64_BYTES_NUM;
77 if (GetBoxType() == BOX_TYPE_UUID) {
78 headerSize += UUID_TYPE_BYTE_NUM;
79 }
80 return headerSize;
81 }
82
83
ReserveHeader(HeifStreamWriter & writer) const84 size_t HeifBox::ReserveHeader(HeifStreamWriter &writer) const
85 {
86 size_t startPos = writer.GetPos();
87 int header_size = InferHeaderSize();
88 writer.Skip(header_size);
89 return startPos;
90 }
91
92
ReserveHeader(HeifStreamWriter & writer) const93 size_t HeifFullBox::ReserveHeader(HeifStreamWriter &writer) const
94 {
95 size_t startPos = HeifBox::ReserveHeader(writer);
96 writer.Skip(UINT32_BYTES_NUM);
97 return startPos;
98 }
99
100
WriteHeader(HeifStreamWriter & writer,size_t boxSize) const101 heif_error HeifFullBox::WriteHeader(HeifStreamWriter &writer, size_t boxSize) const
102 {
103 auto err = HeifBox::WriteHeader(writer, boxSize);
104 if (err) {
105 return err;
106 }
107 writer.Write32((GetVersion() << THREE_BYTES_SHIFT) | GetFlags());
108 return heif_error_ok;
109 }
110
111
WriteCalculatedHeader(HeifStreamWriter & writer,size_t startPos) const112 heif_error HeifBox::WriteCalculatedHeader(HeifStreamWriter &writer, size_t startPos) const
113 {
114 size_t boxSize = writer.GetDataSize() - startPos;
115 writer.SetPos(startPos);
116 auto err = WriteHeader(writer, boxSize);
117 writer.SetPositionToEnd();
118 return err;
119 }
120
121
WriteHeader(HeifStreamWriter & writer,size_t boxSize) const122 heif_error HeifBox::WriteHeader(HeifStreamWriter &writer, size_t boxSize) const
123 {
124 bool isSizeNeed64Bit = (boxSize > 0xFFFFFFFF);
125 if (isSizeNeed64Bit) {
126 // set largeSize need insert (boxSize bytes + boxType bytes).
127 writer.Insert(UINT64_BYTES_NUM);
128 writer.Write32(LARGE_BOX_SIZE_TAG);
129 } else {
130 writer.Write32((uint32_t) boxSize);
131 }
132
133 writer.Write32(GetBoxType());
134
135 if (isSizeNeed64Bit) {
136 writer.Write64(boxSize);
137 }
138
139 if (GetBoxType() == BOX_TYPE_UUID) {
140 writer.Write(GetBoxUuidType());
141 }
142
143 return heif_error_ok;
144 }
145
ParseContent(HeifStreamReader & reader)146 heif_error HeifBox::ParseContent(HeifStreamReader &reader)
147 {
148 uint64_t contentSize = GetBoxSize() - GetHeaderSize();
149 if (reader.CheckSize(contentSize)) {
150 reader.GetStream()->Seek(reader.GetStream()->Tell() + GetBoxSize() - GetHeaderSize());
151 }
152
153 return reader.GetError();
154 }
155
ParseContentChildren(HeifStreamReader & reader,uint32_t & recursionCount)156 heif_error HeifBox::ParseContentChildren(HeifStreamReader &reader, uint32_t &recursionCount)
157 {
158 uint64_t contentSize = GetBoxSize() - GetHeaderSize();
159 if (reader.CheckSize(contentSize)) {
160 reader.GetStream()->Seek(reader.GetStream()->Tell() + GetBoxSize() - GetHeaderSize());
161 }
162
163 return reader.GetError();
164 }
165
ParseFullHeader(HeifStreamReader & reader)166 heif_error HeifFullBox::ParseFullHeader(HeifStreamReader &reader)
167 {
168 uint32_t data = reader.Read32();
169 version_ = static_cast<uint8_t>(data >> THREE_BYTES_SHIFT);
170 flags_ = data & 0x00FFFFFF;
171 headerSize_ += UINT32_BYTES_NUM;
172 return reader.GetError();
173 }
174
MakeBox(uint32_t boxType)175 std::shared_ptr<HeifBox> HeifBox::MakeBox(uint32_t boxType)
176 {
177 std::shared_ptr<HeifBox> box;
178 switch (boxType) {
179 MAKE_BOX_CASE("ftyp", HeifFtypBox);
180 MAKE_BOX_CASE("meta", HeifMetaBox);
181 MAKE_BOX_CASE("hdlr", HeifHdlrBox);
182 MAKE_BOX_CASE("pitm", HeifPtimBox);
183 MAKE_BOX_CASE("iinf", HeifIinfBox);
184 MAKE_BOX_CASE("infe", HeifInfeBox);
185 MAKE_BOX_CASE("iref", HeifIrefBox);
186 MAKE_BOX_CASE("iprp", HeifIprpBox);
187 MAKE_BOX_CASE("ipco", HeifIpcoBox);
188 MAKE_BOX_CASE("ipma", HeifIpmaBox);
189 MAKE_BOX_CASE("colr", HeifColrBox);
190 MAKE_BOX_CASE("hvcC", HeifHvccBox);
191 MAKE_BOX_CASE("ispe", HeifIspeBox);
192 MAKE_BOX_CASE("irot", HeifIrotBox);
193 MAKE_BOX_CASE("imir", HeifImirBox);
194 MAKE_BOX_CASE("pixi", HeifPixiBox);
195 MAKE_BOX_CASE("auxC", HeifAuxcBox);
196 MAKE_BOX_CASE("idat", HeifIdatBox);
197 MAKE_BOX_CASE("iloc", HeifIlocBox);
198 MAKE_BOX_CASE("rloc", HeifRlocBox);
199 MAKE_BOX_CASE("clli", HeifClliBox);
200 default:
201 box = std::make_shared<HeifBox>();
202 break;
203 }
204 return box;
205 }
206
BoxContentChildren(std::shared_ptr<HeifBox> box)207 bool BoxContentChildren(std::shared_ptr<HeifBox> box)
208 {
209 return box->GetBoxType() == BOX_TYPE_IPRP || box->GetBoxType() == BOX_TYPE_IPCO ||
210 box->GetBoxType() == BOX_TYPE_META || box->GetBoxType() == BOX_TYPE_IINF;
211 }
212
MakeFromReader(HeifStreamReader & reader,std::shared_ptr<HeifBox> * result,uint32_t & recursionCount)213 heif_error HeifBox::MakeFromReader(HeifStreamReader &reader,
214 std::shared_ptr<HeifBox> *result, uint32_t &recursionCount)
215 {
216 HeifBox headerBox;
217 heif_error err = headerBox.ParseHeader(reader);
218 if (err) {
219 return err;
220 }
221 if (reader.HasError()) {
222 return reader.GetError();
223 }
224 std::shared_ptr<HeifBox> box = HeifBox::MakeBox(headerBox.GetBoxType());
225 box->SetHeaderInfo(headerBox);
226 if (box->GetBoxSize() < box->GetHeaderSize()) {
227 return heif_error_invalid_box_size;
228 }
229 uint64_t boxContentSize = box->GetBoxSize() - box->GetHeaderSize();
230 if (!reader.CheckSize(boxContentSize)) {
231 return heif_error_eof;
232 }
233 HeifStreamReader contentReader(reader.GetStream(), reader.GetStream()->Tell(), boxContentSize);
234 if (BoxContentChildren(box)) {
235 err = box->ParseContentChildren(contentReader, recursionCount);
236 } else {
237 err = box->ParseContent(contentReader);
238 }
239 if (!err) {
240 *result = std::move(box);
241 }
242 if (err && box->GetBoxType() == BOX_TYPE_CLLI) {
243 err = heif_error_ok;
244 }
245 contentReader.SkipEnd();
246 return err;
247 }
248
Write(HeifStreamWriter & writer) const249 heif_error HeifBox::Write(HeifStreamWriter &writer) const
250 {
251 if (boxType_ == BOX_TYPE_MDAT || boxType_ == BOX_TYPE_IDAT) {
252 return heif_error_ok;
253 }
254
255 size_t boxStart = ReserveHeader(writer);
256
257 heif_error err = WriteChildren(writer);
258
259 WriteCalculatedHeader(writer, boxStart);
260
261 return err;
262 }
263
ReadChildren(HeifStreamReader & reader,uint32_t & recursionCount)264 heif_error HeifBox::ReadChildren(HeifStreamReader &reader, uint32_t &recursionCount)
265 {
266 while (!reader.IsAtEnd() && !reader.HasError()) {
267 std::shared_ptr<HeifBox> box;
268 heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
269 if (error != heif_error_ok) {
270 return error;
271 }
272 children_.push_back(std::move(box));
273 }
274 return reader.GetError();
275 }
276
WriteChildren(HeifStreamWriter & writer) const277 heif_error HeifBox::WriteChildren(HeifStreamWriter &writer) const
278 {
279 for (const auto &child: children_) {
280 if (child->GetBoxType() == BOX_TYPE_GRPL) {
281 continue;
282 }
283 heif_error err = child->Write(writer);
284 if (err) {
285 return err;
286 }
287 }
288 return heif_error_ok;
289 }
290
SetHeaderInfo(const HeifBox & box)291 void HeifBox::SetHeaderInfo(const HeifBox &box)
292 {
293 boxSize_ = box.boxSize_;
294 boxType_ = box.boxType_;
295 boxUuidType_ = box.boxUuidType_;
296 headerSize_ = box.headerSize_;
297 }
298
InferAllFullBoxVersion()299 void HeifBox::InferAllFullBoxVersion()
300 {
301 InferFullBoxVersion();
302
303 for (auto &child: children_) {
304 child->InferAllFullBoxVersion();
305 }
306 }
307 } // namespace ImagePlugin
308 } // namespace OHOS
309