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 &regex)
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 &regex)
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 &regex, 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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex)
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 &regex : 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