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 <fcntl.h>
17 #include <gtest/gtest.h>
18 #include <memory>
19 
20 #include "file_metadata_stream.h"
21 #include "image_source.h"
22 #include "media_errors.h"
23 #include "metadata_accessor.h"
24 
25 using namespace OHOS::Media;
26 using namespace testing::ext;
27 
28 namespace OHOS {
29 namespace Multimedia {
30 namespace {
31 static const std::string IMAGE_GET_FILTER_AREA_HEIF_PATH = "/data/local/tmp/image/get_filter_area.heic";
32 static const std::string IMAGE_GET_FILTER_AREA_JPEG_PATH = "/data/local/tmp/image/get_filter_area.jpg";
33 static const std::string IMAGE_GET_FILTER_AREA_PNG_PATH = "/data/local/tmp/image/get_filter_area.png";
34 static const std::string IMAGE_GET_FILTER_AREA_WEBP_PATH = "/data/local/tmp/image/get_filter_area.webp";
35 static const std::string IMAGE_GET_FILTER_AREA_DNG_PATH = "/data/local/tmp/image/get_filter_area.dng";
36 static const std::string IMAGE_GET_FILTER_AREA_DNG_FILTERED_PATH = "/data/local/tmp/image/get_filter_area_filtered.dng";
37 static const std::string IMAGE_NO_GPS_HEIF_PATH = "/data/local/tmp/image/test.heic";
38 static const std::string IMAGE_NO_GPS_JPEG_PATH = "/data/local/tmp/image/test_jpeg_readexifblob003.jpg";
39 static const std::string IMAGE_NO_GPS_PNG_PATH = "/data/local/tmp/image/test_exif.png";
40 static const std::string IMAGE_NO_GPS_WEBP_PATH = "/data/local/tmp/image/test_webp_readmetadata008.webp";
41 static const std::string IMAGE_INPUT_ITXT_WITHCOMPRESS_PNG_PATH =
42     "/data/local/tmp/image/test_chunk_itxt_withcompress.png";
43 static const uint8_t GPSAltitude[] = {0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
44 static const uint8_t GPSSatellites[] = {0x35, 0x20, 0x38, 0x20, 0x32, 0x30};
45 static const uint8_t GPSStatus[] = {0x56};
46 static const uint8_t GPSMeasureMode[] = {0x32};
47 static const uint8_t GPSDOP[] = {0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
48 static const uint8_t GPSSpeed[] = {0x46, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
49 static const uint8_t GPSTrackRef[] = {0x54};
50 static const uint8_t GPSTrack[] = {0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
51 static const uint8_t GPSImgDirection[] = {0x4a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
52 static const int MAX_FILE_SIZE = 1000 * 1000 * 100;
53 static const std::vector<std::string> gpsExifKeys{
54     "GPSAltitude",
55     "GPSSatellites",
56     "GPSStatus",
57     "GPSMeasureMode",
58     "GPSDOP",
59     "GPSSpeed",
60     "GPSTrackRef",
61     "GPSTrack",
62     "GPSImgDirection"
63 };
64 static const std::vector<std::string> dngExifKeys{
65         "GPSVersionID",
66         "GPSLatitudeRef",
67         "GPSLatitude",
68         "GPSLongitudeRef",
69         "GPSLongitude",
70         "GPSAltitude",
71         "GPSSatellites",
72         "GPSStatus",
73         "GPSMeasureMode",
74         "GPSDOP",
75         "GPSSpeed",
76         "GPSTrackRef",
77         "GPSTrack",
78         "GPSImgDirection",
79         "GPSDateStamp",
80         "GPSHPositioningError",
81         "Make",
82         "Model",
83         "DateTimeOriginal",
84         "LensMake",
85 };
86 }
87 
88 class ExifGetFilterAreaTest : public testing::Test {
89 public:
ExifGetFilterAreaTest()90     ExifGetFilterAreaTest() {}
~ExifGetFilterAreaTest()91     ~ExifGetFilterAreaTest() {}
92 
93     void CopyFileStream(std::fstream &src, std::fstream &dst);
94 };
95 
CopyFileStream(std::fstream & src,std::fstream & dst)96 void ExifGetFilterAreaTest::CopyFileStream(std::fstream &src, std::fstream &dst)
97 {
98     src.seekg(0, src.end);
99     long size = src.tellg();
100     src.seekg(0);
101     if (size > MAX_FILE_SIZE) {
102         return;
103     }
104     char* buffer = new char[size];
105     src.read(buffer, size);
106     dst.write(buffer, size);
107     delete[] buffer;
108     dst.seekg(0);
109 }
110 
111 /**
112  * @tc.name: GetFilterArea001
113  * @tc.desc: test GetFilterArea(filterType, ranges)
114  * @tc.type: FUNC
115  */
116 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea001, TestSize.Level3)
117 {
118     std::unique_ptr<std::fstream> fs = std::make_unique<std::fstream>();
119     fs->open(IMAGE_GET_FILTER_AREA_HEIF_PATH, std::fstream::binary | std::fstream::in);
120     bool isOpen = fs->is_open();
121     ASSERT_EQ(isOpen, true);
122     uint32_t errorCode = 0;
123     SourceOptions opts;
124     std::fstream& fileStream = *fs;
125     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode);
126     ASSERT_NE(imageSource, nullptr);
127     std::vector<std::pair<uint32_t, uint32_t>> ranges;
128     std::vector<std::vector<char>> contents;
129     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
130     ASSERT_EQ(ret, SUCCESS);
131     for (const auto& range : ranges) {
132         fileStream.seekg(range.first, std::ios::beg);
133         std::vector<char> content(range.second);
134         fileStream.read(reinterpret_cast<char *>(content.data()), range.second);
135         contents.push_back(content);
136     }
137     int i = 0;
138     ASSERT_EQ(std::memcmp(GPSAltitude, contents[i].data(), contents[i].size()), SUCCESS);
139     i++;
140     ASSERT_EQ(std::memcmp(GPSSatellites, contents[i].data(), contents[i].size()), SUCCESS);
141     i++;
142     ASSERT_EQ(std::memcmp(GPSStatus, contents[i].data(), contents[i].size()), SUCCESS);
143     i++;
144     ASSERT_EQ(std::memcmp(GPSMeasureMode, contents[i].data(), contents[i].size()), SUCCESS);
145     i++;
146     ASSERT_EQ(std::memcmp(GPSDOP, contents[i].data(), contents[i].size()), SUCCESS);
147     i++;
148     ASSERT_EQ(std::memcmp(GPSSpeed, contents[i].data(), contents[i].size()), SUCCESS);
149     i++;
150     ASSERT_EQ(std::memcmp(GPSTrackRef, contents[i].data(), contents[i].size()), SUCCESS);
151     i++;
152     ASSERT_EQ(std::memcmp(GPSTrack, contents[i].data(), contents[i].size()), SUCCESS);
153     i++;
154     ASSERT_EQ(std::memcmp(GPSImgDirection, contents[i].data(), contents[i].size()), SUCCESS);
155 }
156 
157 /**
158  * @tc.name: GetFilterArea002
159  * @tc.desc: test GetFilterArea(filterType, ranges)
160  * @tc.type: FUNC
161  */
162 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea002, TestSize.Level3)
163 {
164     std::unique_ptr<std::fstream> fs = std::make_unique<std::fstream>();
165     fs->open(IMAGE_GET_FILTER_AREA_PNG_PATH, std::fstream::binary | std::fstream::in);
166     bool isOpen = fs->is_open();
167     ASSERT_EQ(isOpen, true);
168     uint32_t errorCode = 0;
169     SourceOptions opts;
170     std::fstream& fileStream = *fs;
171     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode);
172     ASSERT_NE(imageSource, nullptr);
173     std::vector<std::pair<uint32_t, uint32_t>> ranges;
174     std::vector<std::vector<char>> contents;
175     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
176     ASSERT_EQ(ret, SUCCESS);
177     for (const auto& range : ranges) {
178         fileStream.seekg(range.first, std::ios::beg);
179         std::vector<char> content(range.second);
180         fileStream.read(reinterpret_cast<char *>(content.data()), range.second);
181         contents.push_back(content);
182     }
183     int i = 0;
184     ASSERT_EQ(std::memcmp(GPSAltitude, contents[i].data(), contents[i].size()), SUCCESS);
185     i++;
186     ASSERT_EQ(std::memcmp(GPSSatellites, contents[i].data(), contents[i].size()), SUCCESS);
187     i++;
188     ASSERT_EQ(std::memcmp(GPSStatus, contents[i].data(), contents[i].size()), SUCCESS);
189     i++;
190     ASSERT_EQ(std::memcmp(GPSMeasureMode, contents[i].data(), contents[i].size()), SUCCESS);
191     i++;
192     ASSERT_EQ(std::memcmp(GPSDOP, contents[i].data(), contents[i].size()), SUCCESS);
193     i++;
194     ASSERT_EQ(std::memcmp(GPSSpeed, contents[i].data(), contents[i].size()), SUCCESS);
195     i++;
196     ASSERT_EQ(std::memcmp(GPSTrackRef, contents[i].data(), contents[i].size()), SUCCESS);
197     i++;
198     ASSERT_EQ(std::memcmp(GPSTrack, contents[i].data(), contents[i].size()), SUCCESS);
199     i++;
200     ASSERT_EQ(std::memcmp(GPSImgDirection, contents[i].data(), contents[i].size()), SUCCESS);
201 }
202 
203 /**
204  * @tc.name: GetFilterArea003
205  * @tc.desc: test GetFilterArea(filterType, ranges)
206  * @tc.type: FUNC
207  */
208 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea003, TestSize.Level3)
209 {
210     std::unique_ptr<std::fstream> fs = std::make_unique<std::fstream>();
211     fs->open(IMAGE_GET_FILTER_AREA_JPEG_PATH, std::fstream::binary | std::fstream::in);
212     bool isOpen = fs->is_open();
213     ASSERT_EQ(isOpen, true);
214     uint32_t errorCode = 0;
215     SourceOptions opts;
216     std::fstream& fileStream = *fs;
217     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode);
218     ASSERT_NE(imageSource, nullptr);
219     std::vector<std::pair<uint32_t, uint32_t>> ranges;
220     std::vector<std::vector<char>> contents;
221     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
222     ASSERT_EQ(ret, SUCCESS);
223     for (const auto& range : ranges) {
224         fileStream.seekg(range.first, std::ios::beg);
225         std::vector<char> content(range.second);
226         fileStream.read(reinterpret_cast<char *>(content.data()), range.second);
227         contents.push_back(content);
228     }
229     int i = 0;
230     ASSERT_EQ(std::memcmp(GPSAltitude, contents[i].data(), contents[i].size()), SUCCESS);
231     i++;
232     ASSERT_EQ(std::memcmp(GPSSatellites, contents[i].data(), contents[i].size()), SUCCESS);
233     i++;
234     ASSERT_EQ(std::memcmp(GPSStatus, contents[i].data(), contents[i].size()), SUCCESS);
235     i++;
236     ASSERT_EQ(std::memcmp(GPSMeasureMode, contents[i].data(), contents[i].size()), SUCCESS);
237     i++;
238     ASSERT_EQ(std::memcmp(GPSDOP, contents[i].data(), contents[i].size()), SUCCESS);
239     i++;
240     ASSERT_EQ(std::memcmp(GPSSpeed, contents[i].data(), contents[i].size()), SUCCESS);
241     i++;
242     ASSERT_EQ(std::memcmp(GPSTrackRef, contents[i].data(), contents[i].size()), SUCCESS);
243     i++;
244     ASSERT_EQ(std::memcmp(GPSTrack, contents[i].data(), contents[i].size()), SUCCESS);
245     i++;
246     ASSERT_EQ(std::memcmp(GPSImgDirection, contents[i].data(), contents[i].size()), SUCCESS);
247 }
248 
249 /**
250  * @tc.name: GetFilterArea004
251  * @tc.desc: test GetFilterArea(filterType, ranges)
252  * @tc.type: FUNC
253  */
254 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea004, TestSize.Level3)
255 {
256     std::unique_ptr<std::fstream> fs = std::make_unique<std::fstream>();
257     fs->open(IMAGE_GET_FILTER_AREA_WEBP_PATH, std::fstream::binary | std::fstream::in);
258     bool isOpen = fs->is_open();
259     ASSERT_EQ(isOpen, true);
260     uint32_t errorCode = 0;
261     SourceOptions opts;
262     std::fstream& fileStream = *fs;
263     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(std::move(fs), opts, errorCode);
264     ASSERT_NE(imageSource, nullptr);
265     std::vector<std::pair<uint32_t, uint32_t>> ranges;
266     std::vector<std::vector<char>> contents;
267     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
268     ASSERT_EQ(ret, SUCCESS);
269     for (const auto& range : ranges) {
270         fileStream.seekg(range.first, std::ios::beg);
271         std::vector<char> content(range.second);
272         fileStream.read(reinterpret_cast<char *>(content.data()), range.second);
273         contents.push_back(content);
274     }
275     int i = 0;
276     ASSERT_EQ(std::memcmp(GPSAltitude, contents[i].data(), contents[i].size()), SUCCESS);
277     i++;
278     ASSERT_EQ(std::memcmp(GPSSatellites, contents[i].data(), contents[i].size()), SUCCESS);
279     i++;
280     ASSERT_EQ(std::memcmp(GPSStatus, contents[i].data(), contents[i].size()), SUCCESS);
281     i++;
282     ASSERT_EQ(std::memcmp(GPSMeasureMode, contents[i].data(), contents[i].size()), SUCCESS);
283     i++;
284     ASSERT_EQ(std::memcmp(GPSDOP, contents[i].data(), contents[i].size()), SUCCESS);
285     i++;
286     ASSERT_EQ(std::memcmp(GPSSpeed, contents[i].data(), contents[i].size()), SUCCESS);
287     i++;
288     ASSERT_EQ(std::memcmp(GPSTrackRef, contents[i].data(), contents[i].size()), SUCCESS);
289     i++;
290     ASSERT_EQ(std::memcmp(GPSTrack, contents[i].data(), contents[i].size()), SUCCESS);
291     i++;
292     ASSERT_EQ(std::memcmp(GPSImgDirection, contents[i].data(), contents[i].size()), SUCCESS);
293 }
294 
295 /**
296  * @tc.name: GetFilterArea
297  * @tc.desc: test GetFilterArea005
298  * @tc.type: FUNC
299  */
300 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea005, TestSize.Level3)
301 {
302     uint32_t errorCode = 0;
303     SourceOptions opts;
304     std::unique_ptr<ImageSource> imageSource =
305         ImageSource::CreateImageSource(IMAGE_GET_FILTER_AREA_WEBP_PATH, opts, errorCode);
306     ASSERT_NE(imageSource, nullptr);
307     std::vector<std::pair<uint32_t, uint32_t>> ranges;
308     std::vector<std::string> keys;
309     uint32_t ret = imageSource->GetFilterArea(keys, ranges);
310     ASSERT_EQ(ret, ERR_IMAGE_INVALID_PARAMETER);
311 }
312 
313 /**
314  * @tc.name: GetFilterArea
315  * @tc.desc: test GetFilterArea006
316  * @tc.type: FUNC
317  */
318 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea006, TestSize.Level3)
319 {
320     uint32_t errorCode = 0;
321     SourceOptions opts;
322     std::unique_ptr<ImageSource> imageSource =
323         ImageSource::CreateImageSource(IMAGE_INPUT_ITXT_WITHCOMPRESS_PNG_PATH, opts, errorCode);
324     ASSERT_NE(imageSource, nullptr);
325     std::vector<std::pair<uint32_t, uint32_t>> ranges;
326     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
327     ASSERT_EQ(ret, E_NO_EXIF_TAG);
328 }
329 
330 /**
331  * @tc.name: GetFilterArea
332  * @tc.desc: test GetFilterArea007
333  * @tc.type: FUNC
334  */
335 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea007, TestSize.Level3)
336 {
337     uint32_t errorCode = 0;
338     SourceOptions opts;
339     std::unique_ptr<ImageSource> imageSource =
340         ImageSource::CreateImageSource(IMAGE_NO_GPS_HEIF_PATH, opts, errorCode);
341     ASSERT_NE(imageSource, nullptr);
342     std::vector<std::pair<uint32_t, uint32_t>> ranges;
343     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
344     ASSERT_EQ(ret, E_NO_EXIF_TAG);
345 }
346 
347 /**
348  * @tc.name: GetFilterArea
349  * @tc.desc: test GetFilterArea008
350  * @tc.type: FUNC
351  */
352 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea008, TestSize.Level3)
353 {
354     uint32_t errorCode = 0;
355     SourceOptions opts;
356     std::unique_ptr<ImageSource> imageSource =
357         ImageSource::CreateImageSource(IMAGE_NO_GPS_JPEG_PATH, opts, errorCode);
358     ASSERT_NE(imageSource, nullptr);
359     std::vector<std::pair<uint32_t, uint32_t>> ranges;
360     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
361     ASSERT_EQ(ret, E_NO_EXIF_TAG);
362 }
363 
364 /**
365  * @tc.name: GetFilterArea
366  * @tc.desc: test GetFilterArea009
367  * @tc.type: FUNC
368  */
369 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea009, TestSize.Level3)
370 {
371     uint32_t errorCode = 0;
372     SourceOptions opts;
373     std::unique_ptr<ImageSource> imageSource =
374         ImageSource::CreateImageSource(IMAGE_NO_GPS_PNG_PATH, opts, errorCode);
375     ASSERT_NE(imageSource, nullptr);
376     std::vector<std::pair<uint32_t, uint32_t>> ranges;
377     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
378     ASSERT_EQ(ret, E_NO_EXIF_TAG);
379 }
380 
381 /**
382  * @tc.name: GetFilterArea
383  * @tc.desc: test GetFilterArea010
384  * @tc.type: FUNC
385  */
386 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea010, TestSize.Level3)
387 {
388     uint32_t errorCode = 0;
389     SourceOptions opts;
390     std::unique_ptr<ImageSource> imageSource =
391         ImageSource::CreateImageSource(IMAGE_NO_GPS_WEBP_PATH, opts, errorCode);
392     ASSERT_NE(imageSource, nullptr);
393     std::vector<std::pair<uint32_t, uint32_t>> ranges;
394     uint32_t ret = imageSource->GetFilterArea(gpsExifKeys, ranges);
395     ASSERT_EQ(ret, E_NO_EXIF_TAG);
396 }
397 
398 /**
399  * @tc.name: GetFilterArea011
400  * @tc.desc: test GetFilterArea dng
401  * @tc.type: FUNC
402  */
403 HWTEST_F(ExifGetFilterAreaTest, GetFilterArea011, TestSize.Level3)
404 {
405     std::unique_ptr<std::fstream> fs = std::make_unique<std::fstream>();
406     std::unique_ptr<std::fstream> fsOut = std::make_unique<std::fstream>();
407     fs->open(IMAGE_GET_FILTER_AREA_DNG_PATH, std::fstream::binary | std::fstream::in);
408     fsOut->open(IMAGE_GET_FILTER_AREA_DNG_FILTERED_PATH,
409                 std::fstream::binary | std::fstream::out);
410     bool isOpen = fs->is_open();
411     bool isOutOpen = fsOut->is_open();
412     ASSERT_EQ(isOpen && isOutOpen, true);
413     uint32_t errorCode = 0;
414     SourceOptions opts;
415     std::fstream& fileStream = *fs;
416     std::fstream& fileOutStream = *fsOut;
417     CopyFileStream(fileStream, fileOutStream);
418     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(
419             IMAGE_GET_FILTER_AREA_DNG_PATH, opts, errorCode);
420     ASSERT_NE(imageSource, nullptr);
421     std::vector<std::string> values;
422     for (int i = 0; i < dngExifKeys.size(); ++i) {
423         std::string tmp = "";
424         errorCode = imageSource->GetImagePropertyString(0, dngExifKeys[i], tmp);
425         ASSERT_EQ(errorCode, SUCCESS);
426         values.emplace_back(tmp);
427     }
428     std::vector<std::pair<uint32_t, uint32_t>> ranges;
429     uint32_t ret = imageSource->GetFilterArea(dngExifKeys, ranges);
430     ASSERT_EQ(ret, SUCCESS);
431     for (const auto& range : ranges) {
432         fileOutStream.seekg(range.first, std::ios::beg);
433         std::vector<char> buf(range.second, 0);
434         fileOutStream.write(reinterpret_cast<char *>(buf.data()), range.second);
435     }
436     fileOutStream.seekg(0);
437     fileOutStream.close();
438     fileStream.close();
439     std::unique_ptr<ImageSource> imageSource2 = ImageSource::CreateImageSource(
440             IMAGE_GET_FILTER_AREA_DNG_FILTERED_PATH, opts, errorCode);
441     ASSERT_NE(imageSource2, nullptr);
442     std::vector<std::string> filteredValues;
443     for (int i = 0; i < dngExifKeys.size(); ++i) {
444         std::string tmp = "";
445         errorCode = imageSource2->GetImagePropertyString(0, dngExifKeys[i], tmp);
446         ASSERT_EQ(errorCode, SUCCESS);
447         filteredValues.emplace_back(tmp);
448     }
449     ASSERT_EQ(values.size(), filteredValues.size());
450     for (int i = 0; i < dngExifKeys.size(); ++i) {
451         ASSERT_NE(values[i], filteredValues[i]);
452     }
453 }
454 } // namespace Multimedia
455 } // namespace OHOS