• 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_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