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 "buffer_metadata_stream.h"
17 #include "heif_error.h"
18 #include "heif_exif_metadata_accessor.h"
19 #include "heif_image.h"
20 #include "heif_type.h"
21 #include "image_log.h"
22 #include "media_errors.h"
23 #include "tiff_parser.h"
24 
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
27 
28 #undef LOG_TAG
29 #define LOG_TAG "HeifExifMetadataAccessor"
30 
31 namespace OHOS {
32 namespace Media {
33 using namespace ImagePlugin;
34 
35 const auto EXIF_ID = "Exif\0\0";
36 
HeifExifMetadataAccessor(std::shared_ptr<MetadataStream> & stream)37 HeifExifMetadataAccessor::HeifExifMetadataAccessor(std::shared_ptr<MetadataStream> &stream)
38     : AbstractExifMetadataAccessor(stream)
39 {}
40 
~HeifExifMetadataAccessor()41 HeifExifMetadataAccessor::~HeifExifMetadataAccessor() {}
42 
Read()43 uint32_t HeifExifMetadataAccessor::Read()
44 {
45     std::shared_ptr<HeifParser> parser;
46     heif_error parseRet = HeifParser::MakeFromMemory(imageStream_->GetAddr(), imageStream_->GetSize(), false, &parser);
47     if (parseRet != heif_error_ok) {
48         IMAGE_LOGE("The image source data is incorrect.");
49         return ERR_IMAGE_SOURCE_DATA;
50     }
51 
52     DataBuf dataBuf;
53     if (!GetExifItemData(parser, dataBuf)) {
54         IMAGE_LOGD("The EXIF value is invalid.");
55         return ERR_IMAGE_SOURCE_DATA;
56     }
57 
58     size_t byteOrderPos;
59     if (!CheckTiffPos(const_cast<byte *>(dataBuf.CData()), dataBuf.Size(), byteOrderPos)) {
60         IMAGE_LOGE("Failed to parse Exif metadata: cannot find tiff byte order");
61         return ERR_IMAGE_SOURCE_DATA;
62     }
63     ExifData *exifData = nullptr;
64     TiffParser::Decode(dataBuf.CData(byteOrderPos), dataBuf.Size() - byteOrderPos, &exifData);
65     if (exifData == nullptr) {
66         IMAGE_LOGE("Decode tiffBuf error.");
67         return ERR_EXIF_DECODE_FAILED;
68     }
69     tiffOffset_ = tiffOffset_ + static_cast<long>(byteOrderPos);
70     exifMetadata_ = std::make_shared<ExifMetadata>(exifData);
71     return SUCCESS;
72 }
73 
ReadBlob(DataBuf & blob)74 bool HeifExifMetadataAccessor::ReadBlob(DataBuf &blob)
75 {
76     return false;
77 }
78 
Write()79 uint32_t HeifExifMetadataAccessor::Write()
80 {
81     auto exfiMetadata = this->Get();
82     if (exfiMetadata == nullptr) {
83         IMAGE_LOGE("Heif metadata are not supported.");
84         return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
85     }
86 
87     ExifData *exifData = exfiMetadata->GetExifData();
88     if (exifData == nullptr) {
89         IMAGE_LOGE("Heif Exif format are not supported.");
90         return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
91     }
92 
93     uint_8 *dataBlob = nullptr;
94     uint32_t size = 0;
95     TiffParser::Encode(&dataBlob, size, exifData);
96 
97     if (dataBlob == nullptr) {
98         IMAGE_LOGE("Failed to encode exif matatdata.");
99         return ERR_MEDIA_WRITE_PARCEL_FAIL;
100     }
101 
102     size_t byteOrderPos;
103     DataBuf dataBuf(dataBlob, size);
104     if (!CheckTiffPos(const_cast<byte *>(dataBuf.CData()), dataBuf.Size(), byteOrderPos)) {
105         return ERR_MEDIA_WRITE_PARCEL_FAIL;
106     }
107     if (dataBlob != nullptr) {
108         free(dataBlob);
109         dataBlob = nullptr;
110     }
111     return WriteMetadata(dataBuf);
112 }
113 
WriteMetadata(DataBuf & dataBuf)114 uint32_t HeifExifMetadataAccessor::WriteMetadata(DataBuf &dataBuf)
115 {
116     std::shared_ptr<ImagePlugin::HeifParser> parser;
117     heif_error parseRet = HeifParser::MakeFromMemory(imageStream_->GetAddr(), imageStream_->GetSize(), false, &parser);
118     if (parseRet != heif_error_ok) {
119         IMAGE_LOGE("The EXIF data failed to parser.");
120         return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
121     }
122 
123     auto image = parser->GetPrimaryImage();
124     ImagePlugin::heif_item_id exifItemId;
125 
126     if (GetExifItemIdByHeifParser(parser, exifItemId)) {
127         if (parser->UpdateExifMetadata(image, dataBuf.CData(), dataBuf.Size(), exifItemId)
128                         != heif_error::heif_error_ok) {
129             IMAGE_LOGE("The EXIF data failed to update values.");
130             return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
131         }
132     } else {
133         if (parser->SetExifMetadata(image, dataBuf.CData(), dataBuf.Size())
134                         != heif_error::heif_error_ok) {
135             IMAGE_LOGE("The EXIF data failed to set values.");
136             return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
137         }
138     }
139 
140     HeifStreamWriter writer;
141     parser->Write(writer);
142     size_t dataSize = writer.GetDataSize();
143     if (dataSize == 0) {
144         IMAGE_LOGE("The EXIF data failed to be written to the file.");
145         return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
146     }
147 
148     const uint8_t *buf = writer.GetData().data();
149     if (buf == nullptr) {
150         return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
151     }
152 
153     BufferMetadataStream tmpBufStream;
154     tmpBufStream.Write(const_cast<uint8_t *>(buf), dataSize);
155     imageStream_->Seek(0, SeekPos::BEGIN);
156     imageStream_->CopyFrom(tmpBufStream);
157     return SUCCESS;
158 }
159 
WriteBlob(DataBuf & blob)160 uint32_t HeifExifMetadataAccessor::WriteBlob(DataBuf &blob)
161 {
162     return SUCCESS;
163 }
164 
CheckTiffPos(byte * buff,size_t size,size_t & byteOrderPos)165 bool HeifExifMetadataAccessor::CheckTiffPos(byte *buff, size_t size, size_t &byteOrderPos)
166 {
167     if (buff == nullptr) {
168         return false;
169     }
170 
171     // find the byte order "II 0x2a00" "MM 0x002a"
172     byteOrderPos = TiffParser::FindTiffPos(buff, size);
173     if (byteOrderPos == std::numeric_limits<size_t>::max()) {
174         return false;
175     }
176     return true;
177 }
178 
GetExifItemData(std::shared_ptr<HeifParser> & parser,DataBuf & dataBuf)179 bool HeifExifMetadataAccessor::GetExifItemData(std::shared_ptr<HeifParser> &parser, DataBuf &dataBuf)
180 {
181     ImagePlugin::heif_item_id exifItemId = 0xffff;
182     if (!GetExifItemIdByHeifParser(parser, exifItemId)) {
183         return false;
184     }
185 
186     std::vector<uint8_t> item;
187     if (parser->GetItemData(exifItemId, &item) != heif_error::heif_error_ok) {
188         return false;
189     }
190     tiffOffset_ = parser->GetTiffOffset();
191     dataBuf = DataBuf(item.data(), item.size());
192     return true;
193 }
194 
GetExifItemIdByHeifParser(std::shared_ptr<ImagePlugin::HeifParser> & parser,ImagePlugin::heif_item_id & exifItemId)195 bool HeifExifMetadataAccessor::GetExifItemIdByHeifParser(std::shared_ptr<ImagePlugin::HeifParser> &parser,
196     ImagePlugin::heif_item_id &exifItemId)
197 {
198     auto image = parser->GetPrimaryImage();
199     const std::vector<std::shared_ptr<HeifMetadata>> metadata = image->GetAllMetadata();
200     for (auto meta: metadata) {
201         if (meta == nullptr) {
202             continue;
203         }
204 
205         if (meta->itemType == EXIF_ID) {
206             exifItemId = meta->itemId;
207             return true;
208         }
209     }
210     return false;
211 }
212 } // namespace Media
213 } // namespace OHOS
214