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 "heif_parser.h"
17 #include "box/item_property_aux_box.h"
18 #include "box/item_property_basic_box.h"
19 #include "box/item_property_display_box.h"
20 #include "box/item_property_transform_box.h"
21 #include "securec.h"
22 
23 #include <algorithm>
24 #include <limits>
25 #include <cstring>
26 #include <set>
27 
28 namespace OHOS {
29 namespace ImagePlugin {
30 
31 const auto EXIF_ID = "Exif\0\0";
32 const auto HEIF_AUXTTYPE_ID_FRAGMENT_MAP = "urn:com:huawei:photo:5:0:0:aux:fragmentmap";
33 const std::set<std::string> INFE_ITEM_TYPE = {
34     "hvc1", "grid", "tmap", "iden", "mime"
35 };
36 
37 HeifParser::HeifParser() = default;
38 
39 HeifParser::~HeifParser() = default;
40 
MakeFromMemory(const void * data,size_t size,bool isNeedCopy,std::shared_ptr<HeifParser> * out)41 heif_error HeifParser::MakeFromMemory(const void *data, size_t size, bool isNeedCopy, std::shared_ptr<HeifParser> *out)
42 {
43     if (data == nullptr) {
44         return heif_error_no_data;
45     }
46     auto input_stream = std::make_shared<HeifBufferInputStream>((const uint8_t *) data, size, isNeedCopy);
47     return MakeFromStream(input_stream, out);
48 }
49 
MakeFromStream(const std::shared_ptr<HeifInputStream> & stream,std::shared_ptr<HeifParser> * out)50 heif_error HeifParser::MakeFromStream(const std::shared_ptr<HeifInputStream> &stream, std::shared_ptr<HeifParser> *out)
51 {
52     if (stream == nullptr) {
53         return heif_error_no_data;
54     }
55     std::shared_ptr<HeifParser> file = std::make_shared<HeifParser>(stream);
56 
57     auto maxSize = static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
58     HeifStreamReader reader(stream, 0, maxSize);
59 
60     heif_error errorBox = file->AssembleBoxes(reader);
61     if (errorBox != heif_error_ok) {
62         return errorBox;
63     }
64 
65     heif_error errorImage = file->AssembleImages();
66     if (errorImage != heif_error_ok) {
67         return errorImage;
68     }
69 
70     *out = std::move(file);
71     return errorBox;
72 }
73 
Write(HeifStreamWriter & writer)74 void HeifParser::Write(HeifStreamWriter &writer)
75 {
76     CheckExtentData();
77     for (auto &box: topBoxes_) {
78         box->InferAllFullBoxVersion();
79         box->Write(writer);
80     }
81 
82     ilocBox_->WriteMdatBox(writer);
83 }
84 
GetPrimaryItemId() const85 heif_item_id HeifParser::GetPrimaryItemId() const
86 {
87     return pitmBox_->GetItemId();
88 }
89 
GetAllItemId(std::vector<heif_item_id> & itemIdList) const90 void HeifParser::GetAllItemId(std::vector<heif_item_id> &itemIdList) const
91 {
92     for (const auto &infeBox: infeBoxes_) {
93         itemIdList.push_back(infeBox.second->GetItemId());
94     }
95 }
96 
AssembleBoxes(HeifStreamReader & reader)97 heif_error HeifParser::AssembleBoxes(HeifStreamReader &reader)
98 {
99     while (true) {
100         std::shared_ptr<HeifBox> box;
101         uint32_t recursionCount = 0;
102         heif_error error = HeifBox::MakeFromReader(reader, &box, recursionCount);
103         if (reader.IsAtEnd() || error == heif_error_eof) {
104             break;
105         }
106         if (error != heif_error_ok) {
107             return error;
108         }
109         topBoxes_.push_back(box);
110         if (box->GetBoxType() == BOX_TYPE_META) {
111             metaBox_ = std::dynamic_pointer_cast<HeifMetaBox>(box);
112         }
113         if (box->GetBoxType() == BOX_TYPE_FTYP) {
114             ftypBox_ = std::dynamic_pointer_cast<HeifFtypBox>(box);
115         }
116     }
117 
118     if (!ftypBox_) {
119         return heif_error_no_ftyp;
120     }
121 
122     if (!metaBox_) {
123         return heif_error_no_meta;
124     }
125 
126     hdlrBox_ = metaBox_->GetChild<HeifHdlrBox>(BOX_TYPE_HDLR);
127     if (!hdlrBox_ || (hdlrBox_ && hdlrBox_->GetHandlerType() != HANDLER_TYPE_PICT)) {
128         return heif_error_invalid_handler;
129     }
130 
131     pitmBox_ = metaBox_->GetChild<HeifPtimBox>(BOX_TYPE_PITM);
132     if (!pitmBox_) {
133         return heif_error_no_pitm;
134     }
135 
136     iinfBox_ = metaBox_->GetChild<HeifIinfBox>(BOX_TYPE_IINF);
137     if (!iinfBox_) {
138         return heif_error_no_iinf;
139     }
140     std::vector<std::shared_ptr<HeifInfeBox>> infes = iinfBox_->GetChildren<HeifInfeBox>(BOX_TYPE_INFE);
141     for (auto &infe: infes) {
142         infeBoxes_.insert(std::make_pair(infe->GetItemId(), infe));
143     }
144 
145     irefBox_ = metaBox_->GetChild<HeifIrefBox>(BOX_TYPE_IREF);
146 
147     iprpBox_ = metaBox_->GetChild<HeifIprpBox>(BOX_TYPE_IPRP);
148     if (!iprpBox_) {
149         return heif_error_no_iprp;
150     }
151 
152     ipcoBox_ = iprpBox_->GetChild<HeifIpcoBox>(BOX_TYPE_IPCO);
153     if (!ipcoBox_) {
154         return heif_error_no_ipco;
155     }
156 
157     std::vector<std::shared_ptr<HeifIpmaBox>> ipmas = iprpBox_->GetChildren<HeifIpmaBox>(BOX_TYPE_IPMA);
158     if (ipmas.empty()) {
159         return heif_error_no_ipma;
160     }
161     ipmaBox_ = std::make_shared<HeifIpmaBox>();
162     for (auto &ipma : ipmas) {
163         ipmaBox_->MergeImpaBoxes(*ipma);
164     }
165     idatBox_ = metaBox_->GetChild<HeifIdatBox>(BOX_TYPE_IDAT);
166 
167     ilocBox_ = metaBox_->GetChild<HeifIlocBox>(BOX_TYPE_ILOC);
168     if (!ilocBox_) {
169         return heif_error_no_iloc;
170     }
171     return heif_error_ok;
172 }
173 
HasItemId(heif_item_id itemId) const174 bool HeifParser::HasItemId(heif_item_id itemId) const
175 {
176     return infeBoxes_.find(itemId) != infeBoxes_.end();
177 }
178 
GetItemType(heif_item_id itemId) const179 std::string HeifParser::GetItemType(heif_item_id itemId) const
180 {
181     auto infe_box = GetInfeBox(itemId);
182     if (!infe_box) {
183         return "";
184     }
185     return infe_box->GetItemType();
186 }
187 
GetItemContentType(heif_item_id itemId) const188 std::string HeifParser::GetItemContentType(heif_item_id itemId) const
189 {
190     auto infe_box = GetInfeBox(itemId);
191     if (!infe_box) {
192         return "";
193     }
194     return infe_box->GetContentType();
195 }
196 
GetItemUriType(heif_item_id itemId) const197 std::string HeifParser::GetItemUriType(heif_item_id itemId) const
198 {
199     auto infe_box = GetInfeBox(itemId);
200     if (!infe_box) {
201         return "";
202     }
203     return infe_box->GetItemUriType();
204 }
205 
206 
GetAllProperties(heif_item_id itemId,std::vector<std::shared_ptr<HeifBox>> & properties) const207 heif_error HeifParser::GetAllProperties(heif_item_id itemId, std::vector<std::shared_ptr<HeifBox>> &properties) const
208 {
209     if (!ipcoBox_) {
210         return heif_error_no_ipco;
211     }
212     if (!ipmaBox_) {
213         return heif_error_no_ipma;
214     }
215     return ipcoBox_->GetProperties(itemId, ipmaBox_, properties);
216 }
217 
GetGridLength(heif_item_id itemId,size_t & length)218 heif_error HeifParser::GetGridLength(heif_item_id itemId, size_t &length)
219 {
220     if (!HasItemId(itemId)) {
221         return heif_error_item_not_found;
222     }
223     auto items = ilocBox_->GetItems();
224     const HeifIlocBox::Item *ilocItem = nullptr;
225     auto iter = std::find_if(items.begin(), items.end(), [&itemId](const auto &item) {
226         return item.itemId == itemId;
227     });
228     if (iter != items.end()) {
229         ilocItem = &*iter;
230     } else {
231         return heif_error_item_data_not_found;
232     }
233     return ilocBox_->GetIlocDataLength(*ilocItem, length);
234 }
235 
GetItemData(heif_item_id itemId,std::vector<uint8_t> * out,heif_header_option option) const236 heif_error HeifParser::GetItemData(heif_item_id itemId, std::vector<uint8_t> *out, heif_header_option option) const
237 {
238     if (!HasItemId(itemId)) {
239         return heif_error_item_not_found;
240     }
241 
242     auto infe_box = GetInfeBox(itemId);
243     if (!infe_box) {
244         return heif_error_item_not_found;
245     }
246 
247     std::string item_type = infe_box->GetItemType();
248     auto items = ilocBox_->GetItems();
249     const HeifIlocBox::Item *ilocItem = nullptr;
250     for (const auto &item: items) {
251         if (item.itemId == itemId) {
252             ilocItem = &item;
253             break;
254         }
255     }
256     if (!ilocItem) {
257         return heif_error_item_data_not_found;
258     }
259 
260     heif_error error;
261     if (item_type == "hvc1") {
262         auto hvcc = GetProperty<HeifHvccBox>(itemId);
263         if (!hvcc) {
264             return heif_error_no_hvcc;
265         }
266         if (option != heif_no_header && !hvcc->GetHeaders(out)) {
267             return heif_error_item_data_not_found;
268         }
269         if (option != heif_only_header) {
270             error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
271         } else {
272             error = heif_error_ok;
273         }
274     } else {
275         error = ilocBox_->ReadData(*ilocItem, inputStream_, idatBox_, out);
276     }
277 
278     return error;
279 }
280 
GetTileImages(heif_item_id gridItemId,std::vector<std::shared_ptr<HeifImage>> & out)281 void HeifParser::GetTileImages(heif_item_id gridItemId, std::vector<std::shared_ptr<HeifImage>> &out)
282 {
283     auto infe = GetInfeBox(gridItemId);
284     if (!infe || infe->GetItemType() != "grid") {
285         return;
286     }
287     if (!irefBox_) {
288         return;
289     }
290     auto toItemIds = irefBox_->GetReferences(gridItemId, BOX_TYPE_DIMG);
291     for (heif_item_id toItemId: toItemIds) {
292         auto tileImage = GetImage(toItemId);
293         if (tileImage) {
294             out.push_back(tileImage);
295         }
296     }
297 }
298 
GetIdenImage(heif_item_id itemId,std::shared_ptr<HeifImage> & out)299 void HeifParser::GetIdenImage(heif_item_id itemId, std::shared_ptr<HeifImage> &out)
300 {
301     auto infe = GetInfeBox(itemId);
302     if (!infe || infe->GetItemType() != "iden") {
303         return;
304     }
305     if (!irefBox_) {
306         return;
307     }
308     auto toItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
309     for (heif_item_id toItemId: toItemIds) {
310         auto idenImage = GetImage(toItemId);
311         if (idenImage) {
312             out = idenImage;
313             return;
314         }
315     }
316 }
317 
GetInfeBox(heif_item_id itemId) const318 std::shared_ptr<HeifInfeBox> HeifParser::GetInfeBox(heif_item_id itemId) const
319 {
320     auto iter = infeBoxes_.find(itemId);
321     if (iter == infeBoxes_.end()) {
322         return nullptr;
323     }
324     return iter->second;
325 }
326 
AssembleImages()327 heif_error HeifParser::AssembleImages()
328 {
329     images_.clear();
330     primaryImage_.reset();
331 
332     std::vector<heif_item_id> allItemIds;
333     GetAllItemId(allItemIds);
334 
335     for (heif_item_id itemId: allItemIds) {
336         // extract Image Item
337         auto infe = GetInfeBox(itemId);
338         if (!infe) {
339             continue;
340         }
341         const std::string& itemType = infe->GetItemType();
342         if (INFE_ITEM_TYPE.find(itemType) == INFE_ITEM_TYPE.end()) {
343             continue;
344         }
345         auto image = std::make_shared<HeifImage>(itemId);
346         if (itemType == "tmap") {
347             tmapImage_ = image;
348             ExtractImageProperties(tmapImage_);
349             continue;
350         }
351         images_.insert(std::make_pair(itemId, image));
352         if (!infe->IsHidden() && itemId == GetPrimaryItemId()) {
353             image->SetPrimaryImage(true);
354             primaryImage_ = image;
355         }
356 
357         ExtractImageProperties(image);
358     }
359 
360     if (!primaryImage_) {
361         return heif_error_primary_item_not_found;
362     }
363 
364     ExtractGainmap(allItemIds);
365     ExtractDerivedImageProperties();
366     ExtractNonMasterImages();
367     ExtractMetadata(allItemIds);
368     return heif_error_ok;
369 }
370 
ExtractIT35Metadata(const heif_item_id & metadataItemId)371 void HeifParser::ExtractIT35Metadata(const heif_item_id& metadataItemId)
372 {
373     if (GetItemType(metadataItemId) != "it35") {
374         return;
375     }
376     std::vector<uint8_t> extendInfo;
377     heif_error err = GetItemData(metadataItemId, &(extendInfo));
378     if (err != heif_error_ok || extendInfo.empty()) {
379         return;
380     }
381     primaryImage_->SetUWAInfo(extendInfo);
382 }
383 
ExtractISOMetadata(const heif_item_id & itemId)384 void HeifParser::ExtractISOMetadata(const heif_item_id& itemId)
385 {
386     if (GetItemType(itemId) != "tmap") {
387         return;
388     }
389     std::vector<uint8_t> extendInfo;
390     heif_error err = GetItemData(itemId, &extendInfo);
391     if (err != heif_error_ok || extendInfo.empty()) {
392         return ;
393     }
394     primaryImage_->SetISOMetadata(extendInfo);
395 }
396 
ExtractFragmentMetadata(const heif_item_id & itemId)397 void HeifParser::ExtractFragmentMetadata(const heif_item_id& itemId)
398 {
399     HeifFragmentMetadata extendInfo;
400     auto ispe = GetProperty<HeifIspeBox>(itemId);
401     if (ispe) {
402         extendInfo.width = ispe->GetWidth();
403         extendInfo.height = ispe->GetHeight();
404     }
405     auto rloc = GetProperty<HeifRlocBox>(itemId);
406     if (rloc) {
407         extendInfo.horizontalOffset = rloc->GetX();
408         extendInfo.verticalOffset = rloc->GetY();
409     }
410     primaryImage_->SetFragmentMetadata(extendInfo);
411 }
412 
ExtractDisplayData(std::shared_ptr<HeifImage> & image,heif_item_id & itemId)413 void HeifParser::ExtractDisplayData(std::shared_ptr<HeifImage>& image, heif_item_id& itemId)
414 {
415     auto mdcv = GetProperty<HeifMdcvBox>(itemId);
416     auto clli = GetProperty<HeifClliBox>(itemId);
417     if (mdcv == nullptr && clli == nullptr) {
418         return;
419     }
420     DisplayColourVolume displayColourVolume{};
421     ContentLightLevelInfo lightInfo{};
422     uint32_t displaySize = sizeof(DisplayColourVolume);
423     std::vector<uint8_t> displayVec(displaySize);
424     if (mdcv) {
425         displayColourVolume = mdcv->GetColourVolume();
426         if (memcpy_s(displayVec.data(), displaySize, &displayColourVolume, displaySize) != EOK) {
427             displayVec.resize(0);
428         }
429     }
430 
431     uint32_t lightInfoSize = sizeof(ContentLightLevelInfo);
432     std::vector<uint8_t> lightInfoVec(lightInfoSize);
433     if (clli) {
434         lightInfo = clli->GetLightLevel();
435         if (memcpy_s(lightInfoVec.data(), lightInfoSize, &lightInfo, lightInfoSize) != EOK) {
436             lightInfoVec.resize(0);
437         }
438     }
439 
440     image->SetStaticMetadata(displayVec, lightInfoVec);
441 }
442 
ExtractGainmap(const std::vector<heif_item_id> & allItemIds)443 void HeifParser::ExtractGainmap(const std::vector<heif_item_id>& allItemIds)
444 {
445     for (heif_item_id itemId: allItemIds) {
446         // extract Image Item
447         auto infe = GetInfeBox(itemId);
448         if (!infe) {
449             continue;
450         }
451         const std::string& itemType = infe->GetItemType();
452         if (itemType == "it35") {
453             ExtractIT35Metadata(itemId);
454         }
455         if (itemType == "tmap") {
456             ExtractISOMetadata(itemId);
457             ExtractGainmapImage(itemId);
458         }
459     }
460 }
461 
ExtractImageProperties(std::shared_ptr<HeifImage> & image)462 void HeifParser::ExtractImageProperties(std::shared_ptr<HeifImage> &image)
463 {
464     heif_item_id itemId = image->GetItemId();
465 
466     auto ispe = GetProperty<HeifIspeBox>(itemId);
467     if (ispe) {
468         uint32_t width = ispe->GetWidth();
469         uint32_t height = ispe->GetHeight();
470         image->SetOriginalSize(width, height);
471     }
472 
473     auto irot = GetProperty<HeifIrotBox>(itemId);
474     if (irot) {
475         image->SetRotateDegrees(irot->GetRotDegree());
476     }
477 
478     auto imir = GetProperty<HeifImirBox>(itemId);
479     if (imir) {
480         image->SetMirrorDirection(imir->GetDirection());
481     }
482 
483     auto colr = GetProperty<HeifColrBox>(itemId);
484     if (colr) {
485         auto profile = colr->GetColorProfile();
486         image->SetColorProfile(profile);
487     }
488 
489     auto pixi = GetProperty<HeifPixiBox>(itemId);
490     if (pixi && pixi->GetChannelNum() == 1) {
491         image->SetDefaultColorFormat(HeifColorFormat::MONOCHROME);
492         image->SetDefaultPixelFormat(HeifPixelFormat::MONOCHROME);
493     } else {
494         image->SetDefaultColorFormat(HeifColorFormat::YCBCR);
495         image->SetDefaultPixelFormat(HeifPixelFormat::UNDEFINED);
496     }
497 
498     auto hvcc = GetProperty<HeifHvccBox>(itemId);
499     if (hvcc) {
500         auto hvccConfig = hvcc->GetConfig();
501         image->SetLumaBitNum(hvccConfig.bitDepthLuma);
502         image->SetChromaBitNum(hvccConfig.bitDepthChroma);
503         image->SetDefaultPixelFormat((HeifPixelFormat) hvccConfig.chromaFormat);
504 
505         auto nalArrays = hvcc->GetNalArrays();
506         hvcc->ParserHvccColorRangeFlag(nalArrays);
507         auto spsConfig = hvcc->GetSpsConfig();
508         image->SetColorRangeFlag(static_cast<int>(spsConfig.videoRangeFlag));
509     }
510     ExtractDisplayData(image, itemId);
511 }
512 
ExtractDerivedImageProperties()513 void HeifParser::ExtractDerivedImageProperties()
514 {
515     for (auto &pair: images_) {
516         heif_item_id itemId = pair.first;
517         auto infe = GetInfeBox(itemId);
518         if (!infe || (infe->GetItemType() != "grid" && infe->GetItemType() != "iden")) {
519             continue;
520         }
521         auto &image = pair.second;
522         if (!irefBox_) {
523             return;
524         }
525         auto tileItemIds = irefBox_->GetReferences(itemId, BOX_TYPE_DIMG);
526         if (tileItemIds.empty()) {
527             continue;
528         }
529         auto tileImage = GetImage(tileItemIds[0]);
530         if (tileImage == nullptr) {
531             continue;
532         }
533         if (image->GetLumaBitNum() < 0) {
534             image->SetLumaBitNum(tileImage->GetLumaBitNum());
535         }
536         if (image->GetChromaBitNum() < 0) {
537             image->SetChromaBitNum(tileImage->GetChromaBitNum());
538         }
539         if (image->GetDefaultPixelFormat() == HeifPixelFormat::UNDEFINED) {
540             image->SetDefaultPixelFormat(tileImage->GetDefaultPixelFormat());
541         }
542         if (image->GetDefaultColorFormat() == HeifColorFormat::UNDEDEFINED) {
543             image->SetDefaultColorFormat(tileImage->GetDefaultColorFormat());
544         }
545     }
546 }
547 
ExtractThumbnailImage(std::shared_ptr<HeifImage> & thumbnailImage,const HeifIrefBox::Reference & ref)548 void HeifParser::ExtractThumbnailImage(std::shared_ptr<HeifImage> &thumbnailImage, const HeifIrefBox::Reference &ref)
549 {
550     std::vector<heif_item_id> toItemIds = ref.toItemIds;
551     if (toItemIds.empty()) {
552         return;
553     }
554     heif_item_id masterItemId = toItemIds[0];
555     if (masterItemId == thumbnailImage->GetItemId()) {
556         return;
557     }
558     auto masterImage = GetImage(masterItemId);
559     if (!masterImage) {
560         return;
561     }
562 
563     thumbnailImage->SetThumbnailImage(masterItemId);
564     masterImage->AddThumbnailImage(thumbnailImage);
565 }
566 
ExtractAuxImage(std::shared_ptr<HeifImage> & auxImage,const HeifIrefBox::Reference & ref)567 void HeifParser::ExtractAuxImage(std::shared_ptr<HeifImage> &auxImage, const HeifIrefBox::Reference &ref)
568 {
569     std::vector<heif_item_id> toItemIds = ref.toItemIds;
570     if (toItemIds.empty()) {
571         return;
572     }
573     heif_item_id masterItemId = toItemIds[0];
574     heif_item_id auxItemId = auxImage->GetItemId();
575     if (masterItemId == auxItemId) {
576         return;
577     }
578     auto masterImage = GetImage(masterItemId);
579     if (!masterImage) {
580         return;
581     }
582     std::shared_ptr<HeifAuxcBox> auxc = GetProperty<HeifAuxcBox>(auxItemId);
583     if (!auxc) {
584         return;
585     }
586 
587     if (auxc->GetAuxType() == HEIF_AUXTTYPE_ID_FRAGMENT_MAP) {
588         ExtractFragmentMetadata(auxItemId);
589     }
590     auxImage->SetAuxImage(masterItemId, auxc->GetAuxType());
591     masterImage->AddAuxImage(auxImage);
592 }
593 
ExtractGainmapImage(const heif_item_id & tmapId)594 void HeifParser::ExtractGainmapImage(const heif_item_id& tmapId)
595 {
596     if (!irefBox_) {
597         return;
598     }
599     std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(tmapId);
600     for (const HeifIrefBox::Reference &ref : references) {
601         uint32_t type = ref.box.GetBoxType();
602         if (type != BOX_TYPE_DIMG) {
603             continue;
604         }
605         heif_item_id fromItemId = ref.fromItemId;
606         auto fromItemInfeBox = GetInfeBox(fromItemId);
607         if (fromItemInfeBox == nullptr) {
608             continue;
609         }
610         if (fromItemInfeBox->GetItemType() != "tmap") {
611             return;
612         }
613         std::vector<heif_item_id> toItemIds = ref.toItemIds;
614         const size_t tmapToItemSize = 2;
615         if (toItemIds.size() != tmapToItemSize) {
616             return;
617         }
618         const uint8_t baseIndex = 0;
619         const uint8_t gainmapIndex = 1;
620         heif_item_id baseId = toItemIds[baseIndex];
621         if (baseId != primaryImage_->GetItemId()) {
622             return;
623         }
624         heif_item_id gainmapId = toItemIds[gainmapIndex];
625         auto gainmapImage = GetImage(gainmapId);
626         if (gainmapImage == nullptr) {
627             return;
628         }
629         gainmapImage->SetGainmapMasterImage(baseId);
630         gainmapImage->SetTmapBoxId(tmapId);
631         primaryImage_->AddGainmapImage(gainmapImage);
632         primaryImage_->SetTmapBoxId(tmapId);
633     }
634 }
635 
ExtractNonMasterImages()636 void HeifParser::ExtractNonMasterImages()
637 {
638     if (!irefBox_) {
639         return;
640     }
641     for (auto &pair: images_) {
642         auto &image = pair.second;
643         std::vector<HeifIrefBox::Reference> references = irefBox_->GetReferencesFrom(image->GetItemId());
644         for (const HeifIrefBox::Reference &ref: references) {
645             uint32_t type = ref.box.GetBoxType();
646             if (type == BOX_TYPE_THMB) {
647                 ExtractThumbnailImage(image, ref);
648             } else if (type == BOX_TYPE_AUXL) {
649                 ExtractAuxImage(image, ref);
650             }
651         }
652     }
653 }
654 
ExtractMetadata(const std::vector<heif_item_id> & allItemIds)655 void HeifParser::ExtractMetadata(const std::vector<heif_item_id> &allItemIds)
656 {
657     if (!irefBox_) {
658         return;
659     }
660 
661     for (heif_item_id metadataItemId: allItemIds) {
662         std::vector<heif_item_id> toItemIds = irefBox_->GetReferences(metadataItemId, BOX_TYPE_CDSC);
663         if (toItemIds.empty()) {
664             continue;
665         }
666         heif_item_id masterImageId = toItemIds[0];
667         if (masterImageId == metadataItemId) {
668             continue;
669         }
670         auto masterImage = GetImage(masterImageId);
671         if (!masterImage) {
672             continue;
673         }
674 
675         std::shared_ptr<HeifMetadata> metadata = std::make_shared<HeifMetadata>();
676         metadata->itemId = metadataItemId;
677         metadata->itemType = GetItemType(metadataItemId);
678         metadata->contentType = GetItemContentType(metadataItemId);
679         metadata->itemUriType = GetItemUriType(metadataItemId);
680         heif_error err = GetItemData(metadataItemId, &(metadata->mData));
681         if (err != heif_error_ok) {
682             metadata.reset();
683             continue;
684         }
685         masterImage->AddMetadata(metadata);
686     }
687 }
688 
GetImage(heif_item_id itemId)689 std::shared_ptr<HeifImage> HeifParser::GetImage(heif_item_id itemId)
690 {
691     auto iter = images_.find(itemId);
692     if (iter == images_.end()) {
693         return nullptr;
694     }
695     return iter->second;
696 }
697 
GetPrimaryImage()698 std::shared_ptr<HeifImage> HeifParser::GetPrimaryImage()
699 {
700     return primaryImage_;
701 }
702 
GetGainmapImage()703 std::shared_ptr<HeifImage> HeifParser::GetGainmapImage()
704 {
705     return primaryImage_ != nullptr ? primaryImage_->GetGainmapImage() : nullptr;
706 }
707 
GetAuxiliaryMapImage(const std::string type)708 std::shared_ptr<HeifImage> HeifParser::GetAuxiliaryMapImage(const std::string type)
709 {
710     auto auxImages = primaryImage_->GetAuxImages();
711     for (auto image : auxImages) {
712         if (image->GetAuxImageType() == type) {
713             return image;
714         }
715     }
716     return nullptr;
717 }
718 
GetTmapImage()719 std::shared_ptr<HeifImage> HeifParser::GetTmapImage()
720 {
721     return tmapImage_;
722 }
723 
GetNextItemId() const724 heif_item_id HeifParser::GetNextItemId() const
725 {
726     heif_item_id max_id = 0;
727     for (const auto& infe: infeBoxes_) {
728         max_id = std::max(max_id, infe.second->GetItemId());
729     }
730     return max_id + 1;
731 }
732 
AddItem(const char * itemType,bool hidden)733 std::shared_ptr<HeifInfeBox> HeifParser::AddItem(const char *itemType, bool hidden)
734 {
735     heif_item_id newItemId = GetNextItemId();
736     auto newInfe = std::make_shared<HeifInfeBox>(newItemId, itemType, false);
737     newInfe->SetHidden(hidden);
738     infeBoxes_[newItemId] = newInfe;
739     if (iinfBox_ == nullptr) {
740         return nullptr;
741     }
742     iinfBox_->AddChild(newInfe);
743     return newInfe;
744 }
745 
AddIspeProperty(heif_item_id itemId,uint32_t width,uint32_t height)746 void HeifParser::AddIspeProperty(heif_item_id itemId, uint32_t width, uint32_t height)
747 {
748     auto ispe = std::make_shared<HeifIspeBox>();
749     ispe->SetDimension(width, height);
750     AddProperty(itemId, ispe, false);
751 }
752 
AddProperty(heif_item_id itemId,const std::shared_ptr<HeifBox> & property,bool essential)753 heif_property_id HeifParser::AddProperty(heif_item_id itemId, const std::shared_ptr<HeifBox>& property, bool essential)
754 {
755     int index = ipcoBox_->AddChild(property);
756     ipmaBox_->AddProperty(itemId, PropertyAssociation{essential, uint16_t(index + 1)});
757     return index + 1;
758 }
759 
AddPixiProperty(heif_item_id itemId,uint8_t c1,uint8_t c2,uint8_t c3)760 void HeifParser::AddPixiProperty(heif_item_id itemId, uint8_t c1, uint8_t c2, uint8_t c3)
761 {
762     auto pixi = std::make_shared<HeifPixiBox>();
763     pixi->AddBitNum(c1);
764     pixi->AddBitNum(c2);
765     pixi->AddBitNum(c3);
766     AddProperty(itemId, pixi, false);
767 }
768 
769 
AddHvccProperty(heif_item_id itemId)770 void HeifParser::AddHvccProperty(heif_item_id itemId)
771 {
772     auto hvcC = std::make_shared<HeifHvccBox>();
773     AddProperty(itemId, hvcC, true);
774 }
775 
AppendHvccNalData(heif_item_id itemId,const std::vector<uint8_t> & data)776 heif_error HeifParser::AppendHvccNalData(heif_item_id itemId, const std::vector<uint8_t> &data)
777 {
778     auto hvcc = GetProperty<HeifHvccBox>(itemId);
779     if (!hvcc) {
780         return heif_error_no_hvcc;
781     }
782     hvcc->AppendNalData(data);
783     return heif_error_ok;
784 }
785 
SetHvccConfig(heif_item_id itemId,const HvccConfig & config)786 heif_error HeifParser::SetHvccConfig(heif_item_id itemId, const HvccConfig &config)
787 {
788     auto hvcc = GetProperty<HeifHvccBox>(itemId);
789     if (!hvcc) {
790         return heif_error_no_hvcc;
791     }
792     hvcc->SetConfig(config);
793     return heif_error_ok;
794 }
795 
AppendIlocData(heif_item_id itemId,const std::vector<uint8_t> & data,uint8_t construction_method)796 void HeifParser::AppendIlocData(heif_item_id itemId, const std::vector<uint8_t> &data, uint8_t construction_method)
797 {
798     if (!ilocBox_) {
799         return;
800     }
801     ilocBox_->AppendData(itemId, data, construction_method);
802 }
803 
SetPrimaryItemId(heif_item_id itemId)804 void HeifParser::SetPrimaryItemId(heif_item_id itemId)
805 {
806     if (!pitmBox_) {
807         return;
808     }
809     pitmBox_->SetItemId(itemId);
810 }
811 
AddReference(heif_item_id fromItemId,uint32_t type,const std::vector<heif_item_id> & toItemIds)812 void HeifParser::AddReference(heif_item_id fromItemId, uint32_t type, const std::vector<heif_item_id> &toItemIds)
813 {
814     if (!irefBox_) {
815         irefBox_ = std::make_shared<HeifIrefBox>();
816         metaBox_->AddChild(irefBox_);
817     }
818     irefBox_->AddReferences(fromItemId, type, toItemIds);
819 }
820 
SetAuxcProperty(heif_item_id itemId,const std::string & type)821 void HeifParser::SetAuxcProperty(heif_item_id itemId, const std::string &type)
822 {
823     auto auxC = std::make_shared<HeifAuxcBox>();
824     auxC->SetAuxType(type);
825     AddProperty(itemId, auxC, true);
826 }
827 
SetColorProfile(heif_item_id itemId,const std::shared_ptr<const HeifColorProfile> & profile)828 void HeifParser::SetColorProfile(heif_item_id itemId, const std::shared_ptr<const HeifColorProfile> &profile)
829 {
830     auto colr = std::make_shared<HeifColrBox>();
831     colr->SetColorProfile(profile);
832     AddProperty(itemId, colr, false);
833 }
834 
CheckExtentData()835 void HeifParser::CheckExtentData()
836 {
837     const std::vector<HeifIlocBox::Item>& items = ilocBox_->GetItems();
838     for (const HeifIlocBox::Item& item: items) {
839         ilocBox_->ReadToExtentData(const_cast<HeifIlocBox::Item &>(item), inputStream_, idatBox_);
840     }
841 }
842 
SetPrimaryImage(const std::shared_ptr<HeifImage> & image)843 void HeifParser::SetPrimaryImage(const std::shared_ptr<HeifImage> &image)
844 {
845     if (primaryImage_) {
846         if (primaryImage_->GetItemId() == image->GetItemId()) {
847             return;
848         }
849         primaryImage_->SetPrimaryImage(false);
850     }
851     primaryImage_ = image;
852     image->SetPrimaryImage(true);
853     SetPrimaryItemId(image->GetItemId());
854 }
855 
GetExifHeaderOffset(const uint8_t * data,uint32_t size)856 uint32_t HeifParser::GetExifHeaderOffset(const uint8_t *data, uint32_t size)
857 {
858     uint32_t offset = 0;
859     const int endianSize = 4;
860     while (offset + endianSize < (unsigned int) size) {
861         if (!memcmp(data + offset, "MM\0*", endianSize) || !memcmp(data + offset, "II*\0", endianSize)) {
862             return offset;
863         }
864         offset++;
865     }
866     return offset;
867 }
868 
SetExifMetadata(const std::shared_ptr<HeifImage> & image,const uint8_t * data,uint32_t size)869 heif_error HeifParser::SetExifMetadata(const std::shared_ptr<HeifImage> &image, const uint8_t *data, uint32_t size)
870 {
871     uint32_t offset = GetExifHeaderOffset(data, size);
872     if (offset >= size) {
873         return heif_invalid_exif_data;
874     }
875 
876     std::vector<uint8_t> content;
877     content.resize(size + UINT32_BYTES_NUM);
878     std::string offsetFourcc = code_to_fourcc(offset);
879     for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
880         content[index] = (uint8_t)offsetFourcc[index];
881     }
882     if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != EOK) {
883         return heif_invalid_exif_data;
884     }
885     return SetMetadata(image, content, "Exif", nullptr);
886 }
887 
UpdateExifMetadata(const std::shared_ptr<HeifImage> & master_image,const uint8_t * data,uint32_t size,heif_item_id itemId)888 heif_error HeifParser::UpdateExifMetadata(const std::shared_ptr<HeifImage> &master_image, const uint8_t *data,
889                                           uint32_t size, heif_item_id itemId)
890 {
891     uint32_t offset = GetExifHeaderOffset(data, size);
892     if (offset >= (unsigned int) size) {
893         return heif_invalid_exif_data;
894     }
895 
896     std::vector<uint8_t> content;
897     content.resize(size + UINT32_BYTES_NUM);
898     std::string offsetFourcc = code_to_fourcc(offset);
899     for (int index = 0; index < UINT32_BYTES_NUM; ++index) {
900         content[index] = (uint8_t)offsetFourcc[index];
901     }
902 
903     if (memcpy_s(content.data() + UINT32_BYTES_NUM, size, data, size) != 0) {
904         return heif_invalid_exif_data;
905     }
906 
907     uint8_t construction_method = GetConstructMethod(itemId);
908 
909     return ilocBox_->UpdateData(itemId, content, construction_method);
910 }
911 
SetMetadata(const std::shared_ptr<HeifImage> & image,const std::vector<uint8_t> & data,const char * item_type,const char * content_type)912 heif_error HeifParser::SetMetadata(const std::shared_ptr<HeifImage> &image, const std::vector<uint8_t> &data,
913                                    const char *item_type, const char *content_type)
914 {
915     auto metadataInfe = AddItem(item_type, true);
916     if (content_type != nullptr) {
917         metadataInfe->SetContentType(content_type);
918     }
919 
920     heif_item_id metadataItemId = metadataInfe->GetItemId();
921     heif_item_id imageItemId = image->GetItemId();
922     AddReference(metadataItemId, BOX_TYPE_CDSC, {imageItemId});
923 
924     // store metadata in mdat
925     AppendIlocData(metadataItemId, data, 0);
926     return heif_error_ok;
927 }
928 
GetConstructMethod(const heif_item_id & id)929 uint8_t HeifParser::GetConstructMethod(const heif_item_id &id)
930 {
931     auto items = ilocBox_->GetItems();
932     for (const auto &item: items) {
933         if (item.itemId == id) {
934             return item.constructionMethod;
935         }
936     }
937 
938     // CONSTRUCTION_METHOD_FILE_OFFSET 0
939     return 0;
940 }
941 
SetTiffOffset()942 void HeifParser::SetTiffOffset()
943 {
944     if (tiffOffset_ != 0) {
945         return;
946     }
947     if (GetPrimaryImage() == nullptr) {
948         return;
949     }
950     auto metadataList = GetPrimaryImage()->GetAllMetadata();
951     heif_item_id exifId = 0;
952     for (auto metadata : metadataList) {
953         if (metadata && metadata->itemType == EXIF_ID) {
954             exifId = metadata->itemId;
955             break;
956         }
957     }
958     if (exifId == 0) {
959         return;
960     }
961 
962     if (!HasItemId(exifId)) {
963         return;
964     }
965 
966     auto items = ilocBox_->GetItems();
967     const HeifIlocBox::Item *ilocItem = nullptr;
968     for (const auto &item: items) {
969         if (item.itemId == exifId) {
970             ilocItem = &item;
971             break;
972         }
973     }
974     if (!ilocItem) {
975         return;
976     }
977 
978     tiffOffset_ = ilocItem->baseOffset;
979     if (!ilocItem->extents.empty()) {
980         tiffOffset_ += ilocItem->extents[0].offset;
981     }
982 }
983 } // namespace ImagePlugin
984 } // namespace OHOS
985