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