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
28 #define MAKE_BOX_CASE(box_type, box_class_type) \
29 case fourcc_to_code(box_type): \
30 box = std::make_shared<box_class_type>(); \
31 break
32
33 namespace {
34 const uint8_t UUID_TYPE_BYTE_NUM = 16;
35 const uint8_t LARGE_BOX_SIZE_TAG = 1;
36 }
37
38 namespace OHOS {
39 namespace ImagePlugin {
ParseHeader(HeifStreamReader & reader)40 heif_error HeifBox::ParseHeader(HeifStreamReader &reader)
41 {
42 // box size bytes + box type bytes
43 if (!reader.CheckSize(UINT64_BYTES_NUM)) {
44 return heif_error_eof;
45 }
46
47 boxSize_ = reader.Read32();
48 boxType_ = reader.Read32();
49
50 headerSize_ = UINT64_BYTES_NUM;
51
52 if (boxSize_ == LARGE_BOX_SIZE_TAG) {
53 if (!reader.CheckSize(UINT64_BYTES_NUM)) {
54 return heif_error_eof;
55 }
56 boxSize_ = reader.Read64();
57 headerSize_ += UINT64_BYTES_NUM;
58 }
59
60 if (boxType_ == BOX_TYPE_UUID) {
61 if (!reader.CheckSize(UUID_TYPE_BYTE_NUM)) {
62 return heif_error_eof;
63 }
64
65 boxUuidType_.resize(UUID_TYPE_BYTE_NUM);
66 reader.GetStream()->Read(reinterpret_cast<char*>(boxUuidType_.data()), UUID_TYPE_BYTE_NUM);
67 headerSize_ += UUID_TYPE_BYTE_NUM;
68 }
69
70 return reader.GetError();
71 }
72
InferHeaderSize() const73 int HeifBox::InferHeaderSize() const
74 {
75 int headerSize = UINT64_BYTES_NUM;
76 if (GetBoxType() == BOX_TYPE_UUID) {
77 headerSize += UUID_TYPE_BYTE_NUM;
78 }
79 return headerSize;
80 }
81
82
ReserveHeader(HeifStreamWriter & writer) const83 size_t HeifBox::ReserveHeader(HeifStreamWriter &writer) const
84 {
85 size_t startPos = writer.GetPos();
86 int header_size = InferHeaderSize();
87 writer.Skip(header_size);
88 return startPos;
89 }
90
91
ReserveHeader(HeifStreamWriter & writer) const92 size_t HeifFullBox::ReserveHeader(HeifStreamWriter &writer) const
93 {
94 size_t startPos = HeifBox::ReserveHeader(writer);
95 writer.Skip(UINT32_BYTES_NUM);
96 return startPos;
97 }
98
99
WriteHeader(HeifStreamWriter & writer,size_t boxSize) const100 heif_error HeifFullBox::WriteHeader(HeifStreamWriter &writer, size_t boxSize) const
101 {
102 auto err = HeifBox::WriteHeader(writer, boxSize);
103 if (err) {
104 return err;
105 }
106 writer.Write32((GetVersion() << THREE_BYTES_SHIFT) | GetFlags());
107 return heif_error_ok;
108 }
109
110
WriteCalculatedHeader(HeifStreamWriter & writer,size_t startPos) const111 heif_error HeifBox::WriteCalculatedHeader(HeifStreamWriter &writer, size_t startPos) const
112 {
113 size_t boxSize = writer.GetDataSize() - startPos;
114 writer.SetPos(startPos);
115 auto err = WriteHeader(writer, boxSize);
116 writer.SetPositionToEnd();
117 return err;
118 }
119
120
WriteHeader(HeifStreamWriter & writer,size_t boxSize) const121 heif_error HeifBox::WriteHeader(HeifStreamWriter &writer, size_t boxSize) const
122 {
123 bool isSizeNeed64Bit = (boxSize > 0xFFFFFFFF);
124 if (isSizeNeed64Bit) {
125 // set largeSize need insert (boxSize bytes + boxType bytes).
126 writer.Insert(UINT64_BYTES_NUM);
127 writer.Write32(LARGE_BOX_SIZE_TAG);
128 } else {
129 writer.Write32((uint32_t) boxSize);
130 }
131
132 writer.Write32(GetBoxType());
133
134 if (isSizeNeed64Bit) {
135 writer.Write64(boxSize);
136 }
137
138 if (GetBoxType() == BOX_TYPE_UUID) {
139 writer.Write(GetBoxUuidType());
140 }
141
142 return heif_error_ok;
143 }
144
ParseContent(HeifStreamReader & reader)145 heif_error HeifBox::ParseContent(HeifStreamReader &reader)
146 {
147 uint64_t contentSize = GetBoxSize() - GetHeaderSize();
148 if (reader.CheckSize(contentSize)) {
149 reader.GetStream()->Seek(reader.GetStream()->Tell() + GetBoxSize() - GetHeaderSize());
150 }
151
152 return reader.GetError();
153 }
154
ParseContentChildren(HeifStreamReader & reader,uint32_t & recursionCount)155 heif_error HeifBox::ParseContentChildren(HeifStreamReader &reader, uint32_t &recursionCount)
156 {
157 uint64_t contentSize = GetBoxSize() - GetHeaderSize();
158 if (reader.CheckSize(contentSize)) {
159 reader.GetStream()->Seek(reader.GetStream()->Tell() + GetBoxSize() - GetHeaderSize());
160 }
161
162 return reader.GetError();
163 }
164
ParseFullHeader(HeifStreamReader & reader)165 heif_error HeifFullBox::ParseFullHeader(HeifStreamReader &reader)
166 {
167 uint32_t data = reader.Read32();
168 version_ = static_cast<uint8_t>(data >> THREE_BYTES_SHIFT);
169 flags_ = data & 0x00FFFFFF;
170 headerSize_ += UINT32_BYTES_NUM;
171 return reader.GetError();
172 }
173
MakeBox(uint32_t boxType)174 std::shared_ptr<HeifBox> HeifBox::MakeBox(uint32_t boxType)
175 {
176 std::shared_ptr<HeifBox> box;
177 switch (boxType) {
178 MAKE_BOX_CASE("ftyp", HeifFtypBox);
179 MAKE_BOX_CASE("meta", HeifMetaBox);
180 MAKE_BOX_CASE("hdlr", HeifHdlrBox);
181 MAKE_BOX_CASE("pitm", HeifPtimBox);
182 MAKE_BOX_CASE("iinf", HeifIinfBox);
183 MAKE_BOX_CASE("infe", HeifInfeBox);
184 MAKE_BOX_CASE("iref", HeifIrefBox);
185 MAKE_BOX_CASE("iprp", HeifIprpBox);
186 MAKE_BOX_CASE("ipco", HeifIpcoBox);
187 MAKE_BOX_CASE("ipma", HeifIpmaBox);
188 MAKE_BOX_CASE("colr", HeifColrBox);
189 MAKE_BOX_CASE("hvcC", HeifHvccBox);
190 MAKE_BOX_CASE("ispe", HeifIspeBox);
191 MAKE_BOX_CASE("irot", HeifIrotBox);
192 MAKE_BOX_CASE("imir", HeifImirBox);
193 MAKE_BOX_CASE("pixi", HeifPixiBox);
194 MAKE_BOX_CASE("auxC", HeifAuxcBox);
195 MAKE_BOX_CASE("idat", HeifIdatBox);
196 MAKE_BOX_CASE("iloc", HeifIlocBox);
197 MAKE_BOX_CASE("rloc", HeifRlocBox);
198 default:
199 box = std::make_shared<HeifBox>();
200 break;
201 }
202 return box;
203 }
204
BoxContentChildren(std::shared_ptr<HeifBox> box)205 bool BoxContentChildren(std::shared_ptr<HeifBox> box)
206 {
207 return box->GetBoxType() == BOX_TYPE_IPRP || box->GetBoxType() == BOX_TYPE_IPCO ||
208 box->GetBoxType() == BOX_TYPE_META || box->GetBoxType() == BOX_TYPE_IINF;
209 }
210
MakeFromReader(HeifStreamReader & reader,std::shared_ptr<HeifBox> * result,uint32_t & recursionCount)211 heif_error HeifBox::MakeFromReader(HeifStreamReader &reader,
212 std::shared_ptr<HeifBox> *result, uint32_t &recursionCount)
213 {
214 HeifBox headerBox;
215 heif_error err = headerBox.ParseHeader(reader);
216 if (err) {
217 return err;
218 }
219 if (reader.HasError()) {
220 return reader.GetError();
221 }
222 std::shared_ptr<HeifBox> box = HeifBox::MakeBox(headerBox.GetBoxType());
223 box->SetHeaderInfo(headerBox);
224 if (box->GetBoxSize() < box->GetHeaderSize()) {
225 return heif_error_invalid_box_size;
226 }
227 uint64_t boxContentSize = box->GetBoxSize() - box->GetHeaderSize();
228 if (!reader.CheckSize(boxContentSize)) {
229 return heif_error_eof;
230 }
231 HeifStreamReader contentReader(reader.GetStream(), reader.GetStream()->Tell(), boxContentSize);
232 if (BoxContentChildren(box)) {
233 err = box->ParseContentChildren(contentReader, recursionCount);
234 } else {
235 err = box->ParseContent(contentReader);
236 }
237 if (!err) {
238 *result = std::move(box);
239 }
240 contentReader.SkipEnd();
241 return err;
242 }
243
Write(HeifStreamWriter & writer) const244 heif_error HeifBox::Write(HeifStreamWriter &writer) const
245 {
246 if (boxType_ == BOX_TYPE_MDAT || boxType_ == BOX_TYPE_IDAT) {
247 return heif_error_ok;
248 }
249
250 size_t boxStart = ReserveHeader(writer);
251
252 heif_error err = WriteChildren(writer);
253
254 WriteCalculatedHeader(writer, boxStart);
255
256 return err;
257 }
258
ReadChildren(HeifStreamReader & reader,uint32_t & recursionCount)259 heif_error HeifBox::ReadChildren(HeifStreamReader &reader, uint32_t &recursionCount)
260 {
261 while (!reader.IsAtEnd() && !reader.HasError()) {
262 std::shared_ptr<HeifBox> box;
263 heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
264 if (error != heif_error_ok) {
265 return error;
266 }
267 children_.push_back(std::move(box));
268 }
269 return reader.GetError();
270 }
271
WriteChildren(HeifStreamWriter & writer) const272 heif_error HeifBox::WriteChildren(HeifStreamWriter &writer) const
273 {
274 for (const auto &child: children_) {
275 heif_error err = child->Write(writer);
276 if (err) {
277 return err;
278 }
279 }
280 return heif_error_ok;
281 }
282
SetHeaderInfo(const HeifBox & box)283 void HeifBox::SetHeaderInfo(const HeifBox &box)
284 {
285 boxSize_ = box.boxSize_;
286 boxType_ = box.boxType_;
287 boxUuidType_ = box.boxUuidType_;
288 headerSize_ = box.headerSize_;
289 }
290
InferAllFullBoxVersion()291 void HeifBox::InferAllFullBoxVersion()
292 {
293 InferFullBoxVersion();
294
295 for (auto &child: children_) {
296 child->InferAllFullBoxVersion();
297 }
298 }
299 } // namespace ImagePlugin
300 } // namespace OHOS
301