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