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