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