• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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