exiftool-vendored.pl 13.0.0 → 13.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/bin/Changes +254 -20
  2. package/bin/MANIFEST +10 -0
  3. package/bin/META.json +1 -1
  4. package/bin/META.yml +1 -1
  5. package/bin/README +3 -3
  6. package/bin/arg_files/exif2xmp.args +4 -0
  7. package/bin/arg_files/xmp2exif.args +2 -1
  8. package/bin/build_geolocation +1 -1
  9. package/bin/exiftool +356 -213
  10. package/bin/lib/File/RandomAccess.pm +1 -1
  11. package/bin/lib/File/RandomAccess.pod +2 -2
  12. package/bin/lib/Image/ExifTool/AAC.pm +1 -1
  13. package/bin/lib/Image/ExifTool/AES.pm +1 -1
  14. package/bin/lib/Image/ExifTool/AFCP.pm +6 -6
  15. package/bin/lib/Image/ExifTool/AIFF.pm +2 -2
  16. package/bin/lib/Image/ExifTool/APE.pm +2 -2
  17. package/bin/lib/Image/ExifTool/APP12.pm +1 -1
  18. package/bin/lib/Image/ExifTool/ASF.pm +2 -2
  19. package/bin/lib/Image/ExifTool/Apple.pm +11 -9
  20. package/bin/lib/Image/ExifTool/Audible.pm +1 -1
  21. package/bin/lib/Image/ExifTool/BMP.pm +1 -1
  22. package/bin/lib/Image/ExifTool/BPG.pm +1 -1
  23. package/bin/lib/Image/ExifTool/BZZ.pm +1 -1
  24. package/bin/lib/Image/ExifTool/BigTIFF.pm +1 -1
  25. package/bin/lib/Image/ExifTool/BuildTagLookup.pm +36 -22
  26. package/bin/lib/Image/ExifTool/CBOR.pm +5 -2
  27. package/bin/lib/Image/ExifTool/Canon.pm +66 -27
  28. package/bin/lib/Image/ExifTool/CanonCustom.pm +1 -1
  29. package/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
  30. package/bin/lib/Image/ExifTool/CanonVRD.pm +1 -1
  31. package/bin/lib/Image/ExifTool/CaptureOne.pm +1 -1
  32. package/bin/lib/Image/ExifTool/Casio.pm +1 -1
  33. package/bin/lib/Image/ExifTool/Charset.pm +1 -1
  34. package/bin/lib/Image/ExifTool/DICOM.pm +1 -1
  35. package/bin/lib/Image/ExifTool/DJI.pm +196 -30
  36. package/bin/lib/Image/ExifTool/DNG.pm +1 -1
  37. package/bin/lib/Image/ExifTool/DPX.pm +1 -1
  38. package/bin/lib/Image/ExifTool/DV.pm +1 -1
  39. package/bin/lib/Image/ExifTool/DarwinCore.pm +1 -1
  40. package/bin/lib/Image/ExifTool/DjVu.pm +1 -1
  41. package/bin/lib/Image/ExifTool/EXE.pm +138 -33
  42. package/bin/lib/Image/ExifTool/Exif.pm +29 -16
  43. package/bin/lib/Image/ExifTool/FITS.pm +3 -3
  44. package/bin/lib/Image/ExifTool/FLAC.pm +1 -1
  45. package/bin/lib/Image/ExifTool/FLIF.pm +3 -3
  46. package/bin/lib/Image/ExifTool/FLIR.pm +1 -1
  47. package/bin/lib/Image/ExifTool/Fixup.pm +1 -1
  48. package/bin/lib/Image/ExifTool/Flash.pm +1 -1
  49. package/bin/lib/Image/ExifTool/FlashPix.pm +17 -21
  50. package/bin/lib/Image/ExifTool/Font.pm +2 -2
  51. package/bin/lib/Image/ExifTool/FotoStation.pm +1 -1
  52. package/bin/lib/Image/ExifTool/FujiFilm.pm +1 -1
  53. package/bin/lib/Image/ExifTool/GE.pm +1 -1
  54. package/bin/lib/Image/ExifTool/GIF.pm +144 -93
  55. package/bin/lib/Image/ExifTool/GIMP.pm +1 -1
  56. package/bin/lib/Image/ExifTool/GM.pm +1 -1
  57. package/bin/lib/Image/ExifTool/GPS.pm +34 -30
  58. package/bin/lib/Image/ExifTool/GeoTiff.pm +1 -1
  59. package/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  60. package/bin/lib/Image/ExifTool/Geolocation.pm +19 -9
  61. package/bin/lib/Image/ExifTool/Geotag.pm +46 -12
  62. package/bin/lib/Image/ExifTool/GoPro.pm +120 -8
  63. package/bin/lib/Image/ExifTool/H264.pm +1 -1
  64. package/bin/lib/Image/ExifTool/HP.pm +2 -2
  65. package/bin/lib/Image/ExifTool/HTML.pm +1 -1
  66. package/bin/lib/Image/ExifTool/HtmlDump.pm +1 -1
  67. package/bin/lib/Image/ExifTool/ICC_Profile.pm +81 -2
  68. package/bin/lib/Image/ExifTool/ICO.pm +1 -1
  69. package/bin/lib/Image/ExifTool/ID3.pm +8 -8
  70. package/bin/lib/Image/ExifTool/IPTC.pm +10 -7
  71. package/bin/lib/Image/ExifTool/ISO.pm +1 -1
  72. package/bin/lib/Image/ExifTool/ITC.pm +1 -1
  73. package/bin/lib/Image/ExifTool/Import.pm +5 -4
  74. package/bin/lib/Image/ExifTool/InDesign.pm +2 -2
  75. package/bin/lib/Image/ExifTool/InfiRay.pm +1 -1
  76. package/bin/lib/Image/ExifTool/JPEG.pm +32 -5
  77. package/bin/lib/Image/ExifTool/JPEGDigest.pm +1 -1
  78. package/bin/lib/Image/ExifTool/JSON.pm +1 -1
  79. package/bin/lib/Image/ExifTool/JVC.pm +1 -1
  80. package/bin/lib/Image/ExifTool/Jpeg2000.pm +10 -9
  81. package/bin/lib/Image/ExifTool/Kodak.pm +1 -1
  82. package/bin/lib/Image/ExifTool/KyoceraRaw.pm +1 -1
  83. package/bin/lib/Image/ExifTool/LIF.pm +1 -1
  84. package/bin/lib/Image/ExifTool/LNK.pm +2 -2
  85. package/bin/lib/Image/ExifTool/Lang/cs.pm +1 -1
  86. package/bin/lib/Image/ExifTool/Lang/de.pm +1 -1
  87. package/bin/lib/Image/ExifTool/Lang/en_ca.pm +1 -1
  88. package/bin/lib/Image/ExifTool/Lang/en_gb.pm +1 -1
  89. package/bin/lib/Image/ExifTool/Lang/es.pm +1 -1
  90. package/bin/lib/Image/ExifTool/Lang/fi.pm +1 -1
  91. package/bin/lib/Image/ExifTool/Lang/fr.pm +1 -1
  92. package/bin/lib/Image/ExifTool/Lang/it.pm +1 -1
  93. package/bin/lib/Image/ExifTool/Lang/ja.pm +1 -1
  94. package/bin/lib/Image/ExifTool/Lang/ko.pm +1 -1
  95. package/bin/lib/Image/ExifTool/Lang/nl.pm +1 -1
  96. package/bin/lib/Image/ExifTool/Lang/pl.pm +1 -1
  97. package/bin/lib/Image/ExifTool/Lang/ru.pm +1 -1
  98. package/bin/lib/Image/ExifTool/Lang/sk.pm +1 -1
  99. package/bin/lib/Image/ExifTool/Lang/sv.pm +1 -1
  100. package/bin/lib/Image/ExifTool/Lang/tr.pm +1 -1
  101. package/bin/lib/Image/ExifTool/Lang/zh_cn.pm +1 -1
  102. package/bin/lib/Image/ExifTool/Lang/zh_tw.pm +1 -1
  103. package/bin/lib/Image/ExifTool/Leaf.pm +1 -1
  104. package/bin/lib/Image/ExifTool/LigoGPS.pm +409 -0
  105. package/bin/lib/Image/ExifTool/Lytro.pm +1 -1
  106. package/bin/lib/Image/ExifTool/M2TS.pm +57 -18
  107. package/bin/lib/Image/ExifTool/MIE.pm +15 -6
  108. package/bin/lib/Image/ExifTool/MIEUnits.pod +1 -1
  109. package/bin/lib/Image/ExifTool/MIFF.pm +1 -1
  110. package/bin/lib/Image/ExifTool/MISB.pm +1 -1
  111. package/bin/lib/Image/ExifTool/MNG.pm +1 -1
  112. package/bin/lib/Image/ExifTool/MOI.pm +1 -1
  113. package/bin/lib/Image/ExifTool/MPC.pm +1 -1
  114. package/bin/lib/Image/ExifTool/MPEG.pm +1 -1
  115. package/bin/lib/Image/ExifTool/MPF.pm +1 -1
  116. package/bin/lib/Image/ExifTool/MRC.pm +1 -1
  117. package/bin/lib/Image/ExifTool/MWG.pm +1 -1
  118. package/bin/lib/Image/ExifTool/MXF.pm +3 -3
  119. package/bin/lib/Image/ExifTool/MacOS.pm +3 -2
  120. package/bin/lib/Image/ExifTool/MakerNotes.pm +1 -1
  121. package/bin/lib/Image/ExifTool/Matroska.pm +22 -6
  122. package/bin/lib/Image/ExifTool/Microsoft.pm +2 -2
  123. package/bin/lib/Image/ExifTool/Minolta.pm +1 -1
  124. package/bin/lib/Image/ExifTool/MinoltaRaw.pm +1 -1
  125. package/bin/lib/Image/ExifTool/Motorola.pm +1 -1
  126. package/bin/lib/Image/ExifTool/Nikon.pm +495 -39
  127. package/bin/lib/Image/ExifTool/NikonCapture.pm +1 -1
  128. package/bin/lib/Image/ExifTool/NikonCustom.pm +2 -2
  129. package/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
  130. package/bin/lib/Image/ExifTool/Nintendo.pm +1 -1
  131. package/bin/lib/Image/ExifTool/OOXML.pm +8 -8
  132. package/bin/lib/Image/ExifTool/Ogg.pm +1 -1
  133. package/bin/lib/Image/ExifTool/Olympus.pm +1 -1
  134. package/bin/lib/Image/ExifTool/OpenEXR.pm +1 -1
  135. package/bin/lib/Image/ExifTool/Opus.pm +1 -1
  136. package/bin/lib/Image/ExifTool/Other.pm +1 -1
  137. package/bin/lib/Image/ExifTool/PCX.pm +1 -1
  138. package/bin/lib/Image/ExifTool/PDF.pm +49 -18
  139. package/bin/lib/Image/ExifTool/PGF.pm +1 -1
  140. package/bin/lib/Image/ExifTool/PICT.pm +1 -1
  141. package/bin/lib/Image/ExifTool/PLIST.pm +4 -4
  142. package/bin/lib/Image/ExifTool/PLUS.pm +1 -1
  143. package/bin/lib/Image/ExifTool/PNG.pm +20 -8
  144. package/bin/lib/Image/ExifTool/PPM.pm +12 -3
  145. package/bin/lib/Image/ExifTool/PSP.pm +1 -1
  146. package/bin/lib/Image/ExifTool/Palm.pm +1 -1
  147. package/bin/lib/Image/ExifTool/Panasonic.pm +27 -3
  148. package/bin/lib/Image/ExifTool/PanasonicRaw.pm +1 -1
  149. package/bin/lib/Image/ExifTool/Parrot.pm +1 -1
  150. package/bin/lib/Image/ExifTool/Pentax.pm +1 -1
  151. package/bin/lib/Image/ExifTool/PhaseOne.pm +4 -4
  152. package/bin/lib/Image/ExifTool/PhotoCD.pm +1 -1
  153. package/bin/lib/Image/ExifTool/PhotoMechanic.pm +1 -1
  154. package/bin/lib/Image/ExifTool/Photoshop.pm +65 -4
  155. package/bin/lib/Image/ExifTool/PostScript.pm +1 -1
  156. package/bin/lib/Image/ExifTool/PrintIM.pm +1 -1
  157. package/bin/lib/Image/ExifTool/Protobuf.pm +270 -0
  158. package/bin/lib/Image/ExifTool/Qualcomm.pm +1 -1
  159. package/bin/lib/Image/ExifTool/QuickTime.pm +326 -88
  160. package/bin/lib/Image/ExifTool/QuickTimeStream.pl +199 -195
  161. package/bin/lib/Image/ExifTool/README +12 -2
  162. package/bin/lib/Image/ExifTool/RIFF.pm +21 -6
  163. package/bin/lib/Image/ExifTool/RSRC.pm +1 -1
  164. package/bin/lib/Image/ExifTool/RTF.pm +2 -2
  165. package/bin/lib/Image/ExifTool/Radiance.pm +1 -1
  166. package/bin/lib/Image/ExifTool/Rawzor.pm +1 -1
  167. package/bin/lib/Image/ExifTool/Real.pm +1 -1
  168. package/bin/lib/Image/ExifTool/Reconyx.pm +1 -1
  169. package/bin/lib/Image/ExifTool/Red.pm +1 -1
  170. package/bin/lib/Image/ExifTool/Ricoh.pm +4 -4
  171. package/bin/lib/Image/ExifTool/Samsung.pm +2 -2
  172. package/bin/lib/Image/ExifTool/Sanyo.pm +1 -1
  173. package/bin/lib/Image/ExifTool/Scalado.pm +1 -1
  174. package/bin/lib/Image/ExifTool/Shift.pl +1 -1
  175. package/bin/lib/Image/ExifTool/Shortcuts.pm +1 -1
  176. package/bin/lib/Image/ExifTool/Sigma.pm +1 -1
  177. package/bin/lib/Image/ExifTool/SigmaRaw.pm +1 -1
  178. package/bin/lib/Image/ExifTool/Sony.pm +5 -4
  179. package/bin/lib/Image/ExifTool/SonyIDC.pm +1 -1
  180. package/bin/lib/Image/ExifTool/Stim.pm +1 -1
  181. package/bin/lib/Image/ExifTool/TagInfoXML.pm +6 -5
  182. package/bin/lib/Image/ExifTool/TagLookup.pm +7023 -6968
  183. package/bin/lib/Image/ExifTool/TagNames.pod +445 -29
  184. package/bin/lib/Image/ExifTool/Text.pm +4 -3
  185. package/bin/lib/Image/ExifTool/Theora.pm +1 -1
  186. package/bin/lib/Image/ExifTool/Torrent.pm +3 -3
  187. package/bin/lib/Image/ExifTool/Unknown.pm +1 -1
  188. package/bin/lib/Image/ExifTool/VCard.pm +3 -3
  189. package/bin/lib/Image/ExifTool/Validate.pm +6 -6
  190. package/bin/lib/Image/ExifTool/Vivo.pm +124 -0
  191. package/bin/lib/Image/ExifTool/Vorbis.pm +1 -1
  192. package/bin/lib/Image/ExifTool/WPG.pm +1 -1
  193. package/bin/lib/Image/ExifTool/WTV.pm +1 -1
  194. package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
  195. package/bin/lib/Image/ExifTool/WriteExif.pl +3 -3
  196. package/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
  197. package/bin/lib/Image/ExifTool/WritePDF.pl +1 -1
  198. package/bin/lib/Image/ExifTool/WritePNG.pl +1 -1
  199. package/bin/lib/Image/ExifTool/WritePhotoshop.pl +1 -1
  200. package/bin/lib/Image/ExifTool/WritePostScript.pl +1 -1
  201. package/bin/lib/Image/ExifTool/WriteQuickTime.pl +166 -79
  202. package/bin/lib/Image/ExifTool/WriteRIFF.pl +17 -6
  203. package/bin/lib/Image/ExifTool/WriteXMP.pl +3 -3
  204. package/bin/lib/Image/ExifTool/Writer.pl +89 -96
  205. package/bin/lib/Image/ExifTool/XISF.pm +1 -1
  206. package/bin/lib/Image/ExifTool/XMP.pm +28 -13
  207. package/bin/lib/Image/ExifTool/XMP2.pl +103 -1
  208. package/bin/lib/Image/ExifTool/XMPStruct.pl +2 -3
  209. package/bin/lib/Image/ExifTool/ZIP.pm +2 -2
  210. package/bin/lib/Image/ExifTool/ZISRAW.pm +1 -1
  211. package/bin/lib/Image/ExifTool/iWork.pm +1 -1
  212. package/bin/lib/Image/ExifTool.pm +335 -163
  213. package/bin/lib/Image/ExifTool.pod +119 -73
  214. package/bin/perl-Image-ExifTool.spec +1 -1
  215. package/bin/windows_exiftool.txt +96 -51
  216. package/package.json +9 -9
@@ -4005,7 +4005,7 @@ and values.
4005
4005
 
4006
4006
  =head1 AUTHOR
4007
4007
 
4008
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
4008
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
4009
4009
 
4010
4010
  This library is free software; you can redistribute it and/or modify it
4011
4011
  under the same terms as Perl itself.
@@ -2878,7 +2878,7 @@ and values.
2878
2878
 
2879
2879
  =head1 AUTHOR
2880
2880
 
2881
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
2881
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
2882
2882
 
2883
2883
  This library is free software; you can redistribute it and/or modify it
2884
2884
  under the same terms as Perl itself.
@@ -11270,7 +11270,7 @@ and values.
11270
11270
 
11271
11271
  =head1 AUTHOR
11272
11272
 
11273
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
11273
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
11274
11274
 
11275
11275
  This library is free software; you can redistribute it and/or modify it
11276
11276
  under the same terms as Perl itself.
@@ -7903,7 +7903,7 @@ and values.
7903
7903
 
7904
7904
  =head1 AUTHOR
7905
7905
 
7906
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
7906
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
7907
7907
 
7908
7908
  This library is free software; you can redistribute it and/or modify it
7909
7909
  under the same terms as Perl itself.
@@ -5841,7 +5841,7 @@ and values.
5841
5841
 
5842
5842
  =head1 AUTHOR
5843
5843
 
5844
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
5844
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
5845
5845
 
5846
5846
  This library is free software; you can redistribute it and/or modify it
5847
5847
  under the same terms as Perl itself.
@@ -2316,7 +2316,7 @@ and values.
2316
2316
 
2317
2317
  =head1 AUTHOR
2318
2318
 
2319
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
2319
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
2320
2320
 
2321
2321
  This library is free software; you can redistribute it and/or modify it
2322
2322
  under the same terms as Perl itself.
@@ -3208,7 +3208,7 @@ and values.
3208
3208
 
3209
3209
  =head1 AUTHOR
3210
3210
 
3211
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
3211
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
3212
3212
 
3213
3213
  This library is free software; you can redistribute it and/or modify it
3214
3214
  under the same terms as Perl itself.
@@ -1258,7 +1258,7 @@ and values.
1258
1258
 
1259
1259
  =head1 AUTHOR
1260
1260
 
1261
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
1261
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
1262
1262
 
1263
1263
  This library is free software; you can redistribute it and/or modify it
1264
1264
  under the same terms as Perl itself.
@@ -5718,7 +5718,7 @@ and values.
5718
5718
 
5719
5719
  =head1 AUTHOR
5720
5720
 
5721
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
5721
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
5722
5722
 
5723
5723
  This library is free software; you can redistribute it and/or modify it
5724
5724
  under the same terms as Perl itself.
@@ -1789,7 +1789,7 @@ and values.
1789
1789
 
1790
1790
  =head1 AUTHOR
1791
1791
 
1792
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
1792
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
1793
1793
 
1794
1794
  This library is free software; you can redistribute it and/or modify it
1795
1795
  under the same terms as Perl itself.
@@ -620,7 +620,7 @@ and values.
620
620
 
621
621
  =head1 AUTHOR
622
622
 
623
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
623
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
624
624
 
625
625
  This library is free software; you can redistribute it and/or modify it
626
626
  under the same terms as Perl itself.
@@ -528,7 +528,7 @@ and values.
528
528
 
529
529
  =head1 AUTHOR
530
530
 
531
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
531
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
532
532
 
533
533
  This library is free software; you can redistribute it and/or modify it
534
534
  under the same terms as Perl itself.
@@ -1313,7 +1313,7 @@ and values.
1313
1313
 
1314
1314
  =head1 AUTHOR
1315
1315
 
1316
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
1316
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
1317
1317
 
1318
1318
  This library is free software; you can redistribute it and/or modify it
1319
1319
  under the same terms as Perl itself.
@@ -784,7 +784,7 @@ and values.
784
784
 
785
785
  =head1 AUTHOR
786
786
 
787
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
787
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
788
788
 
789
789
  This library is free software; you can redistribute it and/or modify it
790
790
  under the same terms as Perl itself.
@@ -504,7 +504,7 @@ Capture.
504
504
 
505
505
  =head1 AUTHOR
506
506
 
507
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
507
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
508
508
 
509
509
  This library is free software; you can redistribute it and/or modify it
510
510
  under the same terms as Perl itself.
@@ -0,0 +1,409 @@
1
+ #------------------------------------------------------------------------------
2
+ # File: LigoGPS.pm
3
+ #
4
+ # Description: Read LIGOGPSINFO timed GPS records
5
+ #
6
+ # Revisions: 2024-12-30 - P. Harvey Created
7
+ #------------------------------------------------------------------------------
8
+ package Image::ExifTool::LigoGPS;
9
+
10
+ use strict;
11
+ use vars qw($VERSION);
12
+ use Image::ExifTool;
13
+
14
+ $VERSION = '1.02';
15
+
16
+ sub ProcessLigoGPS($$$;$);
17
+ sub ProcessLigoJSON($$$);
18
+ sub OrderCipherDigits($$$;$);
19
+
20
+ my $knotsToKph = 1.852; # knots --> km/h
21
+
22
+ #------------------------------------------------------------------------------
23
+ # Clean up cipher variables and print warning if deciphering was unsuccessful
24
+ # Inputs: 0) ExifTool ref
25
+ sub CleanupCipher($)
26
+ {
27
+ my $et = shift;
28
+ if ($$et{LigoCipher} and $$et{LigoCipher}{'next'}) {
29
+ $et->Warn('Not enough GPS points to determine cipher for decoding LIGOGPSINFO');
30
+ }
31
+ delete $$et{LigoCipher};
32
+ }
33
+
34
+ #------------------------------------------------------------------------------
35
+ # Un-do LIGOGPS fuzzing
36
+ # Inputs: 0) fuzzed latitude, 1) fuzzed longitude, 2) scale factor
37
+ # Returns: 0) latitude, 1) longitude
38
+ sub UnfuzzLigoGPS($$$)
39
+ {
40
+ my ($lat, $lon, $scl) = @_;
41
+ my $lat2 = int($lat / 10) * 10;
42
+ my $lon2 = int($lon / 10) * 10;
43
+ return($lat2 + ($lon - $lon2) * $scl, $lon2 + ($lat - $lat2) * $scl);
44
+ }
45
+
46
+ #------------------------------------------------------------------------------
47
+ # Decrypt LIGOGPSINFO record (starting with "####")
48
+ # Inputs: 0) encrypted GPS record incuding 8-byte header
49
+ # Returns: decrypted record including 4-byte uint32 header, or undef on error
50
+ sub DecryptLigoGPS($)
51
+ {
52
+ my $str = shift;
53
+ my $num = unpack('x4V',$str);
54
+ return undef if $num < 4;
55
+ $num = 0x84 if $num > 0x84; # (be safe)
56
+ my @in = unpack("x8C$num",$str);
57
+ my @out;
58
+ while (@in) {
59
+ my $b = shift @in; # get next byte in data
60
+ # upper 3 bits steer the decryption for this round
61
+ my $steeringBits = $b & 0xe0;
62
+ if ($steeringBits >= 0xc0) {
63
+ return undef if @in < 4; # next 4 bytes are encrypted data
64
+ push @out, (shift(@in) | $b & 0x01) ^ 0x20,
65
+ (shift(@in) | $b & 0x02) ^ 0x20,
66
+ (shift(@in) | $b & 0x0c) ^ 0x20,
67
+ shift(@in) ^ 0x20 | $b & 0x30;
68
+ } elsif ($steeringBits >= 0x40) {
69
+ return undef if @in < 3; # next 3 bytes are encrypted data
70
+ if ($steeringBits == 0x40) {
71
+ push @out, 0x20,
72
+ (shift(@in) | $b & 0x01) ^ 0x20,
73
+ (shift(@in) | $b & 0x06) ^ 0x20,
74
+ (shift(@in) | $b & 0x18) ^ 0x20;
75
+ } elsif ($steeringBits == 0x60) {
76
+ push @out, (shift(@in) | $b & 0x03) ^ 0x20,
77
+ 0x20,
78
+ (shift(@in) | $b & 0x04) ^ 0x20,
79
+ (shift(@in) | $b & 0x18) ^ 0x20;
80
+ } elsif ($steeringBits == 0x80) {
81
+ push @out, (shift(@in) | $b & 0x03) ^ 0x20,
82
+ (shift(@in) | $b & 0x0c) ^ 0x20,
83
+ 0x20,
84
+ (shift(@in) | $b & 0x10) ^ 0x20;
85
+ } else {
86
+ push @out, (shift(@in) | $b & 0x01) ^ 0x20,
87
+ (shift(@in) | $b & 0x06) ^ 0x20,
88
+ (shift(@in) | $b & 0x18) ^ 0x20,
89
+ 0x20;
90
+ }
91
+ } elsif ($steeringBits == 0x00) {
92
+ return undef if @in < 1; # next byte is encrypted data
93
+ push @out, shift(@in) | $b & 0x13;
94
+ } else {
95
+ return undef; # (shouldn't happen)
96
+ }
97
+ }
98
+ return pack 'C*', @out;
99
+ }
100
+
101
+ #------------------------------------------------------------------------------
102
+ # Determine correct ordering of enciphered digits (unit digits of seconds)
103
+ # Inputs: 0) starting character code, 1) lookup for next character(s) in sequence
104
+ # 2) i/o list of ordered characters, 3) hash of used characters
105
+ # Returns: true if a consistent ordering was found
106
+ # - loops through all possible orders based on $next sequence until a complete
107
+ # cycle is established
108
+ # - this complexity is necessary because GPS may skip some seconds
109
+ sub OrderCipherDigits($$$;$)
110
+ {
111
+ my ($ch, $next, $order, $did) = @_;
112
+ $did or $did = { };
113
+ while ($$next{$ch}) {
114
+ if (@$order < 10) {
115
+ last if $$did{$ch};
116
+ } else {
117
+ # success if we have cycled through all 10 digits and back to the first
118
+ return 1 if @$order == 10 and $ch eq $$order[0];
119
+ last;
120
+ }
121
+ push @$order, $ch;
122
+ $$did{$ch} = 1;
123
+ # continue with next character if there is only one possibility
124
+ @{$$next{$ch}} == 1 and $ch = $$next{$ch}[0], next;
125
+ # otherwise, test all possibilities
126
+ my $n = $#$order;
127
+ foreach (@{$$next{$ch}}) {
128
+ my %did = %$did; # make a copy of the used-character lookup
129
+ return 1 if OrderCipherDigits($_, $next, $order, \%did);
130
+ $#$order = $n; # restore order and try next possibility
131
+ }
132
+ last;
133
+ }
134
+ return 0; # failure
135
+ }
136
+
137
+ #------------------------------------------------------------------------------
138
+ # Decipher and parse LIGOGPSINFO record (starting with "####")
139
+ # Inputs: 0) ExifTool ref, 1) enciphered string, 2) tag table ref
140
+ # 3) true if GPS coordinates don't need de-fuzzing
141
+ # Returns: true if this looked like an enciphered string
142
+ # Notes: handles contained tags, but may defer handling until full cipher is known
143
+ sub DecipherLigoGPS($$$;$)
144
+ {
145
+ my ($et, $str, $tagTbl, $noFuzz) = @_;
146
+
147
+ # (enciphered characters must be in the range 0x30-0x5f ('0' - '_'))
148
+ $str =~ m[^####.{4}([0-_])[0-_]{3}/[0-_]{2}/[0-_]{2} ..([0-_])..([0-_]).([0-_]) ]s or return undef;
149
+ return undef unless $2 eq $3; # (colons in time string must be the same)
150
+
151
+ my $cipherInfo = $$et{LigoCipher};
152
+ unless ($cipherInfo) {
153
+ $cipherInfo = $$et{LigoCipher} = { cache => [ ], 'next' => { } };
154
+ $et->AddCleanup(\&CleanupCipher);
155
+ };
156
+ my $decipher = $$cipherInfo{decipher};
157
+ my $cache = $$cipherInfo{cache};
158
+
159
+ # determine the cipher code table based on the advancing 1's digit of seconds
160
+ unless ($decipher) {
161
+ push @$cache, $str; # cache records until we can decipher them
162
+ my $next = $$cipherInfo{next};
163
+ my ($millennium, $colon, $ch2) = ($1, $2, $4);
164
+ # determine the cipher lookup table
165
+ # (only characters in range 0x30-0x5f are encrypted)
166
+ my $ch1 = $$cipherInfo{ch1};
167
+ $$cipherInfo{ch1} = $ch2;
168
+ return 1 if not defined $ch1 or $ch1 eq $ch2; # ignore duplicate sequential digits
169
+ if ($$next{$ch1}) {
170
+ return 1 if grep /\Q$ch2\E/, @{$$next{$ch1}}; # don't add twice
171
+ push @{$$next{$ch1}}, $ch2;
172
+ } else {
173
+ $$next{$ch1} = [ $ch2 ];
174
+ }
175
+ # must wait until the lookup contains all 10 digits
176
+ scalar(keys %$next) < 10 and return 1;
177
+ # protect against trying to decipher bad data
178
+ scalar(keys %$next) > 10 and $$cipherInfo{'next'} = { }, return 1;
179
+ my (@order, $two);
180
+ return 1 unless OrderCipherDigits($ch1, $next, \@order);
181
+ # get index of enciphered "2" in ordered array
182
+ $order[$_] eq $millennium and $two = $_, last foreach 0..9;
183
+ defined $two or $et->Warn('Problem deciphering LIGOGPSINFO'), return 1;
184
+ delete $$cipherInfo{'next'}; # all done with 'next' lookup
185
+ my %decipher = ( $colon => ':' ); # (':' is the time separator)
186
+ foreach (0..9) {
187
+ my $ch = $order[($_ + $two - 2 + 10) % 10];
188
+ $decipher{$ch} = chr($_ + 0x30);
189
+ }
190
+ # may also know the lat/lon quadrant from the signs of the coordinates
191
+ if ($str =~ / ([0-_])$colon(-?).*? ([0-_])$colon(-?)/) {
192
+ @decipher{$1,$3} = ($2 ? 'S' : 'N', $4 ? 'W' : 'E');
193
+ unless ($2 or $4) {
194
+ my ($ns, $ew) = ($1, $3);
195
+ if ($$et{OPTIONS}{GPSQuadrant} and $$et{OPTIONS}{GPSQuadrant} =~ /^([NS])([EW])$/i) {
196
+ @decipher{$ns,$ew} = (uc($1), uc($2));
197
+ } else {
198
+ $et->Warn('May need to set API GPSQuadrant option (eg. "NW")');
199
+ }
200
+ }
201
+ }
202
+ # fill in unknown entries with '?' (only chars 0x30-0x5f are enciphered)
203
+ defined $decipher{$_} or $decipher{$_} = '?' foreach map(chr, 0x30..0x5f);
204
+ $decipher = $$cipherInfo{decipher} = \%decipher;
205
+ $str = shift @$cache; # start deciphering at oldest cache entry
206
+ }
207
+
208
+ # apply reverse cipher and extract GPS information
209
+ do {
210
+ my $pre = substr($str, 4, 4); # save second 4 bytes of header
211
+ ($str = substr($str,8)) =~ s/\0+$//; # remove 8-byte header and null padding
212
+ $str =~ s/([0-_])/$$decipher{$1}/g; # decipher
213
+ if ($$et{OPTIONS}{Verbose} > 1) {
214
+ $et->VPrint(1, "$$et{INDENT}\(Deciphered: ".unpack('H8',$pre)." $str)\n");
215
+ }
216
+ # add back leading 4 bytes (int16u counter plus 2 unknown bytes), and parse
217
+ ParseLigoGPS($et, "$pre$str", $tagTbl, $noFuzz);
218
+ } while $str = shift @$cache;
219
+
220
+ return 1;
221
+ }
222
+
223
+ #------------------------------------------------------------------------------
224
+ # Parse decrypted/deciphered (but not defuzzed) LIGOGPSINFO record
225
+ # (record starts with 4-byte int32u counter followed by date/time, etc)
226
+ # Inputs: 0) ExifTool ref, 1) GPS string, 2) tag table ref, 3) not fuzzed
227
+ # Returns: nothing
228
+ sub ParseLigoGPS($$$;$)
229
+ {
230
+ my ($et, $str, $tagTbl, $noFuzz) = @_;
231
+
232
+ # example string input
233
+ # "....2022/09/19 12:45:24 N:31.285065 W:124.759483 46.93 km/h x:-0.000 y:-0.000 z:-0.000"
234
+ unless ($str=~ /^.{4}(\S+ \S+)\s+([NS?]):(-?)([.\d]+)\s+([EW?]):(-?)([\.\d]+)\s+([.\d]+)/s) {
235
+ $et->Warn('LIGOGPSINFO format error');
236
+ return;
237
+ }
238
+ my ($time,$latRef,$latNeg,$lat,$lonRef,$lonNeg,$lon,$spd) = ($1,$2,$3,$4,$5,$6,$7,$8);
239
+ my %gpsScl = ( 1 => 1.524855137, 2 => 1.456027985, 3 => 1.15368 );
240
+ my $spdScl = $noFuzz ? $knotsToKph : 1.85407333;
241
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
242
+ $time =~ tr(/)(:);
243
+ # convert from DDMM.MMMMMM to DD.DDDDDD if necessary
244
+ # (speed wasn't scaled in my 1 sample with this format)
245
+ $lat =~ /^\d{3}/ and Image::ExifTool::QuickTime::ConvertLatLon($lat,$lon), $spdScl = 1;
246
+ unless ($noFuzz) { # unfuzz the coordinates if necessary
247
+ my $scl = $$et{OPTIONS}{LigoGPSScale} || $$et{LigoGPSScale} || 1;
248
+ $scl = $gpsScl{$scl} if $gpsScl{$scl};
249
+ ($lat, $lon) = UnfuzzLigoGPS($lat, $lon, $scl);
250
+ }
251
+ # a final sanity check
252
+ ($lat > 90 or $lon > 180) and $et->Warn('LIGOGPSINFO coordinates out of range'), return;
253
+ $$et{SET_GROUP1} = 'LIGO';
254
+ $et->HandleTag($tagTbl, 'GPSDateTime', $time);
255
+ # (ignore N/S/E/W if coordinate is signed)
256
+ $et->HandleTag($tagTbl, 'GPSLatitude', $lat * (($latNeg or $latRef eq 'S') ? -1 : 1));
257
+ $et->HandleTag($tagTbl, 'GPSLongitude', $lon * (($lonNeg or $lonRef eq 'W') ? -1 : 1));
258
+ $et->HandleTag($tagTbl, 'GPSSpeed', $spd * $spdScl);
259
+ $et->HandleTag($tagTbl, 'GPSTrack', $1) if $str =~ /\bA:(\S+)/;
260
+ $et->HandleTag($tagTbl, 'GPSAltitude', $1) if $str =~ /\bH:(\S+)/;
261
+ $et->HandleTag($tagTbl, 'MagneticVariation', $1) if $str =~ /\bM:(\S+)/;
262
+ # (have a sample where tab is used to separate acc components)
263
+ $et->HandleTag($tagTbl, 'Accelerometer',"$1 $2 $3") if $str =~ /x:(\S+)\sy:(\S+)\sz:(\S+)/;
264
+ delete $$et{SET_GROUP1};
265
+ }
266
+
267
+ #------------------------------------------------------------------------------
268
+ # Process LIGOGPSINFO data (non-JSON format)
269
+ # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
270
+ # 3) 1=LIGOGPS lat/lon/spd weren't fuzzed
271
+ # Returns: 1 on success
272
+ # Notes: The directory data should start with the string "LIGOGPSINFO\0"
273
+ sub ProcessLigoGPS($$$;$)
274
+ {
275
+ my ($et, $dirInfo, $tagTbl, $noFuzz) = @_;
276
+ my $dataPt = $$dirInfo{DataPt};
277
+ my $pos = ($$dirInfo{DirStart} || 0) + 0x14;
278
+ return undef if $pos > length $$dataPt;
279
+ my $cipherInfo = $$et{LigoCipher};
280
+ my $dirName = $$dirInfo{DirName} || 'LigoGPS';
281
+ push @{$$et{PATH}}, $dirName unless $$dirInfo{DirID};
282
+ # not fuzzed if header =~ /LIGOGPSINFO\0\0\0\0[\x01\x14]/ (\x01=BlueSkySeaDV688)
283
+ $noFuzz = 1 if substr($$dataPt, $pos-8, 4) =~ /^\0\0\0[\x01\x14]/;
284
+ $et->VerboseDir($dirName);
285
+ for (; $pos + 0x84 <= length($$dataPt); $pos+=0x84) {
286
+ my $dat = substr($$dataPt, $pos, 0x84);
287
+ $dat =~ /^####/ or next; # (have seen blank records filled with zeros, so keep trying)
288
+ # decipher if we already know the encryption
289
+ $cipherInfo and $$cipherInfo{decipher} and DecipherLigoGPS($et, $dat, $tagTbl, $noFuzz) and next;
290
+ my $str = DecryptLigoGPS($dat);
291
+ defined $str or DecipherLigoGPS($et, $dat, $tagTbl, $noFuzz), next; # try to decipher
292
+ $et->VPrint(1, "$$et{INDENT}\(Decrypted: ",unpack('V',$str),' ',substr($str,4),")\n") if $$et{OPTIONS}{Verbose} > 1;
293
+ ParseLigoGPS($et, $str, $tagTbl, $noFuzz);
294
+ }
295
+ pop @{$$et{PATH}} unless $$dirInfo{DirID};
296
+ delete $$et{DOC_NUM};
297
+ return 1;
298
+ }
299
+
300
+ #------------------------------------------------------------------------------
301
+ # Process LIGOGPSINFO JSON-format GPS (Yada RoadCam Pro 4K BT58189)
302
+ # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
303
+ # Returns: 1 on success
304
+ # Sample data (chained 512-byte records starting like this):
305
+ # 0000: 4c 49 47 4f 47 50 53 49 4e 46 4f 20 7b 22 48 6f [LIGOGPSINFO {"Ho]
306
+ # 0010: 75 72 22 3a 20 22 32 33 22 2c 20 22 4d 69 6e 75 [ur": "23", "Minu]
307
+ # 0020: 74 65 22 3a 20 22 31 30 22 2c 20 22 53 65 63 6f [te": "10", "Seco]
308
+ # 0030: 6e 64 22 3a 20 22 32 32 22 2c 20 22 59 65 61 72 [nd": "22", "Year]
309
+ # 0040: 22 3a 20 22 32 30 32 33 22 2c 20 22 4d 6f 6e 74 [": "2023", "Mont]
310
+ # 0050: 68 22 3a 20 22 31 32 22 2c 20 22 44 61 79 22 3a [h": "12", "Day":]
311
+ # 0060: 20 22 32 38 22 2c 20 22 73 74 61 74 75 73 22 3a [ "28", "status":]
312
+ sub ProcessLigoJSON($$$)
313
+ {
314
+ my ($et, $dirInfo, $tagTbl) = @_;
315
+ my $dataPt = $$dirInfo{DataPt};
316
+ my $dirLen = $$dirInfo{DirLen};
317
+ require Image::ExifTool::Import;
318
+ $et->VerboseDir('LIGO_JSON', undef, length($$dataPt));
319
+ $$et{SET_GROUP1} = 'LIGO';
320
+ while ($$dataPt =~ /LIGOGPSINFO (\{.*?\})/g) {
321
+ my $json = $1;
322
+ my %dbase;
323
+ Image::ExifTool::Import::ReadJSON(\$json, \%dbase);
324
+ my $info = $dbase{'*'} or next;
325
+ # my sample contains the following JSON fields (in this order):
326
+ # Hour Minute Second Year Month Day (GPS UTC time)
327
+ # status NS EW Latitude Longitude Speed (speed in knots)
328
+ # GsensorX GsensorY GsensorZ (units? - only seen "000" for all)
329
+ # MHour MMinute MSecond MYear MMonth MDay (local dashcam clock time)
330
+ # OLatitude OLongitude (? same values as Latitude/Longitude)
331
+ next unless defined $$info{status} and $$info{status} eq 'A'; # only read if GPS is active
332
+ $$et{DOC_NUM} = ++$$et{DOC_COUNT};
333
+ my $num = 0;
334
+ defined $$info{$_} and ++$num foreach qw(Year Month Day Hour Minute Second);
335
+ if ($num == 6) {
336
+ # this is the GPS time in UTC
337
+ my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ',@$info{qw{Year Month Day Hour Minute Second}});
338
+ $et->HandleTag($tagTbl, GPSDateTime => $time);
339
+ }
340
+ if ($$info{Latitude} and $$info{Longitude}) {
341
+ my $lat = $$info{Latitude};
342
+ $lat = -$lat if $$info{NS} and $$info{NS} eq 'S';
343
+ my $lon = $$info{Longitude};
344
+ $lon = -$lon if $$info{EW} and $$info{EW} eq 'W';
345
+ $et->HandleTag($tagTbl, GPSLatitude => $lat);
346
+ $et->HandleTag($tagTbl, GPSLongitude => $lon);
347
+ }
348
+ $et->HandleTag($tagTbl, GPSSpeed => $$info{Speed} * $knotsToKph) if defined $$info{Speed};
349
+ if (defined $$info{GsensorX} and defined $$info{GsensorY} and defined $$info{GsensorZ}) {
350
+ # (don't know conversion factor for accel data, so leave it raw for now)
351
+ $et->HandleTag($tagTbl, Accelerometer => "$$info{GsensorX} $$info{GsensorY} $$info{GsensorZ}");
352
+ }
353
+ $num = 0;
354
+ defined $$info{$_} and ++$num foreach qw(MYear MMonth MDay MHour MMinute MSecond);
355
+ if ($num == 6) {
356
+ # this is the dashcam clock time (local time zone)
357
+ my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d',@$info{qw{MYear MMonth MDay MHour MMinute MSecond}});
358
+ $et->HandleTag($tagTbl, DateTimeOriginal => $time);
359
+ }
360
+ if (defined $$info{OLatitude} and defined $$info{OLongitude}) {
361
+ my $lat = $$info{OLatitude};
362
+ $lat = -$lat if $$info{NS} and $$info{NS} eq 'S';
363
+ my $lon = $$info{OLongitude};
364
+ $lon = -$lon if $$info{EW} and $$info{EW} eq 'W';
365
+ $et->HandleTag($tagTbl, GPSLatitude2 => $lat);
366
+ $et->HandleTag($tagTbl, GPSLongitude2 => $lon);
367
+ }
368
+ unless ($et->Options('ExtractEmbedded')) {
369
+ $et->Warn('Use the ExtractEmbedded option to extract all timed GPS',3);
370
+ last;
371
+ }
372
+ }
373
+ delete $$et{DOC_NUM};
374
+ delete $$et{SET_GROUP1};
375
+ return 1;
376
+ }
377
+
378
+ 1; #end
379
+
380
+
381
+ __END__
382
+
383
+ =head1 NAME
384
+
385
+ Image::ExifTool::LigoGPS - Read LIGOGPSINFO timed GPS records
386
+
387
+ =head1 SYNOPSIS
388
+
389
+ This module is loaded automatically by Image::ExifTool when required.
390
+
391
+ =head1 DESCRIPTION
392
+
393
+ This module decrypts, deciphers and decodes timed GPS metadata from
394
+ LIGOGPSINFO records found in various locations of MP4 and M2TS videos from a
395
+ variety of dashcam makes and models.
396
+
397
+ =head1 AUTHOR
398
+
399
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
400
+
401
+ This library is free software; you can redistribute it and/or modify it
402
+ under the same terms as Perl itself.
403
+
404
+ =head1 SEE ALSO
405
+
406
+ L<Image::ExifTool::TagNames/QuickTime Stream Tags>,
407
+ L<Image::ExifTool(3pm)|Image::ExifTool>
408
+
409
+ =cut
@@ -192,7 +192,7 @@ from Lytro Light Field Picture (LFP) files.
192
192
 
193
193
  =head1 AUTHOR
194
194
 
195
- Copyright 2003-2024, Phil Harvey (philharvey66 at gmail.com)
195
+ Copyright 2003-2025, Phil Harvey (philharvey66 at gmail.com)
196
196
 
197
197
  This library is free software; you can redistribute it and/or modify it
198
198
  under the same terms as Perl itself.