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