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 <cmath>
17 #include <iostream>
18 #include <regex>
19 #include <string_view>
20 #include <set>
21 #include <string>
22 #include <sstream>
23 #include <utility>
24 #include <charconv>
25 #include <system_error>
26
27 #include "exif_metadata_formatter.h"
28 #include "hilog/log_cpp.h"
29 #include "hilog/log.h"
30 #include "image_log.h"
31 #include "media_errors.h"
32 #include "string_ex.h"
33
34 #undef LOG_DOMAIN
35 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
36
37 #undef LOG_TAG
38 #define LOG_TAG "ExifMetadatFormatter"
39
40 namespace OHOS {
41 namespace Media {
42
43 const auto GPS_DEGREE_SIZE = 2;
44 const auto GPS_NORMAL_SIZE = 3;
45 const double GPS_MAX_LATITUDE = 90.0;
46 const double GPS_MIN_LATITUDE = 0.0;
47 const double GPS_MAX_LONGITUDE = 180.0;
48 const double GPS_MIN_LONGITUDE = 0.0;
49 const int CONSTANT_0 = 0;
50 const int CONSTANT_1 = 1;
51 const int CONSTANT_2 = 2;
52
53 const static std::set<std::string> READ_WRITE_KEYS = {
54 "BitsPerSample",
55 "Orientation",
56 "ImageLength",
57 "ImageWidth",
58 "GPSLatitude",
59 "GPSLongitude",
60 "GPSLatitudeRef",
61 "GPSLongitudeRef",
62 "DateTimeOriginal",
63 "ExposureTime",
64 "SceneType",
65 "ISOSpeedRatings",
66 "FNumber",
67 "DateTime",
68 "GPSTimeStamp",
69 "GPSDateStamp",
70 "ImageDescription",
71 "Make",
72 "Model",
73 "PhotoMode",
74 "SensitivityType",
75 "StandardOutputSensitivity",
76 "RecommendedExposureIndex",
77 "ISOSpeed",
78 "ApertureValue",
79 "ExposureBiasValue",
80 "MeteringMode",
81 "LightSource",
82 "Flash",
83 "FocalLength",
84 "UserComment",
85 "PixelXDimension",
86 "PixelYDimension",
87 "WhiteBalance",
88 "FocalLengthIn35mmFilm",
89 "CompressedBitsPerPixel",
90 "JPEGProc",
91 "Compression",
92 "PhotometricInterpretation",
93 "StripOffsets",
94 "SamplesPerPixel",
95 "RowsPerStrip",
96 "StripByteCounts",
97 "XResolution",
98 "YResolution",
99 "PlanarConfiguration",
100 "ResolutionUnit",
101 "TransferFunction",
102 "Software",
103 "Artist",
104 "WhitePoint",
105 "PrimaryChromaticities",
106 "YCbCrCoefficients",
107 "YCbCrSubSampling",
108 "YCbCrPositioning",
109 "ReferenceBlackWhite",
110 "Copyright",
111 "SubsecTime",
112 "SubsecTimeOriginal",
113 "SubsecTimeDigitized",
114 "FlashpixVersion",
115 "ColorSpace",
116 "RelatedSoundFile",
117 "FlashEnergy",
118 "SpatialFrequencyResponse",
119 "FocalPlaneXResolution",
120 "FocalPlaneYResolution",
121 "FocalPlaneResolutionUnit",
122 "SubjectLocation",
123 "ExposureIndex",
124 "SensingMethod",
125 "FileSource",
126 "CFAPattern",
127 "CustomRendered",
128 "ExposureMode",
129 "DigitalZoomRatio",
130 "SceneCaptureType",
131 "GainControl",
132 "Contrast",
133 "Saturation",
134 "Sharpness",
135 "DeviceSettingDescription",
136 "SubjectDistanceRange",
137 "ImageUniqueID",
138 "GPSVersionID",
139 "GPSAltitudeRef",
140 "GPSAltitude",
141 "GPSSatellites",
142 "GPSStatus",
143 "GPSMeasureMode",
144 "GPSDOP",
145 "GPSSpeedRef",
146 "GPSSpeed",
147 "GPSTrackRef",
148 "GPSTrack",
149 "GPSImgDirectionRef",
150 "GPSImgDirection",
151 "GPSMapDatum",
152 "GPSDestLatitudeRef",
153 "GPSDestLatitude",
154 "GPSDestLongitudeRef",
155 "GPSDestLongitude",
156 "GPSDestBearingRef",
157 "GPSDestBearing",
158 "GPSDestDistanceRef",
159 "GPSDestDistance",
160 "GPSProcessingMethod",
161 "GPSAreaInformation",
162 "GPSDifferential",
163 "ComponentsConfiguration",
164 "ISOSpeedLatitudeyyy",
165 "ISOSpeedLatitudezzz",
166 "SubjectDistance",
167 "DefaultCropSize",
168 "LensSpecification",
169 "SubjectArea",
170 "DNGVersion",
171 "SubfileType",
172 "NewSubfileType",
173 "LensMake",
174 "LensModel",
175 "LensSerialNumber",
176 "OffsetTimeDigitized",
177 "OffsetTimeOriginal",
178 "SourceExposureTimesOfCompositeImage",
179 "SourceImageNumberOfCompositeImage",
180 "GPSHPositioningError",
181 "Orientation",
182 "GPSLongitudeRef",
183 "ExposureProgram",
184 "SpectralSensitivity",
185 "OECF",
186 "ExifVersion",
187 "DateTimeDigitized",
188 "ShutterSpeedValue",
189 "BrightnessValue",
190 "MaxApertureValue",
191 "BodySerialNumber",
192 "CameraOwnerName",
193 "CompositeImage",
194 "Gamma",
195 "OffsetTime",
196 "PhotographicSensitivity",
197 "HwMnoteCaptureMode",
198 "HwMnoteIsXmageSupported",
199 "HwMnoteXmageMode",
200 "HwMnoteXmageLeft",
201 "HwMnoteXmageTop",
202 "HwMnoteXmageRight",
203 "HwMnoteXmageBottom",
204 "HwMnoteCloudEnhancementMode",
205 "MovingPhotoId",
206 "MovingPhotoVersion",
207 "MicroVideoPresentationTimestampUS",
208 "HwMnoteAiEdit",
209 "MakerNote",
210 };
211
212 const static std::set<std::string> READ_ONLY_KEYS = {
213 "HwMnotePhysicalAperture",
214 "HwMnoteRollAngle", "HwMnotePitchAngle",
215 "HwMnoteSceneFoodConf", "HwMnoteSceneStageConf",
216 "HwMnoteSceneBlueSkyConf", "HwMnoteSceneGreenPlantConf",
217 "HwMnoteSceneBeachConf", "HwMnoteSceneSnowConf",
218 "HwMnoteSceneSunsetConf", "HwMnoteSceneFlowersConf",
219 "HwMnoteSceneNightConf", "HwMnoteSceneTextConf",
220 "HwMnoteFaceCount", "HwMnoteFocusMode",
221 "HwMnoteFrontCamera", "HwMnoteSceneVersion",
222 "HwMnoteScenePointer", "HwMnoteFacePointer",
223 "HwMnoteBurstNumber", "HwMnoteFaceVersion",
224 "HwMnoteFaceConf", "HwMnoteFaceSmileScore",
225 "HwMnoteFaceRect", "HwMnoteFaceLeyeCenter",
226 "HwMnoteFaceReyeCenter", "HwMnoteFaceMouthCenter",
227 "JPEGInterchangeFormat", "JPEGInterchangeFormatLength",
228 "HwMnoteWindSnapshotMode", "HwMnoteFocusModeExif",
229 };
230
231 // Orientation, tag 0x0112
232 constexpr TagDetails exifOrientation[] = {
233 {1, "Top-left"}, {2, "Top-right"}, {3, "Bottom-right"},
234 {4, "Bottom-left"}, {5, "Left-top"}, {6, "Right-top"},
235 {7, "Right-bottom" }, {8, "Left-bottom"},
236 };
237
238 // GPS latitude reference, tag 0x0001; also GPSDestLatitudeRef, tag 0x0013
239 constexpr TagDetails exifGPSLatitudeRef[] = {
240 {78, "North"},
241 {83, "South"},
242 };
243
244 constexpr TagDetails exifGPSLongitudeRef[] = {
245 {69, "East"},
246 {87, "West"},
247 };
248
249 // WhiteBalance, tag 0xa403
250 constexpr TagDetails exifWhiteBalance[] = {
251 {0, "Auto white balance"},
252 {1, "Manual white balance"},
253 };
254
255 // Flash, Exif tag 0x9209
256 constexpr TagDetails exifFlash[] = {
257 {0x00, "Flash did not fire"},
258 {0x01, "Flash fired"},
259 {0x05, "Strobe return light not detected"},
260 {0x07, "Strobe return light detected"},
261 {0x08, "Flash did not fire"},
262 {0x09, "Flash fired, compulsory flash mode"},
263 {0x0d, "Flash fired, compulsory flash mode, return light not detected"},
264 {0x0f, "Flash fired, compulsory flash mode, return light detected"},
265 {0x10, "Flash did not fire, compulsory flash mode"},
266 {0x18, "Flash did not fire, auto mode"},
267 {0x19, "Flash fired, auto mode"},
268 {0x1d, "Flash fired, auto mode, return light not detected"},
269 {0x1f, "Flash fired, auto mode, return light detected"},
270 {0x20, "No flash function"},
271 {0x41, "Flash fired, red-eye reduction mode"},
272 {0x45, "Flash fired, red-eye reduction mode, return light not detected"},
273 {0x47, "Flash fired, red-eye reduction mode, return light detected"},
274 {0x49, "Flash fired, compulsory flash mode, red-eye reduction mode"},
275 {0x4d, "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected"},
276 {0x4f, "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected"},
277 {0x58, "Flash did not fire, auto mode, red-eye reduction mode"},
278 {0x59, "Flash fired, auto mode, red-eye reduction mode"},
279 {0x5d, "Flash fired, auto mode, return light not detected, red-eye reduction mode"},
280 {0x5f, "Flash fired, auto mode, return light detected, red-eye reduction mode"},
281 };
282
283 // ColorSpace, tag 0xa001
284 constexpr TagDetails exifColorSpace[] = {
285 {1, "sRGB"},
286 {2, "Adobe RGB"}, // Not defined to Exif 2.2 spec. But used by a lot of cameras.
287 {0xffff, "Uncalibrated"},
288 };
289
290 // LightSource, tag 0x9208
291 constexpr TagDetails exifLightSource[] = {
292 {0, "Unknown"},
293 {1, "Daylight"},
294 {2, "Fluorescent"},
295 {3, "Tungsten incandescent light"},
296 {4, "Flash"},
297 {9, "Fine weather"},
298 {10, "Cloudy weather"},
299 {11, "Shade"},
300 {12, "Daylight fluorescent"},
301 {13, "Day white fluorescent"},
302 {14, "Cool white fluorescent"},
303 {15, "White fluorescent"},
304 {17, "Standard light A"},
305 {18, "Standard light B"},
306 {19, "Standard light C"},
307 {20, "D55"},
308 {21, "D65"},
309 {22, "D75"},
310 {23, "D50"},
311 {24, "ISO studio tungsten"},
312 {255, "Other"},
313 };
314
315 // MeteringMode, tag 0x9207
316 constexpr TagDetails exifMeteringMode[] = {
317 {0, "Unknown"}, {1, "Average"}, {2, "Center-weighted average"},
318 {3, "Spot"}, {4, "Multi spot"}, {5, "Pattern"},
319 {6, "Partial"}, {255, "Other"},
320 };
321
322 // SceneType, tag 0xa301
323 constexpr TagDetails exifSceneType[] = {
324 {1, "Directly photographed"},
325 };
326
327 // Compression, tag 0x0103
328 constexpr TagDetails exifCompression[] = {
329 {1, "Uncompressed"},
330 {2, "CCITT RLE"},
331 {3, "T4/Group 3 Fax"},
332 {4, "T6/Group 4 Fax"},
333 {5, "LZW compression"},
334 {6, "JPEG (old-style) compression"},
335 {7, "JPEG compression"},
336 {8, "Deflate/ZIP compression"},
337 {9, "JBIG B&W"},
338 {10, "JBIG Color"},
339 {32766, "Next 2-bits RLE"},
340 {32767, "Sony ARW Compressed"},
341 {32769, "Epson ERF Compressed"},
342 {32770, "Samsung SRW Compressed"},
343 {32771, "CCITT RLE 1-word"},
344 {32773, "PackBits compression"},
345 {32809, "Thunderscan RLE"},
346 {32895, "IT8 CT Padding"},
347 {32896, "IT8 Linework RLE"},
348 {32897, "IT8 Monochrome Picture"},
349 {32898, "IT8 Binary Lineart"},
350 {32908, "Pixar Film (10-bits LZW)"},
351 {32909, "Pixar Log (11-bits ZIP)"},
352 {32946, "Pixar Deflate"},
353 {32947, "Kodak DCS Encoding"},
354 {34661, "ISO JBIG"},
355 {34676, "SGI Log Luminance RLE"},
356 {34677, "SGI Log 24-bits packed"},
357 {34712, "Leadtools JPEG 2000"},
358 {34713, "Nikon NEF Compressed"},
359 {34892, "JPEG (lossy)"}, // DNG 1.4
360 {52546, "JPEG XL"}, // DNG 1.7
361 {65000, "Kodak DCR Compressed"},
362 {65535, "Pentax PEF Compressed"},
363 };
364
365 // PhotometricInterpretation, tag 0x0106
366 constexpr TagDetails exifPhotometricInterpretation[] = {
367 {0, "Reversed mono"},
368 {1, "Normal mono"},
369 {2, "RGB"},
370 {3, "Palette"},
371 {5, "CMYK"},
372 {6, "YCbCr"},
373 {8, "CieLAB"},
374 };
375
376 // PlanarConfiguration, tag 0x011c
377 constexpr TagDetails exifPlanarConfiguration[] = {
378 {1, "Chunky format"},
379 {2, "Planar format"},
380 };
381
382 // Units for measuring X and Y resolution, tags 0x0128, 0xa210
383 constexpr TagDetails exifUnit[] = {
384 {2, "Inch"},
385 {3, "Centimeter"},
386 };
387
388 // YCbCrPositioning, tag 0x0213
389 constexpr TagDetails exifYCbCrPositioning[] = {
390 {1, "Centered"},
391 {2, "Co-sited"},
392 };
393
394 // ExposureProgram, tag 0x8822
395 constexpr TagDetails exifExposureProgram[] = {
396 {0, "Not defined"}, {1, "Manual"}, {2, "Normal program"},
397 {3, "Aperture priority"}, {4, "Shutter priority"}, {5, "Creative program (biased toward depth of field)"},
398 {6, "Creative program (biased toward fast shutter speed)"},
399 {7, "Portrait mode (for closeup photos with the background out of focus)"},
400 {8, "Landscape mode (for landscape photos with the background in focus)"},
401 };
402
403 // SensingMethod, TIFF/EP tag 0x9217
404 constexpr TagDetails tiffSensingMethod[] = {
405 {0, ""}, {1, "Not defined"}, {2, "One-chip color area sensor"},
406 {3, "Two-chip color area sensor"}, {4, "Three-chip color area sensor"}, {5, "Color sequential area sensor"},
407 {6, "Monochrome linear"}, {7, "Trilinear sensor"}, {8, "Color sequential linear sensor"},
408 };
409
410 // CustomRendered, tag 0xa401
411 constexpr TagDetails exifCustomRendered[] = {
412 {0, "Normal process"},
413 {1, "Custom process"},
414 };
415
416 // ExposureMode, tag 0xa402
417 constexpr TagDetails exifExposureMode[] = {
418 {0, "Auto exposure"},
419 {1, "Manual exposure"},
420 {2, "Auto bracket"},
421 };
422
423 // SceneCaptureType, tag 0xa406
424 constexpr TagDetails exifSceneCaptureType[] = {
425 {0, "Standard"},
426 {1, "Landscape"},
427 {2, "Portrait"},
428 {3, "Night scene"}
429 };
430
431 // GainControl, tag 0xa407
432 constexpr TagDetails exifGainControl[] = {
433 {0, "Normal"}, {1, "Low gain up"}, {2, "High gain up"},
434 {3, "Low gain down"}, {4, "High gain down"},
435 };
436
437 // Contrast, tag 0xa408 and Sharpness, tag 0xa40a
438 constexpr TagDetails exifNormalSoftHard[] = {
439 {0, "Normal"},
440 {1, "Soft"},
441 {2, "Hard"},
442 };
443
444 // Saturation, tag 0xa409
445 constexpr TagDetails exifSaturation[] = {
446 {0, "Normal"},
447 {1, "Low saturation"},
448 {2, "High saturation"},
449 };
450
451 // SubjectDistanceRange, tag 0xa40c
452 constexpr TagDetails exifSubjectDistanceRange[] = {
453 {0, "Unknown"},
454 {1, "Macro"},
455 {2, "Close view"},
456 {3, "Distant view"}
457 };
458
459 // GPS altitude reference, tag 0x0005
460 constexpr TagDetails exifGPSAltitudeRef[] = {
461 {0, "Sea level"},
462 {1, "Sea level reference"},
463 };
464
465 // NewSubfileType, TIFF tag 0x00fe - this is actually a bitmask
466 constexpr TagDetails exifNewSubfileType[] = {
467 {0, "Primary image"},
468 {1, "Thumbnail/Preview image"},
469 {2, "Primary image, Multi page file"},
470 {3, "Thumbnail/Preview image, Multi page file"},
471 {4, "Primary image, Transparency mask"},
472 {5, "Thumbnail/Preview image, Transparency mask"},
473 {6, "Primary image, Multi page file, Transparency mask"},
474 {7, "Thumbnail/Preview image, Multi page file, Transparency mask"},
475 {8, "Primary image, Depth map"}, // DNG 1.5
476 {9, "Thumbnail/Preview image, Depth map"}, // DNG 1.5
477 {16, "Enhanced image"}, // DNG 1.5 (clashes w/ TIFF-FX)
478 {65537, "Thumbnail/Preview image, Alternative"}, // DNG 1.2
479 {65540, "Primary image, Semantic mask"} // DNG 1.6
480 };
481
482 // SubfileType, TIFF tag 0x00ff
483 constexpr TagDetails exifSubfileType[] = {
484 {1, "Full-resolution image data"},
485 {2, "Reduced-resolution image data"},
486 {3, "A single page of a multi-page image"},
487 };
488
489 // GPS status, tag 0x0009
490 constexpr TagDetails exifGpsStatus[] = {
491 {'A', "Measurement in progress"},
492 {'V', "Measurement interrupted"},
493 };
494
495 // GPS measurement mode, tag 0x000a
496 constexpr TagDetails exifGPSMeasureMode[] = {
497 {2, "2-dimensional measurement"},
498 {3, "3-dimensional measurement"},
499 };
500
501 // GPS speed reference, tag 0x000c
502 constexpr TagDetails exifGPSSpeedRef[] = {
503 {'K', "km/h"},
504 {'M', "mph"},
505 {'N', "knots"},
506 };
507
508 // GPS direction reference, tags 0x000e, 0x0010, 0x0017
509 constexpr TagDetails exifGPSDirRef[] = {
510 {'T', "True direction"},
511 {'M', "Magnetic direction"},
512 };
513
514 // GPS destination distance reference, tag 0x0019
515 constexpr TagDetails exifGPSDestDistanceRef[] = {
516 {'K', "km"},
517 {'M', "miles"},
518 {'N', "nautical miles"},
519 };
520
521 // GPS differential correction, tag 0x001e
522 constexpr TagDetails exifGPSDifferential[] = {
523 {0, "Without correction"},
524 {1, "Correction applied"},
525 };
526
527 // CompositeImage, tag 0xa460
528 constexpr TagDetails exifCompositeImage[] = {
529 {0, "Unknown"},
530 {1, "NonComposite"},
531 {2, "GeneralComposite"},
532 {3, "CompositeCapturedWhenShooting"},
533 };
534
535 // exifSensitivityType, tag 0x8830
536 constexpr TagDetails exifSensitivityType[] = {
537 {0, "Unknown"},
538 {1, "Standard output sensitivity (SOS)"},
539 {2, "Recommended exposure index (REI)"},
540 {3, "ISO speed"},
541 {4, "Standard output sensitivity (SOS) and recommended exposure index (REI)"},
542 {5, "Standard output sensitivity (SOS) and ISO speed"},
543 {6, "Recommended exposure index (REI) and ISO speed"},
544 {7, "Standard output sensitivity (SOS) and recommended exposure index (REI) and ISO speed"},
545 };
546
547 // configuratioin for value range validation. For example GPSLatitudeRef the value must be 'N' or 'S'.
548 std::map<std::string, std::tuple<const TagDetails *, const size_t>> ExifMetadatFormatter::valueRangeValidateConfig = {
549 { "Orientation", std::make_tuple(exifOrientation, std::size(exifOrientation)) },
550 { "GPSLatitudeRef", std::make_tuple(exifGPSLatitudeRef, std::size(exifGPSLatitudeRef)) },
551 { "GPSDestLatitudeRef", std::make_tuple(exifGPSLatitudeRef, std::size(exifGPSLatitudeRef)) },
552 { "GPSLongitudeRef", std::make_tuple(exifGPSLongitudeRef, std::size(exifGPSLongitudeRef)) },
553 { "GPSDestLongitudeRef", std::make_tuple(exifGPSLongitudeRef, std::size(exifGPSLongitudeRef)) },
554 { "WhiteBalance", std::make_tuple(exifWhiteBalance, std::size(exifWhiteBalance)) },
555 { "Flash", std::make_tuple(exifFlash, std::size(exifFlash)) },
556 { "LightSource", std::make_tuple(exifLightSource, std::size(exifLightSource)) },
557 { "MeteringMode", std::make_tuple(exifMeteringMode, std::size(exifMeteringMode)) },
558 { "SceneType", std::make_tuple(exifSceneType, std::size(exifSceneType)) },
559 { "Compression", std::make_tuple(exifCompression, std::size(exifCompression)) },
560 { "PhotometricInterpretation",
561 std::make_tuple(exifPhotometricInterpretation, std::size(exifPhotometricInterpretation)) },
562 { "PlanarConfiguration", std::make_tuple(exifPlanarConfiguration, std::size(exifPlanarConfiguration)) },
563 { "ResolutionUnit", std::make_tuple(exifUnit, std::size(exifUnit)) },
564 { "YCbCrPositioning", std::make_tuple(exifYCbCrPositioning, std::size(exifYCbCrPositioning)) },
565 { "ExposureProgram", std::make_tuple(exifExposureProgram, std::size(exifExposureProgram)) },
566 { "ColorSpace", std::make_tuple(exifColorSpace, std::size(exifColorSpace)) },
567 { "FocalPlaneResolutionUnit", std::make_tuple(exifUnit, std::size(exifUnit)) },
568 { "SensingMethod", std::make_tuple(tiffSensingMethod, std::size(tiffSensingMethod)) },
569 { "CustomRendered", std::make_tuple(exifCustomRendered, std::size(exifCustomRendered)) },
570 { "ExposureMode", std::make_tuple(exifExposureMode, std::size(exifExposureMode)) },
571 { "SceneCaptureType", std::make_tuple(exifSceneCaptureType, std::size(exifSceneCaptureType)) },
572 { "GainControl", std::make_tuple(exifGainControl, std::size(exifGainControl)) },
573 { "Contrast", std::make_tuple(exifNormalSoftHard, std::size(exifNormalSoftHard)) },
574 { "Saturation", std::make_tuple(exifSaturation, std::size(exifSaturation)) },
575 { "Sharpness", std::make_tuple(exifNormalSoftHard, std::size(exifNormalSoftHard)) },
576 { "SubjectDistanceRange", std::make_tuple(exifSubjectDistanceRange, std::size(exifSubjectDistanceRange)) },
577 { "GPSAltitudeRef", std::make_tuple(exifGPSAltitudeRef, std::size(exifGPSAltitudeRef)) },
578 { "NewSubfileType", std::make_tuple(exifNewSubfileType, std::size(exifNewSubfileType)) },
579 { "SubfileType", std::make_tuple(exifSubfileType, std::size(exifSubfileType)) },
580 { "GPSStatus", std::make_tuple(exifGpsStatus, std::size(exifGpsStatus)) },
581 { "GPSMeasureMode", std::make_tuple(exifGPSMeasureMode, std::size(exifGPSMeasureMode)) },
582 { "GPSSpeedRef", std::make_tuple(exifGPSSpeedRef, std::size(exifGPSSpeedRef)) },
583 { "GPSImgDirectionRef", std::make_tuple(exifGPSDirRef, std::size(exifGPSDirRef)) },
584 { "GPSTrackRef", std::make_tuple(exifGPSDirRef, std::size(exifGPSDirRef)) },
585 { "GPSDestBearingRef", std::make_tuple(exifGPSDirRef, std::size(exifGPSDirRef)) },
586 { "GPSDestDistanceRef", std::make_tuple(exifGPSDestDistanceRef, std::size(exifGPSDestDistanceRef)) },
587 { "GPSDifferential", std::make_tuple(exifGPSDifferential, std::size(exifGPSDifferential)) },
588 { "CompositeImage", std::make_tuple(exifCompositeImage, std::size(exifCompositeImage)) },
589 { "SensitivityType", std::make_tuple(exifSensitivityType, std::size(exifSensitivityType)) },
590 };
591
592 const size_t DECIMAL_BASE = 10;
593 const std::string COMMA_REGEX("\\,"), COLON_REGEX("\\:"), DOT_REGEX("\\.");
594 const std::set<std::string> UINT16_KEYS = {
595 "ImageLength", "ImageWidth", "ISOSpeedRatings", "ISOSpeedRatings",
596 "FocalLengthIn35mmFilm", "SamplesPerPixel", "PhotographicSensitivity"
597 };
598
599 const auto SINGLE_RATIONAL_REGEX = R"(^[0-9]+/[1-9][0-9]*$)";
600 const auto SINGLE_INT_REGEX = R"(^\s*[0-9]+$)";
601 const auto SINGLE_DECIMAL_REGEX = "\\s*(\\d+)(\\.\\d+)?";
602 const auto DOUBLE_INT_WITH_BLANK_REGEX = R"(^[0-9]+\s*[0-9]+$)";
603 const auto DOUBLE_INT_WITH_COMMA_REGEX = R"(^[0-9]+,\s*[0-9]+$)";
604 const auto DOUBLE_VALUE_REGEX = "(\\d+)(\\.\\d+)?(/\\d+)?(,)?\\s*(\\d+)(\\.\\d+)?(/\\d+)?";
605 const auto TRIBLE_INT_WITH_BLANK_REGEX = R"(^[0-9]+\s[0-9]+\s[0-9]+$)";
606 const auto TRIBLE_INT_WITH_COMMA_REGEX = R"(^\s*[0-9]+,\s*[0-9]+,\s*[0-9]+$)";
607 const auto TRIBLE_RATIONAL_WITH_BLANK_REGEX = R"(^[0-9]+/[1-9][0-9]*\s[0-9]+/[1-9][0-9]*\s[0-9]+/[1-9][0-9]*$)";
608 const auto TRIBLE_DECIMAL_WITH_BLANK_REGEX = "(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?";
609 const auto TRIBLE_DECIMAL_WITH_COMMA_REGEX = "(\\d+)(\\.\\d+)?,\\s*(\\d+)(\\.\\d+)?,\\s*(\\d+)(\\.\\d+)?";
610 const auto TRIBLE_MIX_WITH_COMMA_REGEX = "^\\s*\\d+(\\.\\d+)?(,\\s*\\d+(\\.\\d+)?)*\\s*$";
611 const auto TRIBLE_INT_WITH_COLON_REGEX = R"(^[1-9][0-9]*:[1-9][0-9]*:[1-9][0-9]*$)";
612 const auto TRIBLE_INT_WITH_DOT_REGEX = R"(^[0-9]+.[0-9]+.[0-9]+.[0-9]+$)";
613 const auto FOUR_INT_WITH_BLANK_REGEX = R"(^[0-9]+\s[0-9]+\s[0-9]+\s[0-9]+$)";
614 const auto FOUR_INT_WITH_COMMA_REGEX = R"(^[0-9]+,\s*[0-9]+,\s*[0-9]+,\s*[0-9]+$)";
615 const auto FOUR_RATIONAL_WITH_BLANK_REGEX =
616 R"(^[0-9]+/[1-9][0-9]*\s[0-9]+/[1-9][0-9]*\s[0-9]+/[1-9][0-9]*\s[0-9]+/[1-9][0-9]*$)";
617 const auto FOUR_DECIMAL_WITH_BLANK_REGEX = "(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?";
618 const auto FOUR_DECIMAL_WITH_COMMA_REGEX = "(\\d+)(\\.\\d+)?(,\\s*(\\d+)(\\.\\d+)?){3}";
619 const auto SIX_DECIMAL_WITH_BLANK_REGEX =
620 "(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?\\s(\\d+)(\\.\\d+)?";
621 const auto SIX_DECIMAL_WITH_COMMA_REGEX = "\\s*(\\d+)(\\.\\d+)?(,\\s*(\\d+)(\\.\\d+)?){5}";
622 const auto TIMESTAMP_REGEX = "^\\d+:\\d+:\\d+(\\.\\d+)$";
623 const auto DATETIME_REGEX =
624 R"(^[0-9]{4}:(0[1-9]|1[012]):(0[1-9]|[12][0-9]|3[01])\s([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$)";
625 const auto DATE_REGEX = R"(^[0-9]{4}:(0[1-9]|1[012]):(0[1-9]|[12][0-9]|3[01])$)";
626 const auto VERSION_REGEX = R"(^[0-9]+\.[0-9]+$)";
627 const auto CHANNEL_REGEX = R"(^[-YCbCrRGB]+(\s[-YCbCrRGB]+)+$)";
628 const auto SENSITIVE_REGEX = R"(gps|lati|longi)";
629
630 /*
631 * validate the key is in value range array.
632 * For example GPSLatitudeRef value should be 'N' or 'S' in exifGPSLatitudeRef array.
633 */
IsValidValue(const TagDetails * array,const size_t & size,const int64_t & key)634 bool ExifMetadatFormatter::IsValidValue(const TagDetails *array, const size_t &size, const int64_t &key)
635 {
636 if (array == nullptr) {
637 return false;
638 }
639
640 for (size_t i = 0; i < size; i++) {
641 if (array[i].val_ == key) {
642 return true;
643 }
644 }
645 return false;
646 }
647
648 // validate regex only
ValidRegex(const std::string & value,const std::string & regex)649 bool ExifMetadatFormatter::ValidRegex(const std::string &value, const std::string ®ex)
650 {
651 IMAGE_LOGD("Validating against regex: %{public}s", regex.c_str());
652 std::regex ratPattern(regex);
653 if (!std::regex_match(value, ratPattern)) {
654 IMAGE_LOGD("Validation failed.Regex: %{public}s", regex.c_str());
655 return false;
656 }
657 return true;
658 }
659
660 // replace as space according to regex
ReplaceAsSpace(std::string & value,const std::string & regex)661 void ExifMetadatFormatter::ReplaceAsSpace(std::string &value, const std::string ®ex)
662 {
663 std::regex pattern(regex);
664 value = std::regex_replace(value, pattern, " ");
665 }
666
ReplaceAsContent(std::string & value,const std::string & regex,const std::string & content)667 void ExifMetadatFormatter::ReplaceAsContent(std::string &value, const std::string ®ex, const std::string &content)
668 {
669 std::regex pattern(regex);
670 value = std::regex_replace(value, pattern, content);
671 }
672
673 // validate the regex & replace comma as space
ValidRegexWithComma(std::string & value,const std::string & regex)674 bool ExifMetadatFormatter::ValidRegexWithComma(std::string &value, const std::string ®ex)
675 {
676 IMAGE_LOGD("Validating comma against regex: %{public}s", regex.c_str());
677 if (!ValidRegex(value, regex)) {
678 return false;
679 }
680 ReplaceAsSpace(value, COMMA_REGEX);
681 return true;
682 }
683
684 // convert integer to rational format. For example 23 15 83 --> 23/1 15/1 83/1
RationalFormat(std::string & value)685 void ExifMetadatFormatter::RationalFormat(std::string &value)
686 {
687 std::regex pattern("\\d+"); // regex for integer
688 std::string result;
689 int icount = 0;
690 while (std::regex_search(value, pattern)) {
691 std::smatch match;
692 if (!std::regex_search(value, match, pattern)) {
693 break; // break since there is no matched value
694 }
695 if (icount != 0) {
696 result += " ";
697 }
698 result += match.str() + "/1"; // appending '/1' to integer
699 value = match.suffix().str(); // skip handled value part
700 icount++;
701 }
702 value = result;
703 }
704
ConvertToDouble(const std::string & str,double & value)705 static bool ConvertToDouble(const std::string& str, double& value)
706 {
707 errno = 0;
708 char* endPtr = nullptr;
709 value = strtod(str.c_str(), &endPtr);
710 if (errno == ERANGE && *endPtr != '\0') {
711 return false;
712 }
713 return true;
714 }
715
716 // convert decimal to rational string. 2.5 -> 5/2
GetFractionFromStr(const std::string & decimal,bool & isOutRange)717 std::string ExifMetadatFormatter::GetFractionFromStr(const std::string &decimal, bool &isOutRange)
718 {
719 // check int part out of range
720 std::string inPareStr = decimal.substr(0, decimal.find("."));
721 int intPart = 0;
722 auto [p, ec] = std::from_chars(inPareStr.data(), inPareStr.data() + inPareStr.size(), intPart);
723 if (ec != std::errc()) {
724 IMAGE_LOGE("GetFractionFromStr failed, value is out of range");
725 isOutRange = true;
726 return "";
727 }
728
729 double decPart = 0.0;
730 std::string decPartStr = decimal.substr(decimal.find("."));
731 if (!ConvertToDouble(decPartStr, decPart)) {
732 IMAGE_LOGE("%{public}s failed, value out of range", __func__);
733 isOutRange = true;
734 return "";
735 }
736
737 int numerator = decPart * pow(DECIMAL_BASE, decimal.length() - decimal.find(".") - 1);
738 int denominator = pow(DECIMAL_BASE, decimal.length() - decimal.find(".") - 1);
739
740 int gcdVal = ExifMetadatFormatter::Gcd(numerator, denominator);
741 if (gcdVal == 0) {
742 return std::to_string(numerator + intPart * denominator) + "/" + std::to_string(denominator);
743 }
744 numerator /= gcdVal;
745 denominator /= gcdVal;
746
747 numerator += intPart * denominator;
748
749 return std::to_string(numerator) + "/" + std::to_string(denominator);
750 }
751
752 // convert decimal to rational format. For example 2.5 -> 5/2
ValidDecimalRationalFormat(std::string & value)753 bool ExifMetadatFormatter::ValidDecimalRationalFormat(std::string &value)
754 {
755 std::string result;
756 int icount = 0;
757 std::regex parPattern("(\\d+)(\\.\\d+)?");
758
759 // with partial regex For 2.5 26 1.2 to iterator each segment 2.5->5/2
760 for (std::sregex_iterator it = std::sregex_iterator(value.begin(), value.end(), parPattern);
761 it != std::sregex_iterator(); ++it) {
762 std::smatch match = *it;
763
764 // add a space at begin of each segment except the first segment
765 if (icount != 0) {
766 result += " ";
767 }
768
769 // 1.if segment is integer type 123->123/1
770 if (ValidRegex(match[0], "\\d+")) {
771 // append '/1' to integer 23 -> 23/1
772 result += match.str() + "/1";
773 }
774 if (ValidRegex(match[0], "\\d+\\.\\d+")) {
775 // segment is decimal call decimalToFraction 2.5 -> 5/2
776 bool isOutRange = false;
777 auto tmpRes = GetFractionFromStr(match[0], isOutRange);
778 if (isOutRange) {
779 return false;
780 }
781 result += tmpRes;
782 }
783 icount++;
784 }
785 value = result;
786 return true;
787 }
788
ValidConvertRationalFormat(std::string & value)789 bool ExifMetadatFormatter::ValidConvertRationalFormat(std::string &value)
790 {
791 std::string result;
792 int icount = 0;
793 std::regex parPattern("\\d+(\\.\\d+)?(/\\d+)?");
794
795 // with partial regex For 2.5 26 1.2 to iterator each segment 2.5->5/2
796 for (std::sregex_iterator it = std::sregex_iterator(value.begin(), value.end(), parPattern);
797 it != std::sregex_iterator(); ++it) {
798 std::smatch match = *it;
799
800 // add a space at begin of each segment except the first segment
801 if (icount != 0) {
802 result += " ";
803 }
804
805 // 1.if segment is integer type 123->123/1
806 if (ValidRegex(match[0], "\\d+")) {
807 // append '/1' to integer 23 -> 23/1
808 result += match.str() + "/1";
809 }
810 if (ValidRegex(match[0], "\\d+/\\d+")) {
811 result += match.str();
812 }
813 if (ValidRegex(match[0], "\\d+\\.\\d+")) {
814 // segment is decimal call decimalToFraction 2.5 -> 5/2
815 bool isOutRange = false;
816 auto tmpRes = GetFractionFromStr(match[0], isOutRange);
817 if (isOutRange) {
818 return false;
819 }
820 result += tmpRes;
821 }
822 icount++;
823 }
824 value = result;
825 return true;
826 }
827
828 // validate regex & convert integer to rational format. For example 23 15 83 --> 23/1 15/1 83
ValidRegexWithRationalFormat(std::string & value,const std::string & regex)829 bool ExifMetadatFormatter::ValidRegexWithRationalFormat(std::string &value, const std::string ®ex)
830 {
831 // 1.validate regex
832 if (!ValidRegex(value, regex)) {
833 return false;
834 }
835
836 // 2.convert integer to rational format. 9 9 9 -> 9/1 9/1 9/1
837 RationalFormat(value);
838 return true;
839 }
840
841 // validate regex & convert value to rational format. For example 9,9,9 -> 9 9 9 -> 9/1 9/1 9/1
ValidRegexWithCommaRationalFormat(std::string & value,const std::string & regex)842 bool ExifMetadatFormatter::ValidRegexWithCommaRationalFormat(std::string &value, const std::string ®ex)
843 {
844 // 1.validate regex
845 if (!ValidRegex(value, regex)) {
846 return false;
847 }
848
849 // 2.replace comma as a space
850 ReplaceAsSpace(value, COMMA_REGEX);
851
852 // 3.convert integer to rational format. 9 9 9 -> 9/1 9/1 9/1
853 RationalFormat(value);
854 return true;
855 }
856
857 // validate regex & convert value to rational format. For example 9:9:9 -> 9 9 9 -> 9/1 9/1 9/1
ValidRegexWithColonRationalFormat(std::string & value,const std::string & regex)858 bool ExifMetadatFormatter::ValidRegexWithColonRationalFormat(std::string &value, const std::string ®ex)
859 {
860 // 1.validate regex
861 if (!ValidRegex(value, regex)) {
862 return false;
863 }
864
865 // 2.replace colon as a space
866 ReplaceAsSpace(value, COLON_REGEX);
867
868 // 3.convert integer to rational format. 9 9 9 -> 9/1 9/1 9/1
869 RationalFormat(value);
870 return true;
871 }
872
873 // validate regex & convert value to integer format.
ValidRegexWithDot(std::string & value,const std::string & regex)874 bool ExifMetadatFormatter::ValidRegexWithDot(std::string &value, const std::string ®ex)
875 {
876 if (!ValidRegex(value, regex)) {
877 return false;
878 }
879 ReplaceAsContent(value, DOT_REGEX, "");
880 return true;
881 }
882
883 // regex validation & convert decimal to rational. For example GPSLatitude 2.5,23,3.4 -> 2.5 23 3.4 -> 5/2 23/1 17/5
ValidRegxWithCommaDecimalRationalFormat(std::string & value,const std::string & regex)884 bool ExifMetadatFormatter::ValidRegxWithCommaDecimalRationalFormat(std::string &value, const std::string ®ex)
885 {
886 if (!ValidRegex(value, regex)) {
887 return false;
888 }
889
890 // replace comma with a space 1.5,2.5.3 -> 1.5 2.5 3
891 ReplaceAsSpace(value, COMMA_REGEX);
892
893 // convert decimal to rationl 2.5 -> 5/2
894 return ValidDecimalRationalFormat(value);
895 }
896
ValidRegxAndConvertRationalFormat(std::string & value,const std::string & regex)897 bool ExifMetadatFormatter::ValidRegxAndConvertRationalFormat(std::string &value, const std::string ®ex)
898 {
899 if (!ValidRegex(value, regex)) {
900 return false;
901 }
902
903 // replace comma with a space 1.5,2.5.3 -> 1.5 2.5 3
904 ReplaceAsSpace(value, COMMA_REGEX);
905
906 // replace colon
907 ReplaceAsSpace(value, COLON_REGEX);
908
909 return ValidConvertRationalFormat(value);
910 }
911
912
913 // regex validation & convert decimal to rational. For example GPSLatitude 2.5 23 3.4 -> 5/2 23/1 17/5
ValidRegexWithDecimalRationalFormat(std::string & value,const std::string & regex)914 bool ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat(std::string &value, const std::string ®ex)
915 {
916 if (!ValidRegex(value, regex)) {
917 return false;
918 }
919
920 // convert decimal to rationl 2.5 -> 5/2
921 return ValidDecimalRationalFormat(value);
922 }
923
ValidRegexWithVersionFormat(std::string & value,const std::string & regex)924 bool ExifMetadatFormatter::ValidRegexWithVersionFormat(std::string &value, const std::string ®ex)
925 {
926 if (!ValidRegex(value, regex)) {
927 return false;
928 }
929
930 std::string result;
931 std::regex parPattern("[0-9]{1,2}");
932
933 int icount = 0;
934 for (std::sregex_iterator it = std::sregex_iterator(value.begin(), value.end(), parPattern);
935 it != std::sregex_iterator(); ++it) {
936 std::smatch match = *it;
937 std::string tmp = match[0].str();
938 if (icount == 0 && tmp.length() == 1) {
939 result += "0" + tmp;
940 } else if (icount == 1 && tmp.length() == 1) {
941 result += tmp + "0";
942 } else {
943 result += tmp;
944 }
945 icount++;
946 }
947 value = result;
948 return true;
949 }
950
ValidRegexWithChannelFormat(std::string & value,const std::string & regex)951 bool ExifMetadatFormatter::ValidRegexWithChannelFormat(std::string &value, const std::string ®ex)
952 {
953 if (!ValidRegex(value, regex)) {
954 return false;
955 }
956
957 std::string result;
958 std::regex parPattern("[-YCbCrRGB]+");
959
960 for (std::sregex_iterator it = std::sregex_iterator(value.begin(), value.end(), parPattern);
961 it != std::sregex_iterator(); ++it) {
962 std::smatch match = *it;
963 std::string tmp = match[0].str();
964 if (tmp == "-") {
965 result += "0";
966 } else if (tmp == "Y") {
967 result += "1";
968 } else if (tmp == "Cb") {
969 result += "2";
970 } else if (tmp == "Cr") {
971 result += "3";
972 } else if (tmp == "R") {
973 result += "4";
974 } else if (tmp == "G") {
975 result += "5";
976 } else if (tmp == "B") {
977 result += "6";
978 }
979 }
980 value = result;
981 return true;
982 }
983
ValidRegexWithGpsOneRationalFormat(std::string & value,const std::string & regex)984 bool ExifMetadatFormatter::ValidRegexWithGpsOneRationalFormat(std::string &value, const std::string ®ex)
985 {
986 IMAGE_LOGD("validate gps with one rational.");
987 if (!ValidRegex(value, regex)) {
988 return false;
989 }
990 std::vector<std::string> vec;
991 SplitStr(value, ",", vec);
992 if (vec.size() != GPS_DEGREE_SIZE) {
993 IMAGE_LOGD("Gps degree data size is invalid.");
994 return false;
995 }
996 value = vec[0] + "/" + vec[1] + " 0/1 0/1";
997 return true;
998 }
999
1000 ValueFormatDelegate ExifMetadatFormatter::singleInt =
1001 std::make_pair(ExifMetadatFormatter::ValidRegex, SINGLE_INT_REGEX);
1002
1003 // regex validation for two integer like DefaultCropSize 9 9 the format is [0-9]+ [0-9]+
1004 ValueFormatDelegate ExifMetadatFormatter::doubleIntWithBlank =
1005 std::make_pair(ExifMetadatFormatter::ValidRegex, DOUBLE_INT_WITH_BLANK_REGEX);
1006
1007 // regex validation for two integer with comma like BitPerSample 9,9 the format is [0-9]+,[0-9]+,[0-9]+
1008 ValueFormatDelegate ExifMetadatFormatter::doubleIntWithComma =
1009 std::make_pair(ExifMetadatFormatter::ValidRegexWithComma, DOUBLE_INT_WITH_COMMA_REGEX);
1010
1011 // regex validation for three integer like BitPerSample 9 9 9 the format is [0-9]+ [0-9]+ [0-9]+
1012 ValueFormatDelegate ExifMetadatFormatter::tribleIntWithBlank =
1013 std::make_pair(ExifMetadatFormatter::ValidRegex, TRIBLE_INT_WITH_BLANK_REGEX);
1014
1015 // regex validation for three integer with comma like BitPerSample 9,9,0 the format is [0-9]+,[0-9]+,[0-9]+,[0-9]+
1016 ValueFormatDelegate ExifMetadatFormatter::tribleIntWithComma =
1017 std::make_pair(ExifMetadatFormatter::ValidRegexWithComma, TRIBLE_INT_WITH_COMMA_REGEX);
1018
1019 // regex validation for four integer like DNGVersion 9 9 9 9 the format is [0-9]+ [0-9]+ [0-9]+ [0-9]+
1020 ValueFormatDelegate ExifMetadatFormatter::fourIntWithBlank =
1021 std::make_pair(ExifMetadatFormatter::ValidRegex, FOUR_INT_WITH_BLANK_REGEX);
1022
1023 // regex validation for four integer with comma like DNGVersion tag encodes the DNG four-tier version number
1024 ValueFormatDelegate ExifMetadatFormatter::fourIntWithComma =
1025 std::make_pair(ExifMetadatFormatter::ValidRegexWithComma, FOUR_INT_WITH_COMMA_REGEX);
1026
1027 // regex validation for one rational like ApertureValue 4/1 the format is [0-9]+/[1-9][0-9]
1028 ValueFormatDelegate ExifMetadatFormatter::singleRational =
1029 std::make_pair(ExifMetadatFormatter::ValidRegex, SINGLE_RATIONAL_REGEX);
1030
1031 // regex validation for integer and convert it to rational like ApertureValue 4 --> 4/1
1032 ValueFormatDelegate ExifMetadatFormatter::singleIntToRational =
1033 std::make_pair(ExifMetadatFormatter::ValidRegexWithRationalFormat, SINGLE_INT_REGEX);
1034
1035 ValueFormatDelegate ExifMetadatFormatter::singleDecimalToRational =
1036 std::make_pair(ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat, SINGLE_DECIMAL_REGEX);
1037
1038 ValueFormatDelegate ExifMetadatFormatter::doubleIntToOneRationalWithComma =
1039 std::make_pair(ExifMetadatFormatter::ValidRegexWithGpsOneRationalFormat, DOUBLE_INT_WITH_COMMA_REGEX);
1040
1041 ValueFormatDelegate ExifMetadatFormatter::doubleValueToRational =
1042 std::make_pair(ExifMetadatFormatter::ValidRegxAndConvertRationalFormat, DOUBLE_VALUE_REGEX);
1043
1044 // regex validation for three rational like GPSLatitude 39/1 54/1 20/1
1045 ValueFormatDelegate ExifMetadatFormatter::tribleRationalWithBlank =
1046 std::make_pair(ExifMetadatFormatter::ValidRegex, TRIBLE_RATIONAL_WITH_BLANK_REGEX);
1047
1048 // regex validation for three integer and convert to three rational like GPSLatitude 39 54 20 --> 39/1 54/1 20/1
1049 ValueFormatDelegate ExifMetadatFormatter::tribleIntToRationalWithBlank =
1050 std::make_pair(ExifMetadatFormatter::ValidRegexWithRationalFormat, TRIBLE_INT_WITH_BLANK_REGEX);
1051
1052 // regex validation for three integer with comma like GPSLatitude 39,54,20 --> 39/1 54/1 20/1
1053 ValueFormatDelegate ExifMetadatFormatter::tribleIntToRationalWithComma =
1054 std::make_pair(ExifMetadatFormatter::ValidRegexWithCommaRationalFormat, TRIBLE_INT_WITH_COMMA_REGEX);
1055
1056 // regex validation for three decimal like YCbCrCoefficients 39.0 54 20.0 --> 39/1 54/1 20/1
1057 ValueFormatDelegate ExifMetadatFormatter::tribleDecimalToRationalWithBlank =
1058 std::make_pair(ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat, TRIBLE_DECIMAL_WITH_BLANK_REGEX);
1059
1060 // regex validation for three decimal like YCbCrCoefficients 39.0,54,20.0 --> 39.0 54 20.0 --> 39/1 54/1 20/1
1061 ValueFormatDelegate ExifMetadatFormatter::tribleDecimalToRatiionalWithComma =
1062 std::make_pair(ExifMetadatFormatter::ValidRegxWithCommaDecimalRationalFormat, TRIBLE_DECIMAL_WITH_COMMA_REGEX);
1063
1064 // regex validation for three decimal like GPS 10, 20, 20.123 --> 10 20 20.123 --> 10/1 20/1 20.123/1
1065 ValueFormatDelegate ExifMetadatFormatter::tribleMixToRationalWithComma =
1066 std::make_pair(ExifMetadatFormatter::ValidRegxWithCommaDecimalRationalFormat, TRIBLE_MIX_WITH_COMMA_REGEX);
1067
1068 // regex validation for four rational like LensSpecification 1/1 3/2 1/1 2/1
1069 ValueFormatDelegate ExifMetadatFormatter::fourRationalWithBlank =
1070 std::make_pair(ExifMetadatFormatter::ValidRegex, FOUR_RATIONAL_WITH_BLANK_REGEX);
1071
1072 // regex validation for four integer and convert to four rational like LensSpecification 1 3 1 2 --> 1/1 3/2 1/1 2/1
1073 ValueFormatDelegate ExifMetadatFormatter::fourIntToRationalWithBlank =
1074 std::make_pair(ExifMetadatFormatter::ValidRegexWithRationalFormat, FOUR_INT_WITH_BLANK_REGEX);
1075
1076 // regex validation for four integer like LensSpecification 1,3,1,2 --> 1/1 3/2 1/1 2/1
1077 ValueFormatDelegate ExifMetadatFormatter::fourIntToRationalWithComma =
1078 std::make_pair(ExifMetadatFormatter::ValidRegexWithCommaRationalFormat, FOUR_INT_WITH_COMMA_REGEX);
1079
1080 // regex validation for four decimal like LensSpecification 1.0 3.0 1.0 2.0 --> 1/1 3/1 2/1
1081 ValueFormatDelegate ExifMetadatFormatter::fourDecimalToRationalWithBlank =
1082 std::make_pair(ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat, FOUR_DECIMAL_WITH_BLANK_REGEX);
1083
1084 // regex validation for four decimal like LensSpecification 1.0,3.0,1.0,2.0 --> 1/1 3/1 2/1
1085 ValueFormatDelegate ExifMetadatFormatter::fourDecimalToRationalWithComma =
1086 std::make_pair(ExifMetadatFormatter::ValidRegxWithCommaDecimalRationalFormat, FOUR_DECIMAL_WITH_COMMA_REGEX);
1087
1088 // regex validation for datetime format like DateTimeOriginal 2022:06:02 15:51:34
1089 ValueFormatDelegate ExifMetadatFormatter::dateTimeValidation =
1090 std::make_pair(ExifMetadatFormatter::ValidRegex, DATETIME_REGEX);
1091
1092 // regex validation for datetime format like DateTimeOriginal 2022:06:02
1093 ValueFormatDelegate ExifMetadatFormatter::dateValidation = std::make_pair(ExifMetadatFormatter::ValidRegex, DATE_REGEX);
1094
1095 // regex validation for three integer like GPSLatitude 39,54,21 --> 39/1 54/1 21/1
1096 ValueFormatDelegate ExifMetadatFormatter::tribleIntToRationalWithColon =
1097 std::make_pair(ExifMetadatFormatter::ValidRegexWithColonRationalFormat, TRIBLE_INT_WITH_COLON_REGEX);
1098
1099 ValueFormatDelegate ExifMetadatFormatter::timeStamp =
1100 std::make_pair(ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat, TIMESTAMP_REGEX);
1101
1102 // regex validation for fou integer with pointer like GPSVersionID
1103 ValueFormatDelegate ExifMetadatFormatter::fourIntWithDot =
1104 std::make_pair(ExifMetadatFormatter::ValidRegexWithDot, TRIBLE_INT_WITH_DOT_REGEX);
1105
1106 ValueFormatDelegate ExifMetadatFormatter::sixDecimalToRationalWithBlank =
1107 std::make_pair(ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat, SIX_DECIMAL_WITH_BLANK_REGEX);
1108
1109 ValueFormatDelegate ExifMetadatFormatter::sixDecimalToRationalWithComma =
1110 std::make_pair(ExifMetadatFormatter::ValidRegexWithDecimalRationalFormat, SIX_DECIMAL_WITH_COMMA_REGEX);
1111
1112 ValueFormatDelegate ExifMetadatFormatter::version =
1113 std::make_pair(ExifMetadatFormatter::ValidRegexWithVersionFormat, VERSION_REGEX);
1114
1115 ValueFormatDelegate ExifMetadatFormatter::channel =
1116 std::make_pair(ExifMetadatFormatter::ValidRegexWithChannelFormat, CHANNEL_REGEX);
1117
1118 // configuration for value format validation. For example BitPerSample the value format should be 9 9 9 or 9,9,9
1119 std::multimap<std::string, ValueFormatDelegate> ExifMetadatFormatter::valueFormatConvertConfig = {
1120 {"BitsPerSample", tribleIntWithBlank},
1121 {"BitsPerSample", tribleIntWithComma},
1122 {"CompressedBitsPerPixel", singleRational},
1123 {"CompressedBitsPerPixel", singleIntToRational},
1124 {"CompressedBitsPerPixel", singleDecimalToRational},
1125 {"GPSLatitude", doubleIntToOneRationalWithComma},
1126 {"GPSLatitude", tribleRationalWithBlank},
1127 {"GPSLatitude", tribleIntToRationalWithBlank},
1128 {"GPSLatitude", tribleIntToRationalWithComma},
1129 {"GPSLatitude", tribleMixToRationalWithComma},
1130 {"GPSLongitude", doubleIntToOneRationalWithComma},
1131 {"GPSLongitude", tribleRationalWithBlank},
1132 {"GPSLongitude", tribleIntToRationalWithBlank},
1133 {"GPSLongitude", tribleIntToRationalWithComma},
1134 {"GPSLongitude", tribleMixToRationalWithComma},
1135 {"ApertureValue", singleRational},
1136 {"ApertureValue", singleIntToRational},
1137 {"ApertureValue", singleDecimalToRational},
1138 {"DateTimeOriginal", dateTimeValidation},
1139 {"DateTimeOriginal", dateValidation},
1140 {"DateTime", dateTimeValidation},
1141 {"DateTime", dateValidation},
1142 {"ExposureBiasValue", singleRational},
1143 {"ExposureBiasValue", singleIntToRational},
1144 {"ExposureBiasValue", singleDecimalToRational},
1145 {"ExposureTime", singleRational},
1146 {"ExposureTime", singleIntToRational},
1147 {"ExposureTime", singleDecimalToRational},
1148 {"FNumber", singleRational},
1149 {"FNumber", singleIntToRational},
1150 {"FNumber", singleDecimalToRational},
1151 {"FocalLength", singleRational},
1152 {"FocalLength", singleIntToRational},
1153 {"FocalLength", singleDecimalToRational},
1154 {"GPSTimeStamp", tribleRationalWithBlank},
1155 {"GPSTimeStamp", tribleIntToRationalWithBlank},
1156 {"GPSTimeStamp", tribleIntToRationalWithColon},
1157 {"GPSTimeStamp", timeStamp},
1158 {"GPSDateStamp", dateValidation},
1159 {"XResolution", singleRational},
1160 {"XResolution", singleIntToRational},
1161 {"XResolution", singleDecimalToRational},
1162 {"YResolution", singleRational},
1163 {"YResolution", singleIntToRational},
1164 {"YResolution", singleDecimalToRational},
1165 {"WhitePoint", singleRational},
1166 {"WhitePoint", singleIntToRational},
1167 {"WhitePoint", singleDecimalToRational},
1168 {"WhitePoint", doubleValueToRational},
1169 {"PrimaryChromaticities", singleRational},
1170 {"PrimaryChromaticities", singleIntToRational},
1171 {"PrimaryChromaticities", singleDecimalToRational},
1172 {"YCbCrCoefficients", tribleRationalWithBlank},
1173 {"YCbCrCoefficients", tribleIntToRationalWithBlank},
1174 {"YCbCrCoefficients", tribleIntToRationalWithComma},
1175 {"YCbCrCoefficients", tribleDecimalToRationalWithBlank},
1176 {"YCbCrCoefficients", tribleDecimalToRatiionalWithComma},
1177 {"ReferenceBlackWhite", singleRational},
1178 {"ReferenceBlackWhite", singleIntToRational},
1179 {"ReferenceBlackWhite", singleDecimalToRational},
1180 {"ReferenceBlackWhite", sixDecimalToRationalWithComma},
1181 {"ShutterSpeedValue", singleRational},
1182 {"ShutterSpeedValue", singleIntToRational},
1183 {"ShutterSpeedValue", singleDecimalToRational},
1184 {"BrightnessValue", singleRational},
1185 {"BrightnessValue", singleIntToRational},
1186 {"BrightnessValue", singleDecimalToRational},
1187 {"MaxApertureValue", singleRational},
1188 {"MaxApertureValue", singleIntToRational},
1189 {"MaxApertureValue", singleDecimalToRational},
1190 {"SubjectDistance", singleRational},
1191 {"SubjectDistance", singleIntToRational},
1192 {"SubjectDistance", singleDecimalToRational},
1193 {"FlashEnergy", singleRational},
1194 {"FlashEnergy", singleIntToRational},
1195 {"FlashEnergy", singleDecimalToRational},
1196 {"FocalPlaneXResolution", singleRational},
1197 {"FocalPlaneXResolution", singleIntToRational},
1198 {"FocalPlaneXResolution", singleDecimalToRational},
1199 {"FocalPlaneYResolution", singleRational},
1200 {"FocalPlaneYResolution", singleIntToRational},
1201 {"FocalPlaneYResolution", singleDecimalToRational},
1202 {"ExposureIndex", singleRational},
1203 {"ExposureIndex", singleIntToRational},
1204 {"ExposureIndex", singleDecimalToRational},
1205 {"DigitalZoomRatio", singleRational},
1206 {"DigitalZoomRatio", singleIntToRational},
1207 {"DigitalZoomRatio", singleDecimalToRational},
1208 {"GPSAltitude", singleRational},
1209 {"GPSAltitude", singleIntToRational},
1210 {"GPSAltitude", singleDecimalToRational},
1211 {"GPSDOP", singleRational},
1212 {"GPSDOP", singleIntToRational},
1213 {"GPSDOP", singleDecimalToRational},
1214 {"GPSSpeed", singleRational},
1215 {"GPSSpeed", singleIntToRational},
1216 {"GPSSpeed", singleDecimalToRational},
1217 {"GPSTrack", singleRational},
1218 {"GPSTrack", singleIntToRational},
1219 {"GPSTrack", singleDecimalToRational},
1220 {"GPSImgDirection", singleRational},
1221 {"GPSImgDirection", singleIntToRational},
1222 {"GPSImgDirection", singleDecimalToRational},
1223 {"GPSDestLatitude", tribleRationalWithBlank},
1224 {"GPSDestLatitude", tribleIntToRationalWithBlank},
1225 {"GPSDestLatitude", tribleIntToRationalWithComma},
1226 {"GPSDestLongitude", tribleRationalWithBlank},
1227 {"GPSDestLongitude", tribleIntToRationalWithBlank},
1228 {"GPSDestLongitude", tribleIntToRationalWithComma},
1229 {"GPSDestBearing", singleRational},
1230 {"GPSDestBearing", singleIntToRational},
1231 {"GPSDestBearing", singleDecimalToRational},
1232 {"GPSDestDistance", singleRational},
1233 {"GPSDestDistance", singleIntToRational},
1234 {"GPSDestDistance", singleDecimalToRational},
1235 {"GPSVersionID", fourIntWithDot},
1236 {"CompressedBitsPerPixel", singleRational},
1237 {"CompressedBitsPerPixel", singleIntToRational},
1238 {"CompressedBitsPerPixel", singleDecimalToRational},
1239 {"DNGVersion", fourIntWithBlank},
1240 {"DNGVersion", fourIntWithComma},
1241 {"DefaultCropSize", doubleIntWithBlank},
1242 {"DefaultCropSize", doubleIntWithComma},
1243 {"Gamma", singleRational},
1244 {"Gamma", singleIntToRational},
1245 {"Gamma", singleDecimalToRational},
1246 {"GPSHPositioningError", singleRational},
1247 {"GPSHPositioningError", singleIntToRational},
1248 {"GPSHPositioningError", singleDecimalToRational},
1249 {"LensSpecification", fourRationalWithBlank},
1250 {"LensSpecification", fourIntToRationalWithBlank},
1251 {"LensSpecification", fourIntToRationalWithComma},
1252 {"LensSpecification", fourDecimalToRationalWithBlank},
1253 {"LensSpecification", fourDecimalToRationalWithComma},
1254 {"ReferenceBlackWhite", sixDecimalToRationalWithBlank},
1255 {"SubjectLocation", doubleIntWithBlank},
1256 {"SubjectLocation", doubleIntWithComma},
1257 {"ImageLength", singleInt},
1258 {"ImageWidth", singleInt},
1259 {"ISOSpeedRatings", singleInt},
1260 {"StandardOutputSensitivity", singleInt},
1261 {"RecommendedExposureIndex", singleInt},
1262 {"ISOSpeed", singleInt},
1263 {"PixelXDimension", singleInt},
1264 {"PixelYDimension", singleInt},
1265 {"FocalLengthIn35mmFilm", singleInt},
1266 {"StripOffsets", singleInt},
1267 {"SamplesPerPixel", singleInt},
1268 {"RowsPerStrip", singleInt},
1269 {"StripByteCounts", singleInt},
1270 {"ExifVersion", singleInt},
1271 {"ExifVersion", version},
1272 {"ISOSpeedLatitudeyyy", singleInt},
1273 {"ISOSpeedLatitudezzz", singleInt},
1274 {"ComponentsConfiguration", singleInt},
1275 {"ComponentsConfiguration", channel},
1276 {"PhotographicSensitivity", singleInt},
1277 {"FlashpixVersion", singleInt},
1278 {"FlashpixVersion", version},
1279 {"PhotoMode", singleInt},
1280 {"JPEGProc", singleInt},
1281 {"HwMnoteCaptureMode", singleInt},
1282 {"HwMnoteIsXmageSupported", singleInt},
1283 {"HwMnoteXmageMode", singleInt},
1284 {"HwMnoteXmageLeft", singleInt},
1285 {"HwMnoteXmageTop", singleInt},
1286 {"HwMnoteXmageRight", singleInt},
1287 {"HwMnoteXmageBottom", singleInt},
1288 {"HwMnoteCloudEnhancementMode", singleInt},
1289 {"HwMnoteAiEdit", singleInt},
1290 {"DateTimeDigitized", dateTimeValidation},
1291 {"DateTimeDigitized", dateValidation},
1292 {"OffsetTime", dateTimeValidation},
1293 {"OffsetTime", dateValidation},
1294 {"SubjectArea", doubleIntWithBlank},
1295 {"SubjectArea", doubleIntWithComma},
1296 {"SourceImageNumberOfCompositeImage", doubleIntWithBlank},
1297 {"SourceImageNumberOfCompositeImage", doubleIntWithComma},
1298 {"YCbCrSubSampling", doubleIntWithBlank},
1299 {"YCbCrSubSampling", doubleIntWithComma},
1300 {"MovingPhotoVersion", singleInt},
1301 {"MicroVideoPresentationTimestampUS", singleInt},
1302 };
1303
1304 // validate the value range. For example GPSLatitudeRef the value must be 'N' or 'S'.
ValidateValueRange(const std::string & keyName,const std::string & value)1305 int32_t ExifMetadatFormatter::ValidateValueRange(const std::string &keyName, const std::string &value)
1306 {
1307 // 1. to find if any value range validation configuratiion according to exif tag in std::map container
1308 auto iter = valueRangeValidateConfig.find(keyName);
1309 if (iter == valueRangeValidateConfig.end()) {
1310 // if no range validation for key default is success.
1311 return Media::SUCCESS;
1312 }
1313
1314 // get value range array & size
1315 auto &[arrRef, arrSize] = iter->second;
1316 if (arrRef == nullptr) {
1317 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
1318 }
1319
1320 int32_t ivalue = -1;
1321
1322 // validate value if integer or char 2.char ascii
1323 std::regex regNum(R"(^[0-9]+$)"); // regex for integer value. For example WhiteBalance support 0 or 1
1324 std::regex regChar(R"(^[a-zA-Z]$)"); // regex for char value. For example GPSLatitudeRef support N or S
1325 if (std::regex_match(value, regNum)) {
1326 // convert string to integer such as "15" -> 15 and check ll out of range
1327 auto [p, ec] = std::from_chars(value.data(), value.data() + value.size(), ivalue);
1328 if (ec != std::errc()) {
1329 return Media::ERR_MEDIA_OUT_OF_RANGE;
1330 }
1331 }
1332 if (std::regex_match(value, regChar)) {
1333 // convert char to integer such as "N" -> 78
1334 ivalue = static_cast<int32_t>(value[0]);
1335 }
1336
1337 // if ivalue is not converted then return FAIL
1338 if (ivalue == -1) {
1339 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
1340 }
1341
1342 // validate the ivalue is in value range array.
1343 auto isValid = IsValidValue(arrRef, arrSize, ivalue);
1344 if (!isValid) {
1345 return Media::ERR_MEDIA_OUT_OF_RANGE;
1346 } else {
1347 return Media::SUCCESS;
1348 }
1349 return Media::SUCCESS;
1350 }
1351
ConvertRangeValue(const std::string & keyName,std::string & value)1352 void ExifMetadatFormatter::ConvertRangeValue(const std::string &keyName, std::string &value)
1353 {
1354 if (keyName == "FileSource" && value == "DSC") {
1355 value = "3";
1356 return;
1357 }
1358 auto iter = valueRangeValidateConfig.find(keyName);
1359 if (iter == valueRangeValidateConfig.end()) {
1360 return;
1361 }
1362
1363 // get value range array & size
1364 auto &[arrRef, arrSize] = iter->second;
1365 if (arrRef == nullptr) {
1366 return;
1367 }
1368 // iterator arrRef to get value
1369 for (size_t i = 0; i < arrSize; i++) {
1370 if (arrRef[i].label_ == value) {
1371 value = std::to_string(arrRef[i].val_);
1372 break;
1373 }
1374 }
1375 }
1376
1377 const std::set<std::string> FORBIDDEN_VALUE = {
1378 "^Internal error \\(unknown value \\d+\\)$",
1379 "^\\d+ bytes undefined data$",
1380 "Unknown FlashPix Version",
1381 "Unknown Exif Version",
1382 "Unknown value \\d+",
1383 };
1384
IsForbiddenValue(const std::string & value)1385 bool ExifMetadatFormatter::IsForbiddenValue(const std::string &value)
1386 {
1387 for (const auto ®ex : FORBIDDEN_VALUE) {
1388 std::regex ratPattern(regex);
1389 if (std::regex_match(value, ratPattern)) {
1390 return true;
1391 }
1392 }
1393 return false;
1394 }
1395
1396 std::multimap<std::string, std::string> ExifMetadatFormatter::valueTemplateConfig = {
1397 {"ExposureTime", "(\\d+/\\d+) sec\\."},
1398 {"ExposureTime", "(\\d+\\.\\d+|\\d+) sec\\."},
1399 {"FNumber", "f/(\\d+\\.\\d+)"},
1400 {"ApertureValue", "(\\d+\\.\\d+) EV \\(f/\\d+\\.\\d+\\)"},
1401 {"ExposureBiasValue", "(\\d+\\.\\d+) EV"},
1402 {"FocalLength", "(\\d+\\.\\d+) mm"},
1403 {"ShutterSpeedValue", "(\\d+\\.\\d+) EV \\(\\d+/\\d+ sec\\.\\)"},
1404 {"BrightnessValue", "(\\d+\\.\\d+) EV \\(\\d+\\.\\d+ cd/m\\^\\d+\\)"},
1405 {"MaxApertureValue", "(\\d+\\.\\d+) EV \\(f/\\d+\\.\\d+\\)"},
1406 {"SubjectDistance", "(\\d+\\.\\d+) m"},
1407 {"SubjectArea", "\\(x,y\\) = \\((\\d+,\\d+)\\)"},
1408 {"ExifVersion", "Exif Version ([0-9]{1,2}\\.[0-9]{1,2})"},
1409 {"FlashpixVersion", "FlashPix Version ([0-9]{1,2}\\.[0-9]{1,2})"},
1410 {"Copyright", "^(.*) \\(Photographer\\) \\- \\[None\\] \\(Editor\\)$"},
1411 };
1412
ExtractValue(const std::string & keyName,std::string & value)1413 void ExifMetadatFormatter::ExtractValue(const std::string &keyName, std::string &value)
1414 {
1415 auto it = ExifMetadatFormatter::valueTemplateConfig.find(keyName);
1416 if (it == ExifMetadatFormatter::valueTemplateConfig.end()) {
1417 return;
1418 }
1419 for (; it != ExifMetadatFormatter::valueTemplateConfig.end() &&
1420 it != ExifMetadatFormatter::valueTemplateConfig.upper_bound(keyName);
1421 it++) {
1422 std::regex pattern(it->second);
1423 for (std::sregex_iterator i = std::sregex_iterator(value.begin(), value.end(), pattern);
1424 i != std::sregex_iterator();
1425 ++i) {
1426 std::smatch match = *i;
1427 std::string subStr = match[1].str();
1428 if (!subStr.empty()) {
1429 value = subStr;
1430 }
1431 }
1432 }
1433 }
1434
1435
1436 // validate value format. For example BitPerSample the value format should be 9 9 9 or 9,9,9
ConvertValueFormat(const std::string & keyName,std::string & value)1437 int32_t ExifMetadatFormatter::ConvertValueFormat(const std::string &keyName, std::string &value)
1438 {
1439 if (IsSensitiveInfo(keyName)) {
1440 IMAGE_LOGD("ConvertValueFormat keyName is [%{public}s].", keyName.c_str());
1441 } else {
1442 IMAGE_LOGD("ConvertValueFormat keyName is [%{public}s] value is [%{public}s].", keyName.c_str(), value.c_str());
1443 }
1444
1445 auto it = ExifMetadatFormatter::valueFormatConvertConfig.find(keyName);
1446 if (it == ExifMetadatFormatter::valueFormatConvertConfig.end()) {
1447 IMAGE_LOGD("No format validation needed. Defaulting to success.");
1448 return Media::SUCCESS;
1449 }
1450 IMAGE_LOGD("Validating value format. Key: %{public}s", keyName.c_str());
1451
1452 // get first iterator according to keyName
1453 for (; it != ExifMetadatFormatter::valueFormatConvertConfig.end() &&
1454 it != ExifMetadatFormatter::valueFormatConvertConfig.upper_bound(keyName);
1455 it++) {
1456 IMAGE_LOGD("Validating value format in loop. Key: %{public}s, Regex: %{public}s", (it->first).c_str(),
1457 (it->second).second.c_str());
1458 auto func = (it->second).first;
1459
1460 // call each value format function with value and regex
1461 int32_t isValid = func(value, (it->second).second);
1462 IMAGE_LOGD("Validation result: %{public}d", isValid);
1463 if (isValid) {
1464 IMAGE_LOGD("Validation successful.");
1465 return Media::SUCCESS;
1466 }
1467 }
1468
1469 IMAGE_LOGD("Validation failed. Unsupported EXIF format.");
1470 return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
1471 }
1472
IsKeySupported(const std::string & keyName)1473 bool ExifMetadatFormatter::IsKeySupported(const std::string &keyName)
1474 {
1475 auto wit = READ_WRITE_KEYS.find(keyName);
1476 auto rit = READ_ONLY_KEYS.find(keyName);
1477 return (wit != READ_WRITE_KEYS.end() || rit != READ_ONLY_KEYS.end());
1478 }
1479
GetRWKeys()1480 const std::set<std::string> &ExifMetadatFormatter::GetRWKeys()
1481 {
1482 return READ_WRITE_KEYS;
1483 }
1484
GetROKeys()1485 const std::set<std::string> &ExifMetadatFormatter::GetROKeys()
1486 {
1487 return READ_ONLY_KEYS;
1488 }
1489
IsModifyAllowed(const std::string & keyName)1490 bool ExifMetadatFormatter::IsModifyAllowed(const std::string &keyName)
1491 {
1492 auto it = READ_WRITE_KEYS.find(keyName);
1493 return (it != READ_WRITE_KEYS.end());
1494 }
1495
Format(const std::string & keyName,const std::string & value)1496 std::pair<int32_t, std::string> ExifMetadatFormatter::Format(const std::string &keyName, const std::string &value)
1497 {
1498 if (IsSensitiveInfo(keyName)) {
1499 IMAGE_LOGD("Processing. Key: %{public}s.", keyName.c_str());
1500 } else {
1501 IMAGE_LOGD("Processing. Key: %{public}s, Value: %{public}s.", keyName.c_str(), value.c_str());
1502 }
1503 std::string tmpValue = value;
1504
1505 if (!ExifMetadatFormatter::IsKeySupported(keyName)) {
1506 IMAGE_LOGD("Key is not supported.");
1507 return std::make_pair(Media::ERR_MEDIA_WRITE_PARCEL_FAIL, "");
1508 }
1509
1510 if (!ExifMetadatFormatter::IsModifyAllowed(keyName)) {
1511 IMAGE_LOGD("Key is not allowed to modify.");
1512 return std::make_pair(Media::ERR_MEDIA_WRITE_PARCEL_FAIL, "");
1513 }
1514
1515 if (ExifMetadatFormatter::IsForbiddenValue(tmpValue)) {
1516 return std::make_pair(Media::ERR_MEDIA_VALUE_INVALID, "");
1517 }
1518 ExifMetadatFormatter::ConvertRangeValue(keyName, tmpValue);
1519 ExifMetadatFormatter::ExtractValue(keyName, tmpValue);
1520
1521 // 1.validate value format
1522 if (ExifMetadatFormatter::ConvertValueFormat(keyName, tmpValue)) {
1523 IMAGE_LOGD("Invalid value format for key:%{public}s.", keyName.c_str());
1524 // value format validate does not pass
1525 return std::make_pair(Media::ERR_MEDIA_VALUE_INVALID, "");
1526 }
1527 IMAGE_LOGD("Processed format value. Key: %{public}s", keyName.c_str());
1528
1529 // 2.validate value range
1530 if (ExifMetadatFormatter::ValidateValueRange(keyName, tmpValue)) {
1531 IMAGE_LOGD("Invalid value range for Key: %{public}s.", keyName.c_str());
1532 // value range validate does not pass
1533 return std::make_pair(Media::ERR_MEDIA_VALUE_INVALID, "");
1534 }
1535 return std::make_pair(Media::SUCCESS, tmpValue);
1536 }
1537
ConvertToInt(const std::string & str,int & value)1538 static bool ConvertToInt(const std::string& str, int& value)
1539 {
1540 auto [ptr, errCode] = std::from_chars(str.data(), str.data() + str.size(), value);
1541 bool ret = errCode == std::errc{} && (ptr == str.data() + str.size());
1542 return ret;
1543 }
1544
StrToDouble(const std::string & value,double & output)1545 static bool StrToDouble(const std::string &value, double &output)
1546 {
1547 if (value.empty()) {
1548 return false;
1549 }
1550 size_t slashPos = value.find('/');
1551 if (slashPos == std::string::npos) {
1552 IMAGE_LOGE("StrToDouble split error");
1553 return false;
1554 }
1555 std::string numeratorStr = value.substr(0, slashPos);
1556 std::string denominatorStr = value.substr(slashPos + 1);
1557 int numerator = 0;
1558 if (!ConvertToInt(numeratorStr, numerator)) {
1559 IMAGE_LOGI("numeratorStr = %{public}s convert convert string to int failed", numeratorStr.c_str());
1560 return false;
1561 }
1562 int denominator = 0;
1563 if (!ConvertToInt(denominatorStr, denominator)) {
1564 IMAGE_LOGI("denominatorStr = %{public}s convert convert string to int failed", denominatorStr.c_str());
1565 return false;
1566 }
1567 if (denominator == 0) {
1568 return false;
1569 }
1570 output = static_cast<double>(numerator) / denominator;
1571 return true;
1572 }
1573
ValidLatLong(const std::string & key,const std::string & value)1574 static bool ValidLatLong(const std::string &key, const std::string &value)
1575 {
1576 IMAGE_LOGD("ValidLatLong key is %{public}s", key.c_str());
1577
1578 double degree = 0.0;
1579 double minute = 0.0;
1580 double second = 0.0;
1581
1582 std::vector<std::string> tokens;
1583 SplitStr(value, " ", tokens);
1584 if (tokens.size() != GPS_NORMAL_SIZE) {
1585 IMAGE_LOGE("value size is not 3. token size %{public}lu", static_cast<unsigned long>(tokens.size()));
1586 return false;
1587 }
1588 if (!StrToDouble(tokens[CONSTANT_0], degree) || !StrToDouble(tokens[CONSTANT_1], minute) ||
1589 !StrToDouble(tokens[CONSTANT_2], second)) {
1590 IMAGE_LOGE("Convert gps data to double type failed.");
1591 return false;
1592 }
1593 constexpr uint32_t timePeriod = 60;
1594 double latOrLong = degree + minute / timePeriod + second / (timePeriod * timePeriod);
1595
1596 if (key == "GPSLatitude" && (latOrLong > GPS_MAX_LATITUDE || latOrLong < GPS_MIN_LATITUDE)) {
1597 IMAGE_LOGE("GPSLatitude is out of range.");
1598 return false;
1599 }
1600 if (key == "GPSLongitude" && (latOrLong > GPS_MAX_LONGITUDE || latOrLong < GPS_MIN_LONGITUDE)) {
1601 IMAGE_LOGE("GPSLongitude is out of range.");
1602 return false;
1603 }
1604 return true;
1605 }
1606
IsUint16(const std::string & s)1607 static bool IsUint16(const std::string &s)
1608 {
1609 std::istringstream iss(s);
1610 uint16_t num;
1611 iss >> num;
1612 return !iss.fail() && iss.eof();
1613 }
1614
1615 // exif validation portal
Validate(const std::string & keyName,const std::string & value)1616 int32_t ExifMetadatFormatter::Validate(const std::string &keyName, const std::string &value)
1617 {
1618 if (IsSensitiveInfo(keyName)) {
1619 IMAGE_LOGD("Validating. Key: %{public}s", keyName.c_str());
1620 } else {
1621 IMAGE_LOGD("Validating. Key: %{public}s, Value: %{public}s.", keyName.c_str(), value.c_str());
1622 }
1623 auto result = ExifMetadatFormatter::Format(keyName, value);
1624 if (result.first) {
1625 IMAGE_LOGE("Validating Error %{public}d", result.first);
1626 return result.first;
1627 }
1628
1629 if ((keyName == "GPSLatitude" || keyName == "GPSLongitude") &&
1630 !ValidLatLong(keyName, result.second)) {
1631 IMAGE_LOGE("Validating GPSLatLong Error");
1632 return ERR_MEDIA_VALUE_INVALID;
1633 }
1634
1635 if ((UINT16_KEYS.find(keyName) != UINT16_KEYS.end()) &&
1636 !IsUint16(result.second)) {
1637 IMAGE_LOGE("Validating uint16 Error %{public}s", result.second.c_str());
1638 return ERR_MEDIA_VALUE_INVALID;
1639 }
1640 IMAGE_LOGD("Validate ret: %{public}d", result.first);
1641 return result.first;
1642 }
1643
IsSensitiveInfo(const std::string & keyName)1644 bool ExifMetadatFormatter::IsSensitiveInfo(const std::string &keyName)
1645 {
1646 std::regex pattern(SENSITIVE_REGEX, std::regex::icase);
1647 return std::regex_search(keyName, pattern);
1648 }
1649 } // namespace Media
1650 } // namespace OHOS
1651