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_movie_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("moov", HeifMoovBox);
200 MAKE_BOX_CASE("mvhd", HeifMvhdBox);
201 MAKE_BOX_CASE("trak", HeifTrakBox);
202 MAKE_BOX_CASE("tkhd", HeifTkhdBox);
203 MAKE_BOX_CASE("mdia", HeifMdiaBox);
204 MAKE_BOX_CASE("mdhd", HeifMdhdBox);
205 MAKE_BOX_CASE("minf", HeifMinfBox);
206 MAKE_BOX_CASE("vmhd", HeifVmhdBox);
207 MAKE_BOX_CASE("dinf", HeifDinfBox);
208 MAKE_BOX_CASE("dref", HeifDrefBox);
209 MAKE_BOX_CASE("stbl", HeifStblBox);
210 MAKE_BOX_CASE("stsd", HeifStsdBox);
211 MAKE_BOX_CASE("hvc1", HeifHvc1Box);
212 MAKE_BOX_CASE("stts", HeifSttsBox);
213 MAKE_BOX_CASE("stsc", HeifStscBox);
214 MAKE_BOX_CASE("stco", HeifStcoBox);
215 MAKE_BOX_CASE("stsz", HeifStszBox);
216 default:
217 box = std::make_shared<HeifBox>();
218 break;
219 }
220 return box;
221 }
222
BoxContentChildren(std::shared_ptr<HeifBox> box)223 bool BoxContentChildren(std::shared_ptr<HeifBox> box)
224 {
225 return box->GetBoxType() == BOX_TYPE_IPRP || box->GetBoxType() == BOX_TYPE_IPCO ||
226 box->GetBoxType() == BOX_TYPE_META || box->GetBoxType() == BOX_TYPE_IINF ||
227 box->GetBoxType() == BOX_TYPE_MOOV || box->GetBoxType() == BOX_TYPE_TRAK ||
228 box->GetBoxType() == BOX_TYPE_MDIA || box->GetBoxType() == BOX_TYPE_DINF ||
229 box->GetBoxType() == BOX_TYPE_STBL || box->GetBoxType() == BOX_TYPE_MINF;
230 }
231
MakeFromReader(HeifStreamReader & reader,std::shared_ptr<HeifBox> * result,uint32_t & recursionCount)232 heif_error HeifBox::MakeFromReader(HeifStreamReader &reader,
233 std::shared_ptr<HeifBox> *result, uint32_t &recursionCount)
234 {
235 HeifBox headerBox;
236 heif_error err = headerBox.ParseHeader(reader);
237 if (err) {
238 return err;
239 }
240 if (reader.HasError()) {
241 return reader.GetError();
242 }
243 std::shared_ptr<HeifBox> box = HeifBox::MakeBox(headerBox.GetBoxType());
244 box->SetHeaderInfo(headerBox);
245 if (box->GetBoxSize() < box->GetHeaderSize()) {
246 return heif_error_invalid_box_size;
247 }
248 uint64_t boxContentSize = box->GetBoxSize() - box->GetHeaderSize();
249 if (!reader.CheckSize(boxContentSize)) {
250 return heif_error_eof;
251 }
252 HeifStreamReader contentReader(reader.GetStream(), reader.GetStream()->Tell(), boxContentSize);
253 if (BoxContentChildren(box)) {
254 err = box->ParseContentChildren(contentReader, recursionCount);
255 } else {
256 err = box->ParseContent(contentReader);
257 }
258 if (!err) {
259 *result = std::move(box);
260 }
261 contentReader.SkipEnd();
262 return err;
263 }
264
Write(HeifStreamWriter & writer) const265 heif_error HeifBox::Write(HeifStreamWriter &writer) const
266 {
267 if (boxType_ == BOX_TYPE_MDAT || boxType_ == BOX_TYPE_IDAT) {
268 return heif_error_ok;
269 }
270
271 size_t boxStart = ReserveHeader(writer);
272
273 heif_error err = WriteChildren(writer);
274
275 WriteCalculatedHeader(writer, boxStart);
276
277 return err;
278 }
279
ReadChildren(HeifStreamReader & reader,uint32_t & recursionCount)280 heif_error HeifBox::ReadChildren(HeifStreamReader &reader, uint32_t &recursionCount)
281 {
282 while (!reader.IsAtEnd() && !reader.HasError()) {
283 std::shared_ptr<HeifBox> box;
284 heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
285 if (error != heif_error_ok) {
286 return error;
287 }
288 children_.push_back(std::move(box));
289 }
290 return reader.GetError();
291 }
292
WriteChildren(HeifStreamWriter & writer) const293 heif_error HeifBox::WriteChildren(HeifStreamWriter &writer) const
294 {
295 for (const auto &child: children_) {
296 heif_error err = child->Write(writer);
297 if (err) {
298 return err;
299 }
300 }
301 return heif_error_ok;
302 }
303
SetHeaderInfo(const HeifBox & box)304 void HeifBox::SetHeaderInfo(const HeifBox &box)
305 {
306 boxSize_ = box.boxSize_;
307 boxType_ = box.boxType_;
308 boxUuidType_ = box.boxUuidType_;
309 headerSize_ = box.headerSize_;
310 }
311
InferAllFullBoxVersion()312 void HeifBox::InferAllFullBoxVersion()
313 {
314 InferFullBoxVersion();
315
316 for (auto &child: children_) {
317 child->InferAllFullBoxVersion();
318 }
319 }
320
ParseContentChildrenByReadChildren(HeifStreamReader & reader,uint32_t & recursionCount)321 heif_error HeifBox::ParseContentChildrenByReadChildren(HeifStreamReader &reader, uint32_t &recursionCount)
322 {
323 recursionCount++;
324 if (recursionCount > MAX_RECURSION_COUNT) {
325 return heif_error_too_many_recursion;
326 }
327 return ReadChildren(reader, recursionCount);
328 }
329 } // namespace ImagePlugin
330 } // namespace OHOS
331