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