• 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 
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 
ParseFullHeader(HeifStreamReader & reader)155 heif_error HeifFullBox::ParseFullHeader(HeifStreamReader &reader)
156 {
157     uint32_t data = reader.Read32();
158     version_ = static_cast<uint8_t>(data >> THREE_BYTES_SHIFT);
159     flags_ = data & 0x00FFFFFF;
160     headerSize_ += UINT32_BYTES_NUM;
161     return reader.GetError();
162 }
163 
MakeBox(uint32_t boxType)164 std::shared_ptr<HeifBox> HeifBox::MakeBox(uint32_t boxType)
165 {
166     std::shared_ptr<HeifBox> box;
167     switch (boxType) {
168         MAKE_BOX_CASE("ftyp", HeifFtypBox);
169         MAKE_BOX_CASE("meta", HeifMetaBox);
170         MAKE_BOX_CASE("hdlr", HeifHdlrBox);
171         MAKE_BOX_CASE("pitm", HeifPtimBox);
172         MAKE_BOX_CASE("iinf", HeifIinfBox);
173         MAKE_BOX_CASE("infe", HeifInfeBox);
174         MAKE_BOX_CASE("iref", HeifIrefBox);
175         MAKE_BOX_CASE("iprp", HeifIprpBox);
176         MAKE_BOX_CASE("ipco", HeifIpcoBox);
177         MAKE_BOX_CASE("ipma", HeifIpmaBox);
178         MAKE_BOX_CASE("colr", HeifColrBox);
179         MAKE_BOX_CASE("hvcC", HeifHvccBox);
180         MAKE_BOX_CASE("ispe", HeifIspeBox);
181         MAKE_BOX_CASE("irot", HeifIrotBox);
182         MAKE_BOX_CASE("imir", HeifImirBox);
183         MAKE_BOX_CASE("pixi", HeifPixiBox);
184         MAKE_BOX_CASE("auxC", HeifAuxcBox);
185         MAKE_BOX_CASE("idat", HeifIdatBox);
186         MAKE_BOX_CASE("iloc", HeifIlocBox);
187         MAKE_BOX_CASE("rloc", HeifRlocBox);
188         default:
189             box = std::make_shared<HeifBox>();
190             break;
191     }
192     return box;
193 }
194 
MakeFromReader(HeifStreamReader & reader,std::shared_ptr<HeifBox> * result)195 heif_error HeifBox::MakeFromReader(HeifStreamReader &reader, std::shared_ptr<HeifBox> *result)
196 {
197     HeifBox headerBox;
198     heif_error err = headerBox.ParseHeader(reader);
199     if (err) {
200         return err;
201     }
202     if (reader.HasError()) {
203         return reader.GetError();
204     }
205     std::shared_ptr<HeifBox> box = HeifBox::MakeBox(headerBox.GetBoxType());
206     box->SetHeaderInfo(headerBox);
207     if (box->GetBoxSize() < box->GetHeaderSize()) {
208         return heif_error_invalid_box_size;
209     }
210     uint64_t boxContentSize = box->GetBoxSize() - box->GetHeaderSize();
211     if (!reader.CheckSize(boxContentSize)) {
212         return heif_error_eof;
213     }
214     HeifStreamReader contentReader(reader.GetStream(), reader.GetStream()->Tell(), boxContentSize);
215     err = box->ParseContent(contentReader);
216     if (!err) {
217         *result = std::move(box);
218     }
219     contentReader.SkipEnd();
220     return err;
221 }
222 
Write(HeifStreamWriter & writer) const223 heif_error HeifBox::Write(HeifStreamWriter &writer) const
224 {
225     if (boxType_ == BOX_TYPE_MDAT || boxType_ == BOX_TYPE_IDAT) {
226         return heif_error_ok;
227     }
228 
229     size_t boxStart = ReserveHeader(writer);
230 
231     heif_error err = WriteChildren(writer);
232 
233     WriteCalculatedHeader(writer, boxStart);
234 
235     return err;
236 }
237 
ReadChildren(HeifStreamReader & reader)238 heif_error HeifBox::ReadChildren(HeifStreamReader &reader)
239 {
240     int count = 0;
241     while (!reader.IsAtEnd() && !reader.HasError()) {
242         std::shared_ptr<HeifBox> box;
243         heif_error error = HeifBox::MakeFromReader(reader, &box);
244         if (error != heif_error_ok) {
245             return error;
246         }
247         children_.push_back(std::move(box));
248         count++;
249     }
250     return reader.GetError();
251 }
252 
WriteChildren(HeifStreamWriter & writer) const253 heif_error HeifBox::WriteChildren(HeifStreamWriter &writer) const
254 {
255     for (const auto &child: children_) {
256         heif_error err = child->Write(writer);
257         if (err) {
258             return err;
259         }
260     }
261     return heif_error_ok;
262 }
263 
SetHeaderInfo(const HeifBox & box)264 void HeifBox::SetHeaderInfo(const HeifBox &box)
265 {
266     boxSize_ = box.boxSize_;
267     boxType_ = box.boxType_;
268     boxUuidType_ = box.boxUuidType_;
269     headerSize_ = box.headerSize_;
270 }
271 
InferAllFullBoxVersion()272 void HeifBox::InferAllFullBoxVersion()
273 {
274     InferFullBoxVersion();
275 
276     for (auto &child: children_) {
277         child->InferAllFullBoxVersion();
278     }
279 }
280 } // namespace ImagePlugin
281 } // namespace OHOS
282