0.7.12.8
10
CHANGELOG.md
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
All notable changes to this project will be documented in this file. Older changes are summarized on individual commits.
|
||||
|
||||
## [0.7.13]
|
||||
- Extensive rewrite to icon generation
|
||||
## [0.7.13.0]
|
||||
- Rewrites to diskutil code
|
||||
- Rewrites to mdutil code
|
||||
- Restructure paths
|
||||
- Remove bundled Imagemagick
|
||||
- Fixed a sort order bug in rtc.php
|
||||
20
README.md
@@ -1,10 +1,10 @@
|
||||
<img align="left" src="https://www.profiteroles.org/assets/yuba.png" style="float: left; margin-right: 30px;" width="120">
|
||||
<img align='left' src='/git/p/Yuba/raw/master/icon.iconset/icon_512x512.png' width='128'>
|
||||
|
||||
# Yuba
|
||||
|
||||
**Yuba** generates web-browsable catalogues from locally attached HFS+ filesystems. Its client application gathers forensic-quality data about a locally attached disk, properly interpreting bundles, reading Spotlight data, Finder flags, labels, and other contextual information. It can generate hashes, thumbnails, and gather 3rd party metadata with exiftool and mediainfo. Yuba's SQLite catalogues are comprehensive, lightweight, optimized for massive (1 million+) trees, and reflect incremental changes to contents and metadata. A server-side PHP script is provided, which allows familiar, Finder-style browsing of a catalogue.
|
||||
**Yuba** generates web-browsable catalogues from locally attached HFS+ filesystems. Its client application gathers forensic-quality data about a volume, properly interpreting bundles, reading Spotlight data, Finder flags, labels, and other contextual information. It can generate hashes, thumbnails, and gather 3rd party metadata with exiftool and mediainfo. Yuba's SQLite catalogues are comprehensive, lightweight, optimized for massive (1 million+) trees, and reflect incremental changes to contents and metadata. A server-side PHP script is provided, which allows familiar, Finder-style browsing of a catalogue.
|
||||
|
||||
* **⇩ [Download Latest Version](https://www.profiteroles.org/git/profiteroles/Yuba/raw/master/Yuba.app.zip)**
|
||||
####[⇩ Download Yuba 0.7.13](https://www.profiteroles.org/git/p/Yuba/raw/master/Yuba.app.zip) ([Changelog](CHANGELOG.md))
|
||||
|
||||
## Features
|
||||
|
||||
@@ -17,21 +17,17 @@
|
||||
|
||||
## Screenshots
|
||||
|
||||
<img src="https://www.profiteroles.org/assets/yuba_progress.png" width="600">
|
||||
<img src="https://www.profiteroles.org/assets/yuba_browser_1.png" width="1100">
|
||||
<img src="https://www.profiteroles.org/assets/yuba_browser_2.png" width="1100">
|
||||
<img src='/git/p/Yuba/raw/master/screenshot_1.png' width='977'>
|
||||
<img src='/git/p/Yuba/raw/master/screenshot_2.png' width='1779'>
|
||||
<img src='/git/p/Yuba/raw/master/screenshot_2.png' width='1779'>
|
||||
|
||||
## Notes
|
||||
|
||||
Running Yuba requires disabling Gatekeeper by running `sudo spctl --master-disable` in the Terminal.
|
||||
|
||||
## Changelog
|
||||
|
||||
https://www.profiteroles.org/git/profiteroles/Yuba/src/master/CHANGELOG.md
|
||||
Running Yuba may require disabling Gatekeeper by running `sudo spctl --master-disable` in the Terminal.
|
||||
|
||||
## Building from source
|
||||
|
||||
Building Yuba requires Platypus and Pashua
|
||||
|
||||
* https://github.com/sveinbjornt/Platypus
|
||||
* https://github.com/BlueM/Pashua
|
||||
* https://github.com/BlueM/Pashua
|
||||
|
||||
BIN
utils/IconTester.app/Contents/Resources/bin/ffmpeg → Tester.zip
Executable file → Normal file
68
Tester/IconTester.platypus
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AcceptsFiles</key>
|
||||
<true/>
|
||||
<key>AcceptsText</key>
|
||||
<false/>
|
||||
<key>Authentication</key>
|
||||
<false/>
|
||||
<key>Author</key>
|
||||
<string>profiteroles</string>
|
||||
<key>BundledFiles</key>
|
||||
<array>
|
||||
<string>/Volumes/Code/Yuba/bin</string>
|
||||
</array>
|
||||
<key>Creator</key>
|
||||
<string>Platypus-5.3</string>
|
||||
<key>DeclareService</key>
|
||||
<false/>
|
||||
<key>DevelopmentVersion</key>
|
||||
<false/>
|
||||
<key>Droppable</key>
|
||||
<true/>
|
||||
<key>IconPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/Tester/icon.icns</string>
|
||||
<key>Identifier</key>
|
||||
<string>org.profiteroles.IconTester</string>
|
||||
<key>InterfaceType</key>
|
||||
<string>Text Window</string>
|
||||
<key>InterpreterPath</key>
|
||||
<string>/usr/bin/php</string>
|
||||
<key>Name</key>
|
||||
<string>IconTester</string>
|
||||
<key>NibPath</key>
|
||||
<string>/usr/local/share/platypus/MainMenu.nib</string>
|
||||
<key>OptimizeApplication</key>
|
||||
<true/>
|
||||
<key>Overwrite</key>
|
||||
<false/>
|
||||
<key>PromptForFileOnLaunch</key>
|
||||
<false/>
|
||||
<key>RemainRunning</key>
|
||||
<true/>
|
||||
<key>RunInBackground</key>
|
||||
<false/>
|
||||
<key>ScriptArgs</key>
|
||||
<array>
|
||||
<string>icon</string>
|
||||
</array>
|
||||
<key>ScriptPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/Tester/Tester.php</string>
|
||||
<key>TextBackground</key>
|
||||
<string>#ffffff</string>
|
||||
<key>TextFont</key>
|
||||
<string>Monaco</string>
|
||||
<key>TextForeground</key>
|
||||
<string>#000000</string>
|
||||
<key>TextSize</key>
|
||||
<real>13</real>
|
||||
<key>UniformTypes</key>
|
||||
<array>
|
||||
<string>public.item</string>
|
||||
</array>
|
||||
<key>Version</key>
|
||||
<string>0.0.0.1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
12
utils/ThumbTester.app/Contents/Resources/script → Tester/Tester.php
Executable file → Normal file
@@ -1,13 +1,11 @@
|
||||
<?
|
||||
|
||||
// Yuba Preview Tester 0.1.4
|
||||
// Yuba Preview Tester 0.1.5
|
||||
|
||||
//print_r($argv); die;
|
||||
//print_r($argv);
|
||||
|
||||
$mode = $argv[1];
|
||||
|
||||
if (empty($argv[2])) { echo "Nothing dragged"; die; }
|
||||
|
||||
// Bundled tools
|
||||
$bin_gfi = __DIR__."/bin/GetFileInfo";
|
||||
$bin_mediainfo = __DIR__."/bin/mediainfo";
|
||||
@@ -17,7 +15,6 @@ $bin_qlthumb = __DIR__."/bin/ql-thumbnail";
|
||||
$bin_qlicon = __DIR__."/bin/ql-icon";
|
||||
$bin_qltool = __DIR__."/bin/qltool";
|
||||
$bin_sox = __DIR__."/bin/sox";
|
||||
$bin_pngcrush = __DIR__."/bin/pngcrush";
|
||||
$bin_pngquant = __DIR__."/bin/pngquant";
|
||||
$bin_parallel = __DIR__."/bin/parallel";
|
||||
|
||||
@@ -32,6 +29,11 @@ $bin_vips = "/opt/local/bin/vipsthumbnail";
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (empty(shell_exec("which ".$bin_convert))) { echo "Binary not found: ".$bin_convert."\n"; }
|
||||
if (empty(shell_exec("which ".$bin_vips))) { echo "Binary not found: ".$bin_vips."\n"; }
|
||||
|
||||
if (empty($argv[2])) { echo "Nothing dragged"; die; }
|
||||
|
||||
$p['icon_size'] = 512;
|
||||
$p['thumb_size'] = 1024;
|
||||
|
||||
68
Tester/ThumbTester.platypus
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AcceptsFiles</key>
|
||||
<true/>
|
||||
<key>AcceptsText</key>
|
||||
<false/>
|
||||
<key>Authentication</key>
|
||||
<false/>
|
||||
<key>Author</key>
|
||||
<string>profiteroles</string>
|
||||
<key>BundledFiles</key>
|
||||
<array>
|
||||
<string>/Volumes/Code/Yuba/bin</string>
|
||||
</array>
|
||||
<key>Creator</key>
|
||||
<string>Platypus-5.3</string>
|
||||
<key>DeclareService</key>
|
||||
<false/>
|
||||
<key>DevelopmentVersion</key>
|
||||
<false/>
|
||||
<key>Droppable</key>
|
||||
<true/>
|
||||
<key>IconPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/Tester/icon.icns</string>
|
||||
<key>Identifier</key>
|
||||
<string>org.profiteroles.ThumbTester</string>
|
||||
<key>InterfaceType</key>
|
||||
<string>Text Window</string>
|
||||
<key>InterpreterPath</key>
|
||||
<string>/usr/bin/php</string>
|
||||
<key>Name</key>
|
||||
<string>ThumbTester</string>
|
||||
<key>NibPath</key>
|
||||
<string>/usr/local/share/platypus/MainMenu.nib</string>
|
||||
<key>OptimizeApplication</key>
|
||||
<true/>
|
||||
<key>Overwrite</key>
|
||||
<false/>
|
||||
<key>PromptForFileOnLaunch</key>
|
||||
<false/>
|
||||
<key>RemainRunning</key>
|
||||
<true/>
|
||||
<key>RunInBackground</key>
|
||||
<false/>
|
||||
<key>ScriptArgs</key>
|
||||
<array>
|
||||
<string>thumb</string>
|
||||
</array>
|
||||
<key>ScriptPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/Tester/Tester.php</string>
|
||||
<key>TextBackground</key>
|
||||
<string>#ffffff</string>
|
||||
<key>TextFont</key>
|
||||
<string>Monaco</string>
|
||||
<key>TextForeground</key>
|
||||
<string>#000000</string>
|
||||
<key>TextSize</key>
|
||||
<real>13</real>
|
||||
<key>UniformTypes</key>
|
||||
<array>
|
||||
<string>public.item</string>
|
||||
</array>
|
||||
<key>Version</key>
|
||||
<string>0.0.0.1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
Tester/icon.icns
Normal file
BIN
Tester/icon.iconset/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Tester/icon.iconset/icon_128x128@2x.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
Tester/icon.iconset/icon_16x16.png
Normal file
|
After Width: | Height: | Size: 823 B |
BIN
Tester/icon.iconset/icon_16x16@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Tester/icon.iconset/icon_256x256.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
Tester/icon.iconset/icon_256x256@2x.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
Tester/icon.iconset/icon_32x32.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Tester/icon.iconset/icon_32x32@2x.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
Tester/icon.iconset/icon_512x512.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
Tester/icon.iconset/icon_512x512@2x.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
Yuba.app.zip
92
Yuba.php
@@ -3,7 +3,7 @@
|
||||
// Yuba
|
||||
// //
|
||||
//////////////////////////////////////////
|
||||
$version = file_get_contents(__DIR__."/version.txt");
|
||||
$version = file_get_contents(__DIR__."/current_version.txt");
|
||||
|
||||
ini_set('memory_limit', '10240M');
|
||||
date_default_timezone_set("America/Los_Angeles");
|
||||
@@ -46,11 +46,11 @@ if (@$argv[1] == "Preferences...") {
|
||||
|
||||
if (@$argv[1] == "Check for Updates...") {
|
||||
|
||||
$curr_version = file_get_contents("https://www.profiteroles.org/git/profiteroles/Yuba/raw/branch/master/version.txt");
|
||||
$curr_version = file_get_contents("https://www.profiteroles.org/git/p/Yuba/raw/master/current_version.txt");
|
||||
if ($curr_version > $version) {
|
||||
if(askMulti("Yuba ".$curr_version." is available (you have ".$version.")", array("Cancel","Download")) == 1) {
|
||||
exec("open http://git.profiteroles.org/profiteroles/Yuba");
|
||||
die;
|
||||
exec("open https://www.profiteroles.org/git/p/Yuba/");
|
||||
echo "QUITAPP\n";
|
||||
}
|
||||
} else {
|
||||
alert($version." is the latest version","Up-to-date");
|
||||
@@ -91,6 +91,14 @@ ini_set("display_errors", TRUE);
|
||||
ini_set("log_errors", TRUE);
|
||||
ini_set("error_log", $error_log_file);
|
||||
|
||||
// Bundled QlGenerators
|
||||
$generators = @glob(__DIR__."/../Library/Quicklook/*.qlgenerator");
|
||||
if (!empty($generators)) {
|
||||
foreach ($generators as $generator) {
|
||||
$p['bundled_generators'][] = basename($generator);
|
||||
}
|
||||
}
|
||||
|
||||
// Banner
|
||||
//////////////////////////////////////////
|
||||
|
||||
@@ -99,11 +107,13 @@ if (!is_dir($zpath) | !is_dir($bdest)) { echo "Filepath error"; die; }
|
||||
$banner = "Yuba: ".$zpath." -> ".$bpath;
|
||||
echo msg($banner."\n".str_repeat("-", strlen($banner)));
|
||||
|
||||
// Disk info
|
||||
// System Info
|
||||
//////////////////////////////////////////
|
||||
|
||||
echo msg("Gathering system info...");
|
||||
|
||||
// Disks
|
||||
|
||||
if (substr($zpath, 0, 9) != "/Volumes/") {
|
||||
$zbase = "/";
|
||||
} else {
|
||||
@@ -115,16 +125,14 @@ $host = gethostname();
|
||||
$disks = shell_exec("diskutil list -plist 2>&1");
|
||||
$diskutil = shell_exec("diskutil info -plist ".$zbase." 2>&1");
|
||||
$diskutil_parsed = $parser->parseString(utf8_for_xml($diskutil));
|
||||
//print_r($diskutil_parsed);
|
||||
foreach ($diskutil_parsed['SMARTDeviceSpecificKeysMayVaryNotGuaranteed'] as $key => $value) {
|
||||
$diskutil_parsed[$key] = $value;
|
||||
}
|
||||
unset($diskutil_parsed['SMARTDeviceSpecificKeysMayVaryNotGuaranteed']);
|
||||
$vdisks = shell_exec("hdiutil info -plist 2>&1");
|
||||
$vdisks_parsed = $parser->parseString(utf8_for_xml($vdisks));
|
||||
//print_r($vdisks_parsed);
|
||||
$df = shell_exec("df 2>&1");
|
||||
|
||||
// old method, new method is to parse plist
|
||||
//$df_volume = trim(shell_exec("df ".escapeshellarg($zpath)." | tail -n 1 | rev | cut -d' ' -f1 | rev"));
|
||||
//$df_device = trim(shell_exec("df ".escapeshellarg($zpath)." | tail -n 1 | cut -d' ' -f1"));
|
||||
|
||||
$df_volume = $diskutil_parsed['MountPoint'];
|
||||
$df_device = "/dev/".$diskutil_parsed['ParentWholeDisk'];
|
||||
|
||||
@@ -134,38 +142,10 @@ if (strpos($mdutil,"disabled")) {
|
||||
$p['spotlight'] = false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// rewrite below to use diskutil info -plist
|
||||
//
|
||||
//
|
||||
//
|
||||
$olddiskutil = shell_exec("diskutil info ".$zbase." 2>&1");
|
||||
$getdetail = array( "Volume Name",
|
||||
"Protocol",
|
||||
"Volume UUID",
|
||||
"Device Location",
|
||||
"Volume Total Space",
|
||||
"Volume Available Space",
|
||||
"Level Type"
|
||||
);
|
||||
foreach ($getdetail as $detail) {
|
||||
preg_match("/(".$detail.":)(.*)(\n)/",$olddiskutil,$matches);
|
||||
if (isset($matches[2])) {
|
||||
if (substr($detail, -5, 5) == "Space") {
|
||||
$pieces = explode(" ", trim($matches[2]));
|
||||
$summary = $pieces[0]." ".$pieces[1];
|
||||
$details[$detail] = $summary;
|
||||
} else {
|
||||
$details[$detail] = trim($matches[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dstring = serialize($details);
|
||||
if ($zpath == "/") {
|
||||
$type = "Startup disk";
|
||||
} elseif (strtolower($zpath) == strtolower("/Volumes/".$details["Volume Name"])) {
|
||||
if ($details["Protocol"] == "Disk Image") {
|
||||
} elseif (strtolower($zpath) == strtolower("/Volumes/".$diskutil_parsed["VolumeName"])) {
|
||||
if ($diskutil_parsed["BusProtocol"] == "Disk Image") {
|
||||
$type = "Disk image";
|
||||
} else {
|
||||
$type = "External disk";
|
||||
@@ -173,11 +153,6 @@ if ($zpath == "/") {
|
||||
} else {
|
||||
$type = "Folder";
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if ($type == "Disk image") {
|
||||
$hdiutil = shell_exec("hdiutil imageinfo -plist ".$df_device." 2>&1");
|
||||
@@ -191,15 +166,30 @@ if ($type == "Disk image") {
|
||||
$image_file = false;
|
||||
}
|
||||
|
||||
// System Profile
|
||||
|
||||
if ($p['profile']) {
|
||||
echo msg("system_profiler");
|
||||
$profile = shell_exec("system_profiler SPHardwareDataType SPStorageDataType SPThunderboltDataType SPUSBDataType 2>&1");
|
||||
} else {
|
||||
$profile = "disabled";
|
||||
}
|
||||
$qlmanage = shell_exec($bin_qlmanage." -m 2>&1");
|
||||
$sysvers = shell_exec("sw_vers 2>&1");
|
||||
|
||||
// QuickLook
|
||||
|
||||
foreach (explode("\n",shell_exec($bin_qlmanage." -m plugins 2>&1")) as $ql_line) {
|
||||
$ql_parts = @explode(" -> ",trim($ql_line));
|
||||
if (@$ql_parts[1]) {
|
||||
$qlmanage['plugins'][$ql_parts[0]] = $ql_parts[1];
|
||||
}
|
||||
}
|
||||
$qlmanage['server'] = trim(shell_exec($bin_qlmanage." -m server 2>&1"));
|
||||
$qlmanage['memory'] = trim(shell_exec($bin_qlmanage." -m memory 2>&1"));
|
||||
$qlmanage['burst'] = trim(shell_exec($bin_qlmanage." -m burst 2>&1"));
|
||||
$qlmanage['threads'] = trim(shell_exec($bin_qlmanage." -m threads 2>&1"));
|
||||
$qlmanage['other'] = trim(shell_exec($bin_qlmanage." -m other 2>&1"));
|
||||
|
||||
// Database
|
||||
//////////////////////////////////////////
|
||||
|
||||
@@ -230,7 +220,6 @@ $dbo->exec("CREATE TABLE _skim (
|
||||
nodescended INTEGER,
|
||||
ignored INTEGER,
|
||||
dupes INTEGER,
|
||||
details TEXT,
|
||||
qlmanage TEXT,
|
||||
sysvers TEXT,
|
||||
disks TEXT,
|
||||
@@ -292,7 +281,7 @@ $dbo->exec("CREATE TABLE files (
|
||||
contents_filename TEXT
|
||||
)");
|
||||
|
||||
$stmt = $dbo->prepare("INSERT INTO _skim VALUES (:version, :opts, :host, :uid, :zpath, :bpath, :type, :passed_file, :passed_dir, :passed_link, :passed_total, :nodescended, :ignored, :dupes, :details, :qlmanage, :sysvers, :disks, :diskutil, :vdisks, :hdiutil, :image_file, :df, :df_device, :df_volume, :mdutil, :profile, :status)");
|
||||
$stmt = $dbo->prepare("INSERT INTO _skim VALUES (:version, :opts, :host, :uid, :zpath, :bpath, :type, :passed_file, :passed_dir, :passed_link, :passed_total, :nodescended, :ignored, :dupes, :qlmanage, :sysvers, :disks, :diskutil, :vdisks, :hdiutil, :image_file, :df, :df_device, :df_volume, :mdutil, :profile, :status)");
|
||||
$stmt->BindValue(":version",$version);
|
||||
$stmt->BindValue(":opts",serialize($p));
|
||||
$stmt->BindValue(":host",$host);
|
||||
@@ -300,8 +289,7 @@ $stmt->BindValue(":uid",posix_getuid());
|
||||
$stmt->BindValue(":zpath",$zpath);
|
||||
$stmt->BindValue(":bpath",$bpath);
|
||||
$stmt->BindValue(":type",$type);
|
||||
$stmt->BindValue(":details",$dstring);
|
||||
$stmt->BindValue(":qlmanage",$qlmanage);
|
||||
$stmt->BindValue(":qlmanage",serialize($qlmanage));
|
||||
$stmt->BindValue(":sysvers",$sysvers);
|
||||
$stmt->BindValue(":disks",$disks);
|
||||
$stmt->BindValue(":diskutil",$diskutil);
|
||||
@@ -587,7 +575,7 @@ if ($p['thumbs']) {
|
||||
file_put_contents($batchfile,implode("\n", $line));
|
||||
echo ProgressBar::finish($wopt_clear);
|
||||
|
||||
echo ProgressBar::start($passed_file,"Running thumb batch (".stepString().")");
|
||||
echo ProgressBar::start($passed_file,"Running thumb batch (".stepString().")");
|
||||
if ($wopt_parallel) {
|
||||
passthru($bin_parallel." < ".$batchfile);
|
||||
} else {
|
||||
|
||||
72
Yuba.platypus
Normal file
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>AcceptsFiles</key>
|
||||
<true/>
|
||||
<key>AcceptsText</key>
|
||||
<false/>
|
||||
<key>Authentication</key>
|
||||
<false/>
|
||||
<key>Author</key>
|
||||
<string>profiteroles</string>
|
||||
<key>BundledFiles</key>
|
||||
<array>
|
||||
<string>/Volumes/Code/Yuba/master/current_version.txt</string>
|
||||
<string>/Volumes/Code/Yuba/master/filetypes.php</string>
|
||||
<string>/Volumes/Code/Yuba/master/functions.php</string>
|
||||
<string>/Volumes/Code/Yuba/master/hr.png</string>
|
||||
<string>/Volumes/Code/Yuba/master/prefs.php</string>
|
||||
<string>/Volumes/Code/Yuba/master/helper.php</string>
|
||||
<string>/Volumes/Code/Yuba/master/Yuba.php</string>
|
||||
<string>/Volumes/Code/Yuba/master/YubaPrefs.php</string>
|
||||
<string>/Volumes/Code/Yuba/bin</string>
|
||||
</array>
|
||||
<key>Creator</key>
|
||||
<string>Platypus-5.3</string>
|
||||
<key>DeclareService</key>
|
||||
<false/>
|
||||
<key>DevelopmentVersion</key>
|
||||
<false/>
|
||||
<key>Droppable</key>
|
||||
<true/>
|
||||
<key>IconPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/icon.icns</string>
|
||||
<key>Identifier</key>
|
||||
<string>org.profiteroles.Yuba</string>
|
||||
<key>InterfaceType</key>
|
||||
<string>Progress Bar</string>
|
||||
<key>InterpreterPath</key>
|
||||
<string>/usr/bin/php</string>
|
||||
<key>Name</key>
|
||||
<string>Yuba</string>
|
||||
<key>NibPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/MainMenu.nib</string>
|
||||
<key>OptimizeApplication</key>
|
||||
<true/>
|
||||
<key>Overwrite</key>
|
||||
<false/>
|
||||
<key>PromptForFileOnLaunch</key>
|
||||
<false/>
|
||||
<key>RemainRunning</key>
|
||||
<true/>
|
||||
<key>RunInBackground</key>
|
||||
<false/>
|
||||
<key>ScriptPath</key>
|
||||
<string>/Volumes/Code/Yuba/master/script</string>
|
||||
<key>TextBackground</key>
|
||||
<string>#ffffff</string>
|
||||
<key>TextFont</key>
|
||||
<string>SFMono-Regular</string>
|
||||
<key>TextForeground</key>
|
||||
<string>#000000</string>
|
||||
<key>TextSize</key>
|
||||
<real>11</real>
|
||||
<key>UniformTypes</key>
|
||||
<array>
|
||||
<string>public.folder</string>
|
||||
</array>
|
||||
<key>Version</key>
|
||||
<string>0.0.0.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -198,7 +198,7 @@ $strings[] = array("qltool","qlmanage");
|
||||
|
||||
// Launch Pashua and parse results
|
||||
|
||||
$path = __DIR__."/Pashua.app/Contents/MacOS/Pashua";
|
||||
$path = __DIR__."/bin/Pashua.app/Contents/MacOS/Pashua";
|
||||
$raw = shell_exec("echo ".escapeshellarg(makeWindowString($p, $strings))." | ".escapeshellarg($path)." - ");
|
||||
$result = array();
|
||||
foreach (explode("\n", $raw) as $line) {
|
||||
|
||||
1
current_version.txt
Executable file
@@ -0,0 +1 @@
|
||||
0.7.12.8
|
||||
@@ -17,7 +17,7 @@ $bin_parallel = __DIR__."/bin/parallel";
|
||||
// System tools
|
||||
$bin_php = "php";
|
||||
$bin_qlmanage = "qlmanage";
|
||||
$bin_sips = "qlmanage";
|
||||
$bin_sips = "sips";
|
||||
|
||||
// External tools
|
||||
$bin_convert = "/opt/local/bin/convert";
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// //
|
||||
//////////////////////////////////////////
|
||||
|
||||
$prefs_file = "/Users/".get_current_user()."/Library/Preferences/yuba_prefs.php";
|
||||
$prefs_file = "/Users/".get_current_user()."/Library/Preferences/org.profiteroles.Yuba.php";
|
||||
$p = unserialize(file_get_contents($prefs_file));
|
||||
|
||||
require("functions.php");
|
||||
|
||||
BIN
icon.iconset/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
icon.iconset/icon_128x128@2x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
icon.iconset/icon_16x16.png
Normal file
|
After Width: | Height: | Size: 597 B |
BIN
icon.iconset/icon_16x16@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
icon.iconset/icon_256x256.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
icon.iconset/icon_256x256@2x.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
icon.iconset/icon_32x32.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
icon.iconset/icon_32x32@2x.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
icon.iconset/icon_512x512.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
icon.iconset/icon_512x512@2x.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
screenshot_1.png
Normal file
|
After Width: | Height: | Size: 289 KiB |
BIN
screenshot_2.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
screenshot_3.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
utils/IconTester.app/Contents/Resources/MainMenu.nib
generated
@@ -1,378 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: RandomAccess.pm
|
||||
#
|
||||
# Description: Buffer to support random access reading of sequential file
|
||||
#
|
||||
# Revisions: 02/11/2004 - P. Harvey Created
|
||||
# 02/20/2004 - P. Harvey Added flag to disable SeekTest in new()
|
||||
# 11/18/2004 - P. Harvey Fixed bug with seek relative to end of file
|
||||
# 01/02/2005 - P. Harvey Added DEBUG code
|
||||
# 01/09/2006 - P. Harvey Fixed bug in ReadLine() when using
|
||||
# multi-character EOL sequences
|
||||
# 02/20/2006 - P. Harvey Fixed bug where seek past end of file could
|
||||
# generate "substr outside string" warning
|
||||
# 06/10/2006 - P. Harvey Decreased $CHUNK_SIZE from 64k to 8k
|
||||
# 11/23/2006 - P. Harvey Limit reads to < 0x80000000 bytes
|
||||
# 11/26/2008 - P. Harvey Fixed bug in ReadLine when reading from a
|
||||
# scalar with a multi-character newline
|
||||
# 01/24/2009 - PH Protect against reading too much at once
|
||||
#
|
||||
# Notes: Calls the normal file i/o routines unless SeekTest() fails, in
|
||||
# which case the file is buffered in memory to allow random access.
|
||||
# SeekTest() is called automatically when the object is created
|
||||
# unless specified.
|
||||
#
|
||||
# May also be used for string i/o (just pass a scalar reference)
|
||||
#
|
||||
# Legal: Copyright (c) 2003-2018 Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package File::RandomAccess;
|
||||
|
||||
use strict;
|
||||
require 5.002;
|
||||
require Exporter;
|
||||
|
||||
use vars qw($VERSION @ISA @EXPORT_OK);
|
||||
$VERSION = '1.10';
|
||||
@ISA = qw(Exporter);
|
||||
|
||||
sub Read($$$);
|
||||
|
||||
# constants
|
||||
my $CHUNK_SIZE = 8192; # size of chunks to read from file (must be power of 2)
|
||||
my $SLURP_CHUNKS = 16; # read this many chunks at a time when slurping
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Create new RandomAccess object
|
||||
# Inputs: 0) reference to RandomAccess object or RandomAccess class name
|
||||
# 1) file reference or scalar reference
|
||||
# 2) flag set if file is already random access (disables automatic SeekTest)
|
||||
sub new($$;$)
|
||||
{
|
||||
my ($that, $filePt, $isRandom) = @_;
|
||||
my $class = ref($that) || $that;
|
||||
my $self;
|
||||
|
||||
if (ref $filePt eq 'SCALAR') {
|
||||
# string i/o
|
||||
$self = {
|
||||
BUFF_PT => $filePt,
|
||||
POS => 0,
|
||||
LEN => length($$filePt),
|
||||
TESTED => -1,
|
||||
};
|
||||
bless $self, $class;
|
||||
} else {
|
||||
# file i/o
|
||||
my $buff = '';
|
||||
$self = {
|
||||
FILE_PT => $filePt, # file pointer
|
||||
BUFF_PT => \$buff, # reference to file data
|
||||
POS => 0, # current position in file
|
||||
LEN => 0, # data length
|
||||
TESTED => 0, # 0=untested, 1=passed, -1=failed (requires buffering)
|
||||
};
|
||||
bless $self, $class;
|
||||
$self->SeekTest() unless $isRandom;
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Enable DEBUG code
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
sub Debug($)
|
||||
{
|
||||
my $self = shift;
|
||||
$self->{DEBUG} = { };
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Perform seek test and turn on buffering if necessary
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
# Returns: 1 if seek test passed (ie. no buffering required)
|
||||
# Notes: Must be done before any other i/o
|
||||
sub SeekTest($)
|
||||
{
|
||||
my $self = shift;
|
||||
unless ($self->{TESTED}) {
|
||||
my $fp = $self->{FILE_PT};
|
||||
if (seek($fp, 1, 1) and seek($fp, -1, 1)) {
|
||||
$self->{TESTED} = 1; # test passed
|
||||
} else {
|
||||
$self->{TESTED} = -1; # test failed (requires buffering)
|
||||
}
|
||||
}
|
||||
return $self->{TESTED} == 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Get current position in file
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
# Returns: current position in file
|
||||
sub Tell($)
|
||||
{
|
||||
my $self = shift;
|
||||
my $rtnVal;
|
||||
if ($self->{TESTED} < 0) {
|
||||
$rtnVal = $self->{POS};
|
||||
} else {
|
||||
$rtnVal = tell($self->{FILE_PT});
|
||||
}
|
||||
return $rtnVal;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Seek to position in file
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
# 1) position, 2) whence (0 or undef=from start, 1=from cur pos, 2=from end)
|
||||
# Returns: 1 on success
|
||||
# Notes: When buffered, this doesn't quite behave like seek() since it will return
|
||||
# success even if you seek outside the limits of the file. However if you
|
||||
# do this, you will get an error on your next Read().
|
||||
sub Seek($$;$)
|
||||
{
|
||||
my ($self, $num, $whence) = @_;
|
||||
$whence = 0 unless defined $whence;
|
||||
my $rtnVal;
|
||||
if ($self->{TESTED} < 0) {
|
||||
my $newPos;
|
||||
if ($whence == 0) {
|
||||
$newPos = $num; # from start of file
|
||||
} elsif ($whence == 1) {
|
||||
$newPos = $num + $self->{POS}; # relative to current position
|
||||
} else {
|
||||
$self->Slurp(); # read whole file into buffer
|
||||
$newPos = $num + $self->{LEN}; # relative to end of file
|
||||
}
|
||||
if ($newPos >= 0) {
|
||||
$self->{POS} = $newPos;
|
||||
$rtnVal = 1;
|
||||
}
|
||||
} else {
|
||||
$rtnVal = seek($self->{FILE_PT}, $num, $whence);
|
||||
}
|
||||
return $rtnVal;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Read from the file
|
||||
# Inputs: 0) reference to RandomAccess object, 1) buffer, 2) bytes to read
|
||||
# Returns: Number of bytes read
|
||||
sub Read($$$)
|
||||
{
|
||||
my $self = shift;
|
||||
my $len = $_[1];
|
||||
my $rtnVal;
|
||||
|
||||
# protect against reading too much at once
|
||||
# (also from dying with a "Negative length" error)
|
||||
if ($len & 0xf8000000) {
|
||||
return 0 if $len < 0;
|
||||
# read in smaller blocks because Windows attempts to pre-allocate
|
||||
# memory for the full size, which can lead to an out-of-memory error
|
||||
my $maxLen = 0x4000000; # (MUST be less than bitmask in "if" above)
|
||||
my $num = Read($self, $_[0], $maxLen);
|
||||
return $num if $num < $maxLen;
|
||||
for (;;) {
|
||||
$len -= $maxLen;
|
||||
last if $len <= 0;
|
||||
my $l = $len < $maxLen ? $len : $maxLen;
|
||||
my $buff;
|
||||
my $n = Read($self, $buff, $l);
|
||||
last unless $n;
|
||||
$_[0] .= $buff;
|
||||
$num += $n;
|
||||
last if $n < $l;
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
# read through our buffer if necessary
|
||||
if ($self->{TESTED} < 0) {
|
||||
my $buff;
|
||||
my $newPos = $self->{POS} + $len;
|
||||
# number of bytes to read from file
|
||||
my $num = $newPos - $self->{LEN};
|
||||
if ($num > 0 and $self->{FILE_PT}) {
|
||||
# read data from file in multiples of $CHUNK_SIZE
|
||||
$num = (($num - 1) | ($CHUNK_SIZE - 1)) + 1;
|
||||
$num = read($self->{FILE_PT}, $buff, $num);
|
||||
if ($num) {
|
||||
${$self->{BUFF_PT}} .= $buff;
|
||||
$self->{LEN} += $num;
|
||||
}
|
||||
}
|
||||
# number of bytes left in data buffer
|
||||
$num = $self->{LEN} - $self->{POS};
|
||||
if ($len <= $num) {
|
||||
$rtnVal = $len;
|
||||
} elsif ($num <= 0) {
|
||||
$_[0] = '';
|
||||
return 0;
|
||||
} else {
|
||||
$rtnVal = $num;
|
||||
}
|
||||
# return data from our buffer
|
||||
$_[0] = substr(${$self->{BUFF_PT}}, $self->{POS}, $rtnVal);
|
||||
$self->{POS} += $rtnVal;
|
||||
} else {
|
||||
# read directly from file
|
||||
$_[0] = '' unless defined $_[0];
|
||||
$rtnVal = read($self->{FILE_PT}, $_[0], $len) || 0;
|
||||
}
|
||||
if ($self->{DEBUG}) {
|
||||
my $pos = $self->Tell() - $rtnVal;
|
||||
unless ($self->{DEBUG}->{$pos} and $self->{DEBUG}->{$pos} > $rtnVal) {
|
||||
$self->{DEBUG}->{$pos} = $rtnVal;
|
||||
}
|
||||
}
|
||||
return $rtnVal;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Read a line from file (end of line is $/)
|
||||
# Inputs: 0) reference to RandomAccess object, 1) buffer
|
||||
# Returns: Number of bytes read
|
||||
sub ReadLine($$)
|
||||
{
|
||||
my $self = shift;
|
||||
my $rtnVal;
|
||||
my $fp = $self->{FILE_PT};
|
||||
|
||||
if ($self->{TESTED} < 0) {
|
||||
my ($num, $buff);
|
||||
my $pos = $self->{POS};
|
||||
if ($fp) {
|
||||
# make sure we have some data after the current position
|
||||
while ($self->{LEN} <= $pos) {
|
||||
$num = read($fp, $buff, $CHUNK_SIZE);
|
||||
return 0 unless $num;
|
||||
${$self->{BUFF_PT}} .= $buff;
|
||||
$self->{LEN} += $num;
|
||||
}
|
||||
# scan and read until we find the EOL (or hit EOF)
|
||||
for (;;) {
|
||||
$pos = index(${$self->{BUFF_PT}}, $/, $pos);
|
||||
if ($pos >= 0) {
|
||||
$pos += length($/);
|
||||
last;
|
||||
}
|
||||
$pos = $self->{LEN}; # have scanned to end of buffer
|
||||
$num = read($fp, $buff, $CHUNK_SIZE) or last;
|
||||
${$self->{BUFF_PT}} .= $buff;
|
||||
$self->{LEN} += $num;
|
||||
}
|
||||
} else {
|
||||
# string i/o
|
||||
$pos = index(${$self->{BUFF_PT}}, $/, $pos);
|
||||
if ($pos < 0) {
|
||||
$pos = $self->{LEN};
|
||||
$self->{POS} = $pos if $self->{POS} > $pos;
|
||||
} else {
|
||||
$pos += length($/);
|
||||
}
|
||||
}
|
||||
# read the line from our buffer
|
||||
$rtnVal = $pos - $self->{POS};
|
||||
$_[0] = substr(${$self->{BUFF_PT}}, $self->{POS}, $rtnVal);
|
||||
$self->{POS} = $pos;
|
||||
} else {
|
||||
$_[0] = <$fp>;
|
||||
if (defined $_[0]) {
|
||||
$rtnVal = length($_[0]);
|
||||
} else {
|
||||
$rtnVal = 0;
|
||||
}
|
||||
}
|
||||
if ($self->{DEBUG}) {
|
||||
my $pos = $self->Tell() - $rtnVal;
|
||||
unless ($self->{DEBUG}->{$pos} and $self->{DEBUG}->{$pos} > $rtnVal) {
|
||||
$self->{DEBUG}->{$pos} = $rtnVal;
|
||||
}
|
||||
}
|
||||
return $rtnVal;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Read whole file into buffer (without changing read pointer)
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
sub Slurp($)
|
||||
{
|
||||
my $self = shift;
|
||||
my $fp = $self->{FILE_PT} || return;
|
||||
# read whole file into buffer (in large chunks)
|
||||
my ($buff, $num);
|
||||
while (($num = read($fp, $buff, $CHUNK_SIZE * $SLURP_CHUNKS)) != 0) {
|
||||
${$self->{BUFF_PT}} .= $buff;
|
||||
$self->{LEN} += $num;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# set binary mode
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
sub BinMode($)
|
||||
{
|
||||
my $self = shift;
|
||||
binmode($self->{FILE_PT}) if $self->{FILE_PT};
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# close the file and free the buffer
|
||||
# Inputs: 0) reference to RandomAccess object
|
||||
sub Close($)
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if ($self->{DEBUG}) {
|
||||
local $_;
|
||||
if ($self->Seek(0,2)) {
|
||||
$self->{DEBUG}->{$self->Tell()} = 0; # set EOF marker
|
||||
my $last;
|
||||
my $tot = 0;
|
||||
my $bad = 0;
|
||||
foreach (sort { $a <=> $b } keys %{$self->{DEBUG}}) {
|
||||
my $pos = $_;
|
||||
my $len = $self->{DEBUG}->{$_};
|
||||
if (defined $last and $last < $pos) {
|
||||
my $bytes = $pos - $last;
|
||||
$tot += $bytes;
|
||||
$self->Seek($last);
|
||||
my $buff;
|
||||
$self->Read($buff, $bytes);
|
||||
my $warn = '';
|
||||
if ($buff =~ /[^\0]/) {
|
||||
$bad += ($pos - $last);
|
||||
$warn = ' - NON-ZERO!';
|
||||
}
|
||||
printf "0x%.8x - 0x%.8x (%d bytes)$warn\n", $last, $pos, $bytes;
|
||||
}
|
||||
my $cur = $pos + $len;
|
||||
$last = $cur unless defined $last and $last > $cur;
|
||||
}
|
||||
print "$tot bytes missed";
|
||||
$bad and print ", $bad non-zero!";
|
||||
print "\n";
|
||||
} else {
|
||||
warn "File::RandomAccess DEBUG not working (file already closed?)\n";
|
||||
}
|
||||
delete $self->{DEBUG};
|
||||
}
|
||||
# close the file
|
||||
if ($self->{FILE_PT}) {
|
||||
close($self->{FILE_PT});
|
||||
delete $self->{FILE_PT};
|
||||
}
|
||||
# reset the buffer
|
||||
my $emptyBuff = '';
|
||||
$self->{BUFF_PT} = \$emptyBuff;
|
||||
$self->{LEN} = 0;
|
||||
$self->{POS} = 0;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
1; # end
|
||||
@@ -1,231 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: RandomAccess.pod -- Documentation for File::RandomAccess
|
||||
#
|
||||
# Description: Buffer to support random access reading of sequential file
|
||||
#
|
||||
# Legal: Copyright (c) 2003-2018 Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the same terms as Perl itself.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
=head1 NAME
|
||||
|
||||
File::RandomAccess - Random access reads of sequential file or scalar
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use File::RandomAccess;
|
||||
|
||||
$raf = new File::RandomAccess(\*FILE, $disableSeekTest);
|
||||
|
||||
$raf = new File::RandomAccess(\$data);
|
||||
|
||||
$err = $raf->Seek($pos);
|
||||
$num = $raf->Read($buff, $bytes);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Allows random access to sequential file by buffering the file if necessary.
|
||||
Also allows access to data in memory to be accessed as if it were a file.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<new>
|
||||
|
||||
Creates a new RandomAccess object given a file reference or
|
||||
reference to data in memory.
|
||||
|
||||
# Read from open file or pipe
|
||||
$raf = new File::RandomAccess(\*FILE);
|
||||
|
||||
# Read from data in memory
|
||||
$raf = new File::RandomAccess(\$data);
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object or RandomAccess class name.
|
||||
|
||||
1) File reference or scalar reference.
|
||||
|
||||
2) Flag set if file is already random access (disables automatic SeekTest).
|
||||
|
||||
=item Returns:
|
||||
|
||||
Reference to RandomAccess object.
|
||||
|
||||
=back
|
||||
|
||||
=item B<SeekTest>
|
||||
|
||||
Performs test seek() on file to determine if buffering is necessary. If
|
||||
the seek() fails, then the file is buffered to allow random access.
|
||||
B<SeekTest>() is automatically called from B<new> unless specified.
|
||||
|
||||
$result = $raf->SeekTest();
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
=item Returns:
|
||||
|
||||
1 if seek test passed (ie. no buffering required).
|
||||
|
||||
=item Notes:
|
||||
|
||||
Must be called before any other i/o.
|
||||
|
||||
=back
|
||||
|
||||
=item B<Tell>
|
||||
|
||||
Get current position in file
|
||||
|
||||
$pos = $raf->Tell();
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
=item Returns:
|
||||
|
||||
Current position in file
|
||||
|
||||
=back
|
||||
|
||||
=item B<Seek>
|
||||
|
||||
Seek to specified position in file. When buffered, this doesn't quite
|
||||
behave like seek() since it returns success even if you seek outside the
|
||||
limits of the file.
|
||||
|
||||
$success = $raf->Seek($pos, 0);
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
1) Position.
|
||||
|
||||
2) Whence (0=from start, 1=from cur pos, 2=from end).
|
||||
|
||||
=item Returns:
|
||||
|
||||
1 on success, 0 otherwise
|
||||
|
||||
=back
|
||||
|
||||
=item B<Read>
|
||||
|
||||
Read data from the file.
|
||||
|
||||
$num = $raf->Read($buff, 1024);
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
1) Buffer.
|
||||
|
||||
2) Number of bytes to read.
|
||||
|
||||
=item Returns:
|
||||
|
||||
Number of bytes actually read.
|
||||
|
||||
=back
|
||||
|
||||
=item B<ReadLine>
|
||||
|
||||
Read a line from file (end of line is $/).
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
1) Buffer.
|
||||
|
||||
=item Returns:
|
||||
|
||||
Number of bytes read.
|
||||
|
||||
=back
|
||||
|
||||
=item B<Slurp>
|
||||
|
||||
Read whole file into buffer, without changing read pointer.
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
=item Returns:
|
||||
|
||||
Nothing.
|
||||
|
||||
=back
|
||||
|
||||
=item B<BinMode>
|
||||
|
||||
Set binary mode for file.
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
=item Returns:
|
||||
|
||||
Nothing.
|
||||
|
||||
=back
|
||||
|
||||
=item B<Close>
|
||||
|
||||
Close the file and free the buffer.
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Reference to RandomAccess object.
|
||||
|
||||
=item Returns:
|
||||
|
||||
Nothing.
|
||||
|
||||
=back
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018 Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
# end
|
||||
@@ -1,501 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: AES.pm
|
||||
#
|
||||
# Description: AES encryption with cipher-block chaining
|
||||
#
|
||||
# Revisions: 2010/10/14 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://www.hoozi.com/Articles/AESEncryption.htm
|
||||
# 2) http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||
# 3) http://www.faqs.org/rfcs/rfc3602.html
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::AES;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION @ISA @EXPORT_OK);
|
||||
require Exporter;
|
||||
|
||||
$VERSION = '1.01';
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(Crypt);
|
||||
|
||||
my $seeded; # flag set if we already seeded random number generator
|
||||
my $nr; # number of rounds in AES cipher
|
||||
my @cbc; # cipher-block chaining bytes
|
||||
|
||||
# arrays (all unsigned character) to hold intermediate results during encryption
|
||||
my @state = ([],[],[],[]); # the 2-dimensional state array
|
||||
my @RoundKey; # round keys
|
||||
|
||||
my @sbox = (
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
);
|
||||
|
||||
# reverse sbox
|
||||
my @rsbox = (
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
|
||||
);
|
||||
|
||||
# the round constant word array, $rcon[i], contains the values given by
|
||||
# x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||
# Note that i starts at 1, not 0).
|
||||
my @rcon = (
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
|
||||
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
|
||||
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
|
||||
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
|
||||
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
|
||||
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
|
||||
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
|
||||
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
|
||||
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
|
||||
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
|
||||
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
|
||||
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
|
||||
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
|
||||
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
|
||||
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# This function produces 4*($nr+1) round keys.
|
||||
# The round keys are used in each round to encrypt the states.
|
||||
# Inputs: 0) key string (must be 16, 24 or 32 bytes long)
|
||||
sub KeyExpansion($)
|
||||
{
|
||||
my $key = shift;
|
||||
my @key = unpack 'C*', $key; # convert the key into a byte array
|
||||
my $nk = int(length($key) / 4); # number of 32-bit words in the key
|
||||
$nr = $nk + 6; # number of rounds
|
||||
|
||||
# temporary variables (all unsigned characters)
|
||||
my ($i,@temp);
|
||||
|
||||
# The first round key is the key itself.
|
||||
for ($i=0; $i<$nk; ++$i) {
|
||||
@RoundKey[$i*4..$i*4+3] = @key[$i*4..$i*4+3];
|
||||
}
|
||||
# All other round keys are found from the previous round keys.
|
||||
while ($i < (4 * ($nr+1))) {
|
||||
|
||||
@temp[0..3] = @RoundKey[($i-1)*4..($i-1)*4+3];
|
||||
|
||||
if ($i % $nk == 0) {
|
||||
# rotate the 4 bytes in a word to the left once
|
||||
# [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||
@temp[0..3] = @temp[1,2,3,0];
|
||||
|
||||
# take a four-byte input word and apply the S-box
|
||||
# to each of the four bytes to produce an output word.
|
||||
@temp[0..3] = @sbox[@temp[0..3]];
|
||||
|
||||
$temp[0] = $temp[0] ^ $rcon[$i/$nk];
|
||||
|
||||
} elsif ($nk > 6 && $i % $nk == 4) {
|
||||
|
||||
@temp[0..3] = @sbox[@temp[0..3]];
|
||||
}
|
||||
$RoundKey[$i*4+0] = $RoundKey[($i-$nk)*4+0] ^ $temp[0];
|
||||
$RoundKey[$i*4+1] = $RoundKey[($i-$nk)*4+1] ^ $temp[1];
|
||||
$RoundKey[$i*4+2] = $RoundKey[($i-$nk)*4+2] ^ $temp[2];
|
||||
$RoundKey[$i*4+3] = $RoundKey[($i-$nk)*4+3] ^ $temp[3];
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# This function adds the round key to state.
|
||||
# The round key is added to the state by an XOR function.
|
||||
sub AddRoundKey($)
|
||||
{
|
||||
my $round = shift;
|
||||
my ($i,$j);
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
my $k = $round*16 + $i*4;
|
||||
for ($j=0; $j<4; ++$j) {
|
||||
$state[$j][$i] ^= $RoundKey[$k + $j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Substitute the values in the state matrix with values in an S-box
|
||||
sub SubBytes()
|
||||
{
|
||||
my $i;
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
@{$state[$i]}[0..3] = @sbox[@{$state[$i]}[0..3]];
|
||||
}
|
||||
}
|
||||
|
||||
sub InvSubBytes()
|
||||
{
|
||||
my $i;
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
@{$state[$i]}[0..3] = @rsbox[@{$state[$i]}[0..3]];
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Shift the rows in the state to the left.
|
||||
# Each row is shifted with different offset.
|
||||
# Offset = Row number. So the first row is not shifted.
|
||||
sub ShiftRows()
|
||||
{
|
||||
# rotate first row 1 columns to left
|
||||
@{$state[1]}[0,1,2,3] = @{$state[1]}[1,2,3,0];
|
||||
|
||||
# rotate second row 2 columns to left
|
||||
@{$state[2]}[0,1,2,3] = @{$state[2]}[2,3,0,1];
|
||||
|
||||
# rotate third row 3 columns to left
|
||||
@{$state[3]}[0,1,2,3] = @{$state[3]}[3,0,1,2];
|
||||
}
|
||||
|
||||
sub InvShiftRows()
|
||||
{
|
||||
# rotate first row 1 columns to right
|
||||
@{$state[1]}[0,1,2,3] = @{$state[1]}[3,0,1,2];
|
||||
|
||||
# rotate second row 2 columns to right
|
||||
@{$state[2]}[0,1,2,3] = @{$state[2]}[2,3,0,1];
|
||||
|
||||
# rotate third row 3 columns to right
|
||||
@{$state[3]}[0,1,2,3] = @{$state[3]}[1,2,3,0];
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Find the product of {02} and the argument to xtime modulo 0x1b
|
||||
# Note: returns an integer which may need to be trimmed to 8 bits
|
||||
sub xtime($)
|
||||
{
|
||||
return ($_[0]<<1) ^ ((($_[0]>>7) & 1) * 0x1b);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Multiply numbers in the field GF(2^8)
|
||||
sub Mult($$)
|
||||
{
|
||||
my ($x, $y) = @_;
|
||||
return (($y & 1) * $x) ^
|
||||
(($y>>1 & 1) * xtime($x)) ^
|
||||
(($y>>2 & 1) * xtime(xtime($x))) ^
|
||||
(($y>>3 & 1) * xtime(xtime(xtime($x)))) ^
|
||||
(($y>>4 & 1) * xtime(xtime(xtime(xtime($x)))));
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Mix the columns of the state matrix
|
||||
sub MixColumns()
|
||||
{
|
||||
my ($i,$t0,$t1,$t2);
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
$t0 = $state[0][$i];
|
||||
$t2 = $state[0][$i] ^ $state[1][$i] ^ $state[2][$i] ^ $state[3][$i];
|
||||
$t1 = $state[0][$i] ^ $state[1][$i] ; $t1 = xtime($t1) & 0xff; $state[0][$i] ^= $t1 ^ $t2 ;
|
||||
$t1 = $state[1][$i] ^ $state[2][$i] ; $t1 = xtime($t1) & 0xff; $state[1][$i] ^= $t1 ^ $t2 ;
|
||||
$t1 = $state[2][$i] ^ $state[3][$i] ; $t1 = xtime($t1) & 0xff; $state[2][$i] ^= $t1 ^ $t2 ;
|
||||
$t1 = $state[3][$i] ^ $t0 ; $t1 = xtime($t1) & 0xff; $state[3][$i] ^= $t1 ^ $t2 ;
|
||||
}
|
||||
}
|
||||
|
||||
sub InvMixColumns()
|
||||
{
|
||||
my $i;
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
my $a = $state[0][$i];
|
||||
my $b = $state[1][$i];
|
||||
my $c = $state[2][$i];
|
||||
my $d = $state[3][$i];
|
||||
$state[0][$i] = (Mult($a,0x0e) ^ Mult($b,0x0b) ^ Mult($c,0x0d) ^ Mult($d,0x09)) & 0xff;
|
||||
$state[1][$i] = (Mult($a,0x09) ^ Mult($b,0x0e) ^ Mult($c,0x0b) ^ Mult($d,0x0d)) & 0xff;
|
||||
$state[2][$i] = (Mult($a,0x0d) ^ Mult($b,0x09) ^ Mult($c,0x0e) ^ Mult($d,0x0b)) & 0xff;
|
||||
$state[3][$i] = (Mult($a,0x0b) ^ Mult($b,0x0d) ^ Mult($c,0x09) ^ Mult($d,0x0e)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Encrypt (Cipher) or decrypt (InvCipher) a block of data with CBC
|
||||
# Inputs: 0) string to cipher (must be 16 bytes long)
|
||||
# Returns: cipher'd string
|
||||
sub Cipher($)
|
||||
{
|
||||
my @in = unpack 'C*', $_[0]; # unpack input plaintext
|
||||
my ($i, $j, $round);
|
||||
|
||||
# copy the input PlainText to state array and apply the CBC
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
for ($j=0; $j<4; ++$j) {
|
||||
my $k = $i*4 + $j;
|
||||
$state[$j][$i] = $in[$k] ^ $cbc[$k];
|
||||
}
|
||||
}
|
||||
|
||||
# add the First round key to the state before starting the rounds
|
||||
AddRoundKey(0);
|
||||
|
||||
# there will be $nr rounds; the first $nr-1 rounds are identical
|
||||
for ($round=1; ; ++$round) {
|
||||
SubBytes();
|
||||
ShiftRows();
|
||||
if ($round < $nr) {
|
||||
MixColumns();
|
||||
AddRoundKey($round);
|
||||
} else {
|
||||
# MixColumns() is not used in the last round
|
||||
AddRoundKey($nr);
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# the encryption process is over
|
||||
# copy the state array to output array (and save for CBC)
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
for ($j=0; $j<4; ++$j) {
|
||||
$cbc[$i*4+$j] = $state[$j][$i];
|
||||
}
|
||||
}
|
||||
return pack 'C*', @cbc; # return packed ciphertext
|
||||
}
|
||||
|
||||
sub InvCipher($)
|
||||
{
|
||||
my @in = unpack 'C*', $_[0]; # unpack input ciphertext
|
||||
my (@out, $i, $j, $round);
|
||||
|
||||
# copy the input CipherText to state array
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
for ($j=0; $j<4; ++$j) {
|
||||
$state[$j][$i] = $in[$i*4 + $j];
|
||||
}
|
||||
}
|
||||
|
||||
# add the First round key to the state before starting the rounds
|
||||
AddRoundKey($nr);
|
||||
|
||||
# there will be $nr rounds; the first $nr-1 rounds are identical
|
||||
for ($round=$nr-1; ; --$round) {
|
||||
InvShiftRows();
|
||||
InvSubBytes();
|
||||
AddRoundKey($round);
|
||||
# InvMixColumns() is not used in the last round
|
||||
last if $round <= 0;
|
||||
InvMixColumns();
|
||||
}
|
||||
|
||||
# copy the state array to output array and reverse the CBC
|
||||
for ($i=0; $i<4; ++$i) {
|
||||
for ($j=0; $j<4; ++$j) {
|
||||
my $k = $i*4 + $j;
|
||||
$out[$k] = $state[$j][$i] ^ $cbc[$k];
|
||||
}
|
||||
}
|
||||
@cbc = @in; # update CBC for next block
|
||||
return pack 'C*', @out; # return packed plaintext
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Encrypt/Decrypt using AES-CBC algorithm (with fixed 16-byte blocks)
|
||||
# Inputs: 0) data reference (with leading 16-byte initialization vector when decrypting)
|
||||
# 1) encryption key (16, 24 or 32 bytes for AES-128, AES-192 or AES-256)
|
||||
# 2) encrypt flag (false for decryption, true with length 16 bytes to
|
||||
# encrypt using this as the CBC IV, or true with other length to
|
||||
# encrypt with a randomly-generated IV)
|
||||
# 3) flag to disable padding
|
||||
# Returns: error string, or undef on success
|
||||
# Notes: encrypts/decrypts data in place (encrypted data returned with leading IV)
|
||||
sub Crypt($$;$$)
|
||||
{
|
||||
my ($dataPt, $key, $encrypt, $noPad) = @_;
|
||||
|
||||
# validate key length
|
||||
my $keyLen = length $key;
|
||||
unless ($keyLen == 16 or $keyLen == 24 or $keyLen == 32) {
|
||||
return "Invalid AES key length ($keyLen)";
|
||||
}
|
||||
my $partLen = length($$dataPt) % 16;
|
||||
my ($pos, $i);
|
||||
if ($encrypt) {
|
||||
if (length($encrypt) == 16) {
|
||||
@cbc = unpack 'C*', $encrypt;
|
||||
} else {
|
||||
# generate a random 16-byte CBC initialization vector
|
||||
unless ($seeded) {
|
||||
srand(time() & ($$ + ($$<<15)));
|
||||
$seeded = 1;
|
||||
}
|
||||
for ($i=0; $i<16; ++$i) {
|
||||
$cbc[$i] = int(rand(256));
|
||||
}
|
||||
$encrypt = pack 'C*', @cbc;
|
||||
}
|
||||
$$dataPt = $encrypt . $$dataPt; # add IV to the start of the data
|
||||
# add required padding so we can recover the
|
||||
# original string length after decryption
|
||||
# (padding bytes have value set to padding length)
|
||||
my $padLen = 16 - $partLen;
|
||||
$$dataPt .= (chr($padLen)) x $padLen unless $padLen == 16 and $noPad;
|
||||
$pos = 16; # start encrypting at byte 16 (after the IV)
|
||||
} elsif ($partLen) {
|
||||
return 'Invalid AES ciphertext length';
|
||||
} elsif (length $$dataPt >= 32) {
|
||||
# take the CBC initialization vector from the start of the data
|
||||
@cbc = unpack 'C16', $$dataPt;
|
||||
$$dataPt = substr($$dataPt, 16);
|
||||
$pos = 0; # start decrypting from byte 0 (now that IV is removed)
|
||||
} else {
|
||||
$$dataPt = ''; # empty text
|
||||
return undef;
|
||||
}
|
||||
# the KeyExpansion routine must be called before encryption
|
||||
KeyExpansion($key);
|
||||
|
||||
# loop through the data and convert in blocks
|
||||
my $dataLen = length $$dataPt;
|
||||
my $last = $dataLen - 16;
|
||||
my $func = $encrypt ? \&Cipher : \&InvCipher;
|
||||
while ($pos <= $last) {
|
||||
# cipher this block
|
||||
substr($$dataPt, $pos, 16) = &$func(substr($$dataPt, $pos, 16));
|
||||
$pos += 16;
|
||||
}
|
||||
unless ($encrypt or $noPad) {
|
||||
# remove padding if necessary (padding byte value gives length of padding)
|
||||
my $padLen = ord(substr($$dataPt, -1, 1));
|
||||
return 'AES decryption error (invalid pad byte)' if $padLen > 16;
|
||||
$$dataPt = substr($$dataPt, 0, $dataLen - $padLen);
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::AES - AES encryption with cipher-block chaining
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Image::ExifTool::AES qw(Crypt);
|
||||
|
||||
$err = Crypt(\$plaintext, $key, 1); # encryption
|
||||
|
||||
$err = Crypt(\$ciphertext, $key); # decryption
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains an implementation of the AES encryption/decryption
|
||||
algorithms with cipher-block chaining (CBC) and RFC 2898 PKCS #5 padding.
|
||||
This is the AESV2 and AESV3 encryption mode used in PDF documents.
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
Exports nothing by default, but L</Crypt> may be exported.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 Crypt
|
||||
|
||||
Implement AES encryption/decryption with cipher-block chaining.
|
||||
|
||||
=over 4
|
||||
|
||||
=item Inputs:
|
||||
|
||||
0) Scalar reference for data to encrypt/decrypt.
|
||||
|
||||
1) Encryption key string (must have length 16, 24 or 32).
|
||||
|
||||
2) [optional] Encrypt flag (false to decrypt).
|
||||
|
||||
3) [optional] Flag to avoid removing padding after decrypting, or to avoid
|
||||
adding 16 bytes of padding before encrypting when data length is already a
|
||||
multiple of 16 bytes.
|
||||
|
||||
=item Returns:
|
||||
|
||||
On success, the return value is undefined and the data is encrypted or
|
||||
decrypted as specified. Otherwise returns an error string and the data is
|
||||
left in an indeterminate state.
|
||||
|
||||
=item Notes:
|
||||
|
||||
The length of the encryption key dictates the AES mode, with lengths of 16,
|
||||
24 and 32 bytes resulting in AES-128, AES-192 and AES-256.
|
||||
|
||||
When encrypting, the input data may be any length and will be padded to an
|
||||
even 16-byte block size using the specified padding technique. If the
|
||||
encrypt flag has length 16, it is used as the initialization vector for
|
||||
the cipher-block chaining, otherwise a random IV is generated. Upon
|
||||
successful return the data will be encrypted, with the first 16 bytes of
|
||||
the data being the CBC IV.
|
||||
|
||||
When decrypting, the input data begins with the 16-byte CBC initialization
|
||||
vector.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
This code is blindingly slow. But in truth, slowing down processing is the
|
||||
main purpose of encryption, so this really can't be considered a bug.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.hoozi.com/Articles/AESEncryption.htm>
|
||||
|
||||
=item L<http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf>
|
||||
|
||||
=item L<http://www.faqs.org/rfcs/rfc3602.html>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
@@ -1,281 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: AFCP.pm
|
||||
#
|
||||
# Description: Read/write AFCP trailer
|
||||
#
|
||||
# Revisions: 12/26/2005 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://web.archive.org/web/20080828211305/http://www.tocarte.com/media/axs_afcp_spec.pdf
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::AFCP;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.08';
|
||||
|
||||
sub ProcessAFCP($$);
|
||||
|
||||
%Image::ExifTool::AFCP::Main = (
|
||||
PROCESS_PROC => \&ProcessAFCP,
|
||||
NOTES => q{
|
||||
AFCP stands for AXS File Concatenation Protocol, and is a poorly designed
|
||||
protocol for appending information to the end of files. This can be used as
|
||||
an auxiliary technique to store IPTC information in images, but is
|
||||
incompatible with some file formats.
|
||||
|
||||
ExifTool will read and write (but not create) AFCP IPTC information in JPEG
|
||||
and TIFF images.
|
||||
|
||||
See
|
||||
L<http://web.archive.org/web/20080828211305/http://www.tocarte.com/media/axs_afcp_spec.pdf>
|
||||
for the AFCP specification.
|
||||
},
|
||||
IPTC => { SubDirectory => { TagTable => 'Image::ExifTool::IPTC::Main' } },
|
||||
TEXT => 'Text',
|
||||
Nail => {
|
||||
Name => 'ThumbnailImage',
|
||||
Groups => { 2 => 'Preview' },
|
||||
# (the specification allows for a variable amount of padding before
|
||||
# the image after a 10-byte header, so look for the JPEG SOI marker,
|
||||
# otherwise assume a fixed 8 bytes of padding)
|
||||
RawConv => q{
|
||||
pos($val) = 10;
|
||||
my $start = ($val =~ /\xff\xd8\xff/g) ? pos($val) - 3 : 18;
|
||||
my $img = substr($val, $start);
|
||||
return $self->ValidateImage(\$img, $tag);
|
||||
},
|
||||
},
|
||||
PrVw => {
|
||||
Name => 'PreviewImage',
|
||||
Groups => { 2 => 'Preview' },
|
||||
RawConv => q{
|
||||
pos($val) = 10;
|
||||
my $start = ($val =~ /\xff\xd8\xff/g) ? pos($val) - 3 : 18;
|
||||
my $img = substr($val, $start);
|
||||
return $self->ValidateImage(\$img, $tag);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Read/write AFCP information in a file
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# (Set 'ScanForAFCP' member in dirInfo to scan from current position for AFCP)
|
||||
# Returns: 1 on success, 0 if this file didn't contain AFCP information
|
||||
# -1 on write error or if the offsets were incorrect on reading
|
||||
# - updates DataPos to point to actual AFCP start if ScanForAFCP is set
|
||||
# - updates DirLen to trailer length
|
||||
# - returns Fixup reference in dirInfo hash when writing
|
||||
sub ProcessAFCP($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my $curPos = $raf->Tell();
|
||||
my $offset = $$dirInfo{Offset} || 0; # offset from end of file
|
||||
my $rtnVal = 0;
|
||||
|
||||
NoAFCP: for (;;) {
|
||||
my ($buff, $fix, $dirBuff, $valBuff, $fixup, $vers);
|
||||
# look for AXS trailer
|
||||
last unless $raf->Seek(-12-$offset, 2) and
|
||||
$raf->Read($buff, 12) == 12 and
|
||||
$buff =~ /^(AXS(!|\*))/;
|
||||
my $endPos = $raf->Tell();
|
||||
my $hdr = $1;
|
||||
SetByteOrder($2 eq '!' ? 'MM' : 'II');
|
||||
my $startPos = Get32u(\$buff, 4);
|
||||
if ($raf->Seek($startPos, 0) and $raf->Read($buff, 12) == 12 and $buff =~ /^$hdr/) {
|
||||
$fix = 0;
|
||||
} else {
|
||||
$rtnVal = -1;
|
||||
# look for start of AXS trailer if 'ScanForAFCP'
|
||||
last unless $$dirInfo{ScanForAFCP} and $raf->Seek($curPos, 0);
|
||||
my $actualPos = $curPos;
|
||||
# first look for header right at current position
|
||||
for (;;) {
|
||||
last if $raf->Read($buff, 12) == 12 and $buff =~ /^$hdr/;
|
||||
last NoAFCP if $actualPos != $curPos;
|
||||
# scan for AXS header (could be after preview image)
|
||||
for (;;) {
|
||||
my $buf2;
|
||||
$raf->Read($buf2, 65536) or last NoAFCP;
|
||||
$buff .= $buf2;
|
||||
if ($buff =~ /$hdr/g) {
|
||||
$actualPos += pos($buff) - length($hdr);
|
||||
last; # ok, now go back and re-read header
|
||||
}
|
||||
$buf2 = substr($buf2, -3); # only need last 3 bytes for next test
|
||||
$actualPos += length($buff) - length($buf2);
|
||||
$buff = $buf2;
|
||||
}
|
||||
last unless $raf->Seek($actualPos, 0); # seek to start of AFCP
|
||||
}
|
||||
# calculate shift for fixing AFCP offsets
|
||||
$fix = $actualPos - $startPos;
|
||||
}
|
||||
# set variables returned in dirInfo hash
|
||||
$$dirInfo{DataPos} = $startPos + $fix; # actual start position
|
||||
$$dirInfo{DirLen} = $endPos - ($startPos + $fix);
|
||||
|
||||
$rtnVal = 1;
|
||||
my $verbose = $et->Options('Verbose');
|
||||
my $out = $et->Options('TextOut');
|
||||
my $outfile = $$dirInfo{OutFile};
|
||||
if ($outfile) {
|
||||
# allow all AFCP information to be deleted
|
||||
if ($$et{DEL_GROUP}{AFCP}) {
|
||||
$verbose and print $out " Deleting AFCP\n";
|
||||
++$$et{CHANGED};
|
||||
last;
|
||||
}
|
||||
$dirBuff = $valBuff = '';
|
||||
require Image::ExifTool::Fixup;
|
||||
$fixup = $$dirInfo{Fixup};
|
||||
$fixup or $fixup = $$dirInfo{Fixup} = new Image::ExifTool::Fixup;
|
||||
$vers = substr($buff, 4, 2); # get version number
|
||||
} else {
|
||||
$et->DumpTrailer($dirInfo) if $verbose or $$et{HTML_DUMP};
|
||||
}
|
||||
# read AFCP directory data
|
||||
my $numEntries = Get16u(\$buff, 6);
|
||||
my $dir;
|
||||
unless ($raf->Read($dir, 12 * $numEntries) == 12 * $numEntries) {
|
||||
$et->Error('Error reading AFCP directory', 1);
|
||||
last;
|
||||
}
|
||||
if ($verbose > 2 and not $outfile) {
|
||||
my $dat = $buff . $dir;
|
||||
print $out " AFCP Directory:\n";
|
||||
$et->VerboseDump(\$dat, Addr => $$dirInfo{DataPos}, Width => 12);
|
||||
}
|
||||
$fix and $et->Warn("Adjusted AFCP offsets by $fix", 1);
|
||||
#
|
||||
# process AFCP directory
|
||||
#
|
||||
my $tagTablePtr = GetTagTable('Image::ExifTool::AFCP::Main');
|
||||
my ($index, $entry);
|
||||
for ($index=0; $index<$numEntries; ++$index) {
|
||||
my $entry = 12 * $index;
|
||||
my $tag = substr($dir, $entry, 4);
|
||||
my $size = Get32u(\$dir, $entry + 4);
|
||||
my $offset = Get32u(\$dir, $entry + 8);
|
||||
if ($size < 0x80000000 and
|
||||
$raf->Seek($offset+$fix, 0) and
|
||||
$raf->Read($buff, $size) == $size)
|
||||
{
|
||||
if ($outfile) {
|
||||
# rewrite this information
|
||||
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
||||
if ($tagInfo and $$tagInfo{SubDirectory}) {
|
||||
my %subdirInfo = (
|
||||
DataPt => \$buff,
|
||||
DirStart => 0,
|
||||
DirLen => $size,
|
||||
DataPos => $offset + $fix,
|
||||
Parent => 'AFCP',
|
||||
);
|
||||
my $subTable = GetTagTable($tagInfo->{SubDirectory}->{TagTable});
|
||||
my $newDir = $et->WriteDirectory(\%subdirInfo, $subTable);
|
||||
if (defined $newDir) {
|
||||
$size = length $newDir;
|
||||
$buff = $newDir;
|
||||
}
|
||||
}
|
||||
$fixup->AddFixup(length($dirBuff) + 8);
|
||||
$dirBuff .= $tag . Set32u($size) . Set32u(length $valBuff);
|
||||
$valBuff .= $buff;
|
||||
} else {
|
||||
# extract information
|
||||
$et->HandleTag($tagTablePtr, $tag, $buff,
|
||||
DataPt => \$buff,
|
||||
Size => $size,
|
||||
Index => $index,
|
||||
DataPos => $offset + $fix,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$et->Warn("Bad AFCP directory");
|
||||
$rtnVal = -1 if $outfile;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($outfile and length($dirBuff)) {
|
||||
my $outPos = Tell($outfile); # get current outfile position
|
||||
# apply fixup to directory pointers
|
||||
my $valPos = $outPos + 12; # start of value data
|
||||
$fixup->{Shift} += $valPos + length($dirBuff);
|
||||
$fixup->ApplyFixup(\$dirBuff);
|
||||
# write the AFCP header, directory, value data and EOF record (with zero checksums)
|
||||
Write($outfile, $hdr, $vers, Set16u(length($dirBuff)/12), Set32u(0),
|
||||
$dirBuff, $valBuff, $hdr, Set32u($outPos), Set32u(0)) or $rtnVal = -1;
|
||||
# complete fixup so the calling routine can apply further shifts
|
||||
$fixup->AddFixup(length($dirBuff) + length($valBuff) + 4);
|
||||
$fixup->{Start} += $valPos;
|
||||
$fixup->{Shift} -= $valPos;
|
||||
}
|
||||
last;
|
||||
}
|
||||
return $rtnVal;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::AFCP - Read/write AFCP trailer
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to extract
|
||||
information from the AFCP trailer. Although the AFCP specification is
|
||||
compatible with various file formats, ExifTool currently only processes AFCP
|
||||
in JPEG images.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
AFCP is a specification which allows meta information (including IPTC) to be
|
||||
appended to the end of a file.
|
||||
|
||||
It is a poorly designed protocol because (like TIFF) it uses absolute
|
||||
offsets to specify data locations. This is a huge blunder because it makes
|
||||
the AFCP information dependent on the file length, so it is easily
|
||||
invalidated by image editing software which doesn't recognize the AFCP
|
||||
trailer to fix up these offsets when the file length changes. ExifTool will
|
||||
attempt to fix these invalid offsets if possible.
|
||||
|
||||
Scanning for AFCP information may be time consuming, especially when reading
|
||||
from a sequential device, since the information is at the end of the file.
|
||||
In these instances, the ExifTool FastScan option may be used to disable
|
||||
scanning for AFCP information.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.tocarte.com/media/axs_afcp_spec.pdf>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/AFCP Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: AIFF.pm
|
||||
#
|
||||
# Description: Read AIFF meta information
|
||||
#
|
||||
# Revisions: 01/06/2006 - P. Harvey Created
|
||||
# 09/22/2008 - PH Added DjVu support
|
||||
#
|
||||
# References: 1) http://developer.apple.com/documentation/QuickTime/INMAC/SOUND/imsoundmgr.30.htm#pgfId=3190
|
||||
# 2) http://astronomy.swin.edu.au/~pbourke/dataformats/aiff/
|
||||
# 3) http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::AIFF;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
use Image::ExifTool::ID3;
|
||||
|
||||
$VERSION = '1.08';
|
||||
|
||||
# information for time/date-based tags (time zero is Jan 1, 1904)
|
||||
my %timeInfo = (
|
||||
Groups => { 2 => 'Time' },
|
||||
ValueConv => 'ConvertUnixTime($val - ((66 * 365 + 17) * 24 * 3600))',
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
);
|
||||
|
||||
# AIFF info
|
||||
%Image::ExifTool::AIFF::Main = (
|
||||
GROUPS => { 2 => 'Audio' },
|
||||
NOTES => q{
|
||||
Tags extracted from Audio Interchange File Format (AIFF) files. See
|
||||
L<http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/AIFF.html> for
|
||||
the AIFF specification.
|
||||
},
|
||||
# FORM => 'Format',
|
||||
FVER => {
|
||||
Name => 'FormatVersion',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::AIFF::FormatVers' },
|
||||
},
|
||||
COMM => {
|
||||
Name => 'Common',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::AIFF::Common' },
|
||||
},
|
||||
COMT => {
|
||||
Name => 'Comment',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::AIFF::Comment' },
|
||||
},
|
||||
NAME => {
|
||||
Name => 'Name',
|
||||
ValueConv => '$self->Decode($val, "MacRoman")',
|
||||
},
|
||||
AUTH => {
|
||||
Name => 'Author',
|
||||
Groups => { 2 => 'Author' },
|
||||
ValueConv => '$self->Decode($val, "MacRoman")',
|
||||
},
|
||||
'(c) ' => {
|
||||
Name => 'Copyright',
|
||||
Groups => { 2 => 'Author' },
|
||||
ValueConv => '$self->Decode($val, "MacRoman")',
|
||||
},
|
||||
ANNO => {
|
||||
Name => 'Annotation',
|
||||
ValueConv => '$self->Decode($val, "MacRoman")',
|
||||
},
|
||||
'ID3 ' => {
|
||||
Name => 'ID3',
|
||||
SubDirectory => {
|
||||
TagTable => 'Image::ExifTool::ID3::Main',
|
||||
ProcessProc => \&Image::ExifTool::ID3::ProcessID3,
|
||||
},
|
||||
},
|
||||
# SSND => 'SoundData',
|
||||
# MARK => 'Marker',
|
||||
# INST => 'Instrument',
|
||||
# MIDI => 'MidiData',
|
||||
# AESD => 'AudioRecording',
|
||||
# APPL => 'ApplicationSpecific',
|
||||
);
|
||||
|
||||
%Image::ExifTool::AIFF::Common = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 2 => 'Audio' },
|
||||
FORMAT => 'int16u',
|
||||
0 => 'NumChannels',
|
||||
1 => { Name => 'NumSampleFrames', Format => 'int32u' },
|
||||
3 => 'SampleSize',
|
||||
4 => { Name => 'SampleRate', Format => 'extended' }, #3
|
||||
9 => {
|
||||
Name => 'CompressionType',
|
||||
Format => 'string[4]',
|
||||
PrintConv => {
|
||||
NONE => 'None',
|
||||
ACE2 => 'ACE 2-to-1',
|
||||
ACE8 => 'ACE 8-to-3',
|
||||
MAC3 => 'MAC 3-to-1',
|
||||
MAC6 => 'MAC 6-to-1',
|
||||
sowt => 'Little-endian, no compression',
|
||||
},
|
||||
},
|
||||
11 => { #PH
|
||||
Name => 'CompressorName',
|
||||
Format => 'pstring',
|
||||
ValueConv => '$self->Decode($val, "MacRoman")',
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::AIFF::FormatVers = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
FORMAT => 'int32u',
|
||||
0 => { Name => 'FormatVersionTime', %timeInfo },
|
||||
);
|
||||
|
||||
%Image::ExifTool::AIFF::Comment = (
|
||||
PROCESS_PROC => \&Image::ExifTool::AIFF::ProcessComment,
|
||||
GROUPS => { 2 => 'Audio' },
|
||||
0 => { Name => 'CommentTime', %timeInfo },
|
||||
1 => 'MarkerID',
|
||||
2 => {
|
||||
Name => 'Comment',
|
||||
ValueConv => '$self->Decode($val, "MacRoman")',
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::AIFF::Composite = (
|
||||
Duration => {
|
||||
Require => {
|
||||
0 => 'AIFF:SampleRate',
|
||||
1 => 'AIFF:NumSampleFrames',
|
||||
},
|
||||
RawConv => '($val[0] and $val[1]) ? $val[1] / $val[0] : undef',
|
||||
PrintConv => 'ConvertDuration($val)',
|
||||
},
|
||||
);
|
||||
|
||||
# add our composite tags
|
||||
Image::ExifTool::AddCompositeTags('Image::ExifTool::AIFF');
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process AIFF Comment chunk
|
||||
# Inputs: 0) ExifTool object reference, 1) DirInfo reference, 2) tag table ref
|
||||
# Returns: 1 on success
|
||||
sub ProcessComment($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
my $verbose = $et->Options('Verbose');
|
||||
return 0 unless $dirLen > 2;
|
||||
my $numComments = unpack('n',$$dataPt);
|
||||
my $pos = 2;
|
||||
my $i;
|
||||
$verbose and $et->VerboseDir('Comment', $numComments);
|
||||
for ($i=0; $i<$numComments; ++$i) {
|
||||
last if $pos + 8 > $dirLen;
|
||||
my ($time, $markerID, $size) = unpack("x${pos}Nnn", $$dataPt);
|
||||
$et->HandleTag($tagTablePtr, 0, $time);
|
||||
$et->HandleTag($tagTablePtr, 1, $markerID) if $markerID;
|
||||
$pos += 8;
|
||||
last if $pos + $size > $dirLen;
|
||||
my $val = substr($$dataPt, $pos, $size);
|
||||
$et->HandleTag($tagTablePtr, 2, $val);
|
||||
++$size if $size & 0x01; # account for padding byte if necessary
|
||||
$pos += $size;
|
||||
}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract information from a AIFF file
|
||||
# Inputs: 0) ExifTool object reference, 1) DirInfo reference
|
||||
# Returns: 1 on success, 0 if this wasn't a valid AIFF file
|
||||
sub ProcessAIFF($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my ($buff, $err, $tagTablePtr, $page, $type);
|
||||
|
||||
# verify this is a valid AIFF file
|
||||
return 0 unless $raf->Read($buff, 12) == 12;
|
||||
my $fast3 = $$et{OPTIONS}{FastScan} && $$et{OPTIONS}{FastScan} == 3;
|
||||
my $pos = 12;
|
||||
# check for DjVu image
|
||||
if ($buff =~ /^AT&TFORM/) {
|
||||
# http://www.djvu.org/
|
||||
# http://djvu.sourceforge.net/specs/djvu3changes.txt
|
||||
my $buf2;
|
||||
return 0 unless $raf->Read($buf2, 4) == 4 and $buf2 =~ /^(DJVU|DJVM)/;
|
||||
$pos += 4;
|
||||
$buff = substr($buff, 4) . $buf2;
|
||||
$et->SetFileType('DJVU');
|
||||
return 1 if $fast3;
|
||||
$tagTablePtr = GetTagTable('Image::ExifTool::DjVu::Main');
|
||||
# modifiy FileType to indicate a multi-page document
|
||||
$$et{VALUE}{FileType} .= " (multi-page)" if $buf2 eq 'DJVM';
|
||||
$type = 'DjVu';
|
||||
} else {
|
||||
return 0 unless $buff =~ /^FORM....(AIF(F|C))/s;
|
||||
$et->SetFileType($1);
|
||||
return 1 if $fast3;
|
||||
$tagTablePtr = GetTagTable('Image::ExifTool::AIFF::Main');
|
||||
$type = 'AIFF';
|
||||
}
|
||||
SetByteOrder('MM');
|
||||
my $verbose = $et->Options('Verbose');
|
||||
#
|
||||
# Read through the IFF chunks
|
||||
#
|
||||
for (;;) {
|
||||
$raf->Read($buff, 8) == 8 or last;
|
||||
$pos += 8;
|
||||
my ($tag, $len) = unpack('a4N', $buff);
|
||||
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
||||
$et->VPrint(0, "AIFF '${tag}' chunk ($len bytes of data):\n");
|
||||
# AIFF chunks are padded to an even number of bytes
|
||||
my $len2 = $len + ($len & 0x01);
|
||||
if ($tagInfo) {
|
||||
if ($$tagInfo{TypeOnly}) {
|
||||
$len = $len2 = 4;
|
||||
$page = ($page || 0) + 1;
|
||||
$et->VPrint(0, $$et{INDENT} . "Page $page:\n");
|
||||
}
|
||||
$raf->Read($buff, $len2) >= $len or $err=1, last;
|
||||
unless ($$tagInfo{SubDirectory} or $$tagInfo{Binary}) {
|
||||
$buff =~ s/\0+$//; # remove trailing nulls
|
||||
}
|
||||
$et->HandleTag($tagTablePtr, $tag, $buff,
|
||||
DataPt => \$buff,
|
||||
DataPos => $pos,
|
||||
Start => 0,
|
||||
Size => $len,
|
||||
);
|
||||
} elsif ($verbose > 2 and $len2 < 1024000) {
|
||||
$raf->Read($buff, $len2) == $len2 or $err = 1, last;
|
||||
$et->VerboseDump(\$buff);
|
||||
} else {
|
||||
$raf->Seek($len2, 1) or $err=1, last;
|
||||
}
|
||||
$pos += $len2;
|
||||
}
|
||||
$err and $et->Warn("Error reading $type file (corrupted?)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::AIFF - Read AIFF meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains routines required by Image::ExifTool to extract
|
||||
information from AIFF (Audio Interchange File Format) audio files.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://developer.apple.com/documentation/QuickTime/INMAC/SOUND/imsoundmgr.30.htm#pgfId=3190>
|
||||
|
||||
=item L<http://astronomy.swin.edu.au/~pbourke/dataformats/aiff/>
|
||||
|
||||
=item L<http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/AIFF Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
@@ -1,287 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: APE.pm
|
||||
#
|
||||
# Description: Read Monkey's Audio meta information
|
||||
#
|
||||
# Revisions: 11/13/2006 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://www.monkeysaudio.com/
|
||||
# 2) http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::APE;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.05';
|
||||
|
||||
# APE metadata blocks
|
||||
%Image::ExifTool::APE::Main = (
|
||||
GROUPS => { 2 => 'Audio' },
|
||||
NOTES => q{
|
||||
Tags found in Monkey's Audio (APE) information. Only a few common tags are
|
||||
listed below, but ExifTool will extract any tag found. ExifTool supports
|
||||
APEv1 and APEv2 tags, as well as ID3 information in APE files, and will also
|
||||
read APE metadata from MP3 and MPC files.
|
||||
},
|
||||
Album => { },
|
||||
Artist => { },
|
||||
Genre => { },
|
||||
Title => { },
|
||||
Track => { },
|
||||
Year => { },
|
||||
DURATION => {
|
||||
Name => 'Duration',
|
||||
ValueConv => '$val += 4294967296 if $val < 0 and $val >= -2147483648; $val * 1e-7',
|
||||
PrintConv => 'ConvertDuration($val)',
|
||||
},
|
||||
'Tool Version' => { Name => 'ToolVersion' },
|
||||
'Tool Name' => { Name => 'ToolName' },
|
||||
);
|
||||
|
||||
# APE MAC header version 3.97 or earlier
|
||||
%Image::ExifTool::APE::OldHeader = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 1 => 'MAC', 2 => 'Audio' },
|
||||
FORMAT => 'int16u',
|
||||
NOTES => 'APE MAC audio header for version 3.97 or earlier.',
|
||||
0 => {
|
||||
Name => 'APEVersion',
|
||||
ValueConv => '$val / 1000',
|
||||
},
|
||||
1 => 'CompressionLevel',
|
||||
# 2 => 'FormatFlags',
|
||||
3 => 'Channels',
|
||||
4 => { Name => 'SampleRate', Format => 'int32u' },
|
||||
# 6 => { Name => 'HeaderBytes', Format => 'int32u' }, # WAV header bytes
|
||||
# 8 => { Name => 'TerminatingBytes', Format => 'int32u' },
|
||||
10 => { Name => 'TotalFrames', Format => 'int32u' },
|
||||
12 => { Name => 'FinalFrameBlocks', Format => 'int32u' },
|
||||
);
|
||||
|
||||
# APE MAC header version 3.98 or later
|
||||
%Image::ExifTool::APE::NewHeader = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 1 => 'MAC', 2 => 'Audio' },
|
||||
FORMAT => 'int16u',
|
||||
NOTES => 'APE MAC audio header for version 3.98 or later.',
|
||||
0 => 'CompressionLevel',
|
||||
# 1 => 'FormatFlags',
|
||||
2 => { Name => 'BlocksPerFrame', Format => 'int32u' },
|
||||
4 => { Name => 'FinalFrameBlocks', Format => 'int32u' },
|
||||
6 => { Name => 'TotalFrames', Format => 'int32u' },
|
||||
8 => 'BitsPerSample',
|
||||
9 => 'Channels',
|
||||
10 => { Name => 'SampleRate', Format => 'int32u' },
|
||||
);
|
||||
|
||||
# APE Composite tags
|
||||
%Image::ExifTool::APE::Composite = (
|
||||
GROUPS => { 2 => 'Audio' },
|
||||
Duration => {
|
||||
Require => {
|
||||
0 => 'APE:SampleRate',
|
||||
1 => 'APE:TotalFrames',
|
||||
2 => 'APE:BlocksPerFrame',
|
||||
3 => 'APE:FinalFrameBlocks',
|
||||
},
|
||||
RawConv => '($val[0] && $val[1]) ? (($val[1] - 1) * $val[2] + $val[3]) / $val[0]: undef',
|
||||
PrintConv => 'ConvertDuration($val)',
|
||||
},
|
||||
);
|
||||
|
||||
# add our composite tags
|
||||
Image::ExifTool::AddCompositeTags('Image::ExifTool::APE');
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Make tag info hash for specified tag
|
||||
# Inputs: 0) tag name, 1) tag table ref
|
||||
# - must only call if tag doesn't exist
|
||||
sub MakeTag($$)
|
||||
{
|
||||
my ($tag, $tagTablePtr) = @_;
|
||||
my $name = ucfirst(lc($tag));
|
||||
# remove invalid characters in tag name and capitalize following letters
|
||||
$name =~ s/[^\w-]+(.?)/\U$1/sg;
|
||||
$name =~ s/([a-z0-9])_([a-z])/$1\U$2/g;
|
||||
my %tagInfo = ( Name => $name );
|
||||
$tagInfo{Groups} = { 2 => 'Preview' } if $tag =~ /^Cover Art/ and $tag !~ /Desc$/;
|
||||
AddTagToTable($tagTablePtr, $tag, \%tagInfo);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract information from an APE file
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# - Just looks for APE trailer if FileType is already set
|
||||
# Returns: 1 on success, 0 if this wasn't a valid APE file
|
||||
sub ProcessAPE($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
|
||||
# must first check for leading/trailing ID3 information
|
||||
unless ($$et{DoneID3}) {
|
||||
require Image::ExifTool::ID3;
|
||||
Image::ExifTool::ID3::ProcessID3($et, $dirInfo) and return 1;
|
||||
}
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my $verbose = $et->Options('Verbose');
|
||||
my ($buff, $i, $header, $tagTablePtr, $dataPos, $oldIndent);
|
||||
|
||||
$$et{DoneAPE} = 1;
|
||||
|
||||
# check APE signature and process audio information
|
||||
# unless this is some other type of file
|
||||
unless ($$et{VALUE}{FileType}) {
|
||||
$raf->Read($buff, 32) == 32 or return 0;
|
||||
$buff =~ /^(MAC |APETAGEX)/ or return 0;
|
||||
$et->SetFileType();
|
||||
SetByteOrder('II');
|
||||
|
||||
if ($buff =~ /^APETAGEX/) {
|
||||
# we already read the APE header
|
||||
$header = 1;
|
||||
} else {
|
||||
# process the MAC header
|
||||
my $vers = Get16u(\$buff, 4);
|
||||
my $table;
|
||||
if ($vers <= 3970) {
|
||||
$buff = substr($buff, 4);
|
||||
$table = GetTagTable('Image::ExifTool::APE::OldHeader');
|
||||
} else {
|
||||
my $dlen = Get32u(\$buff, 8);
|
||||
my $hlen = Get32u(\$buff, 12);
|
||||
unless ($dlen & 0x80000000 or $hlen & 0x80000000) {
|
||||
if ($raf->Seek($dlen, 0) and $raf->Read($buff, $hlen) == $hlen) {
|
||||
$table = GetTagTable('Image::ExifTool::APE::NewHeader');
|
||||
}
|
||||
}
|
||||
}
|
||||
$et->ProcessDirectory( { DataPt => \$buff }, $table) if $table;
|
||||
}
|
||||
}
|
||||
# look for APE trailer unless we already found an APE header
|
||||
unless ($header) {
|
||||
# look for the APE trailer footer...
|
||||
my $footPos = -32;
|
||||
# (...but before the ID3v1 trailer if it exists)
|
||||
$footPos -= 128 if $$et{DoneID3} == 2;
|
||||
$raf->Seek($footPos, 2) or return 1;
|
||||
$raf->Read($buff, 32) == 32 or return 1;
|
||||
$buff =~ /^APETAGEX/ or return 1;
|
||||
SetByteOrder('II');
|
||||
}
|
||||
#
|
||||
# Read the APE data (we have just read the APE header or footer into $buff)
|
||||
#
|
||||
my ($version, $size, $count, $flags) = unpack('x8V4', $buff);
|
||||
$version /= 1000;
|
||||
$size -= 32; # get size of data only
|
||||
if (($size & 0x80000000) == 0 and
|
||||
($header or $raf->Seek(-$size-32, 1)) and
|
||||
$raf->Read($buff, $size) == $size)
|
||||
{
|
||||
if ($verbose) {
|
||||
$oldIndent = $$et{INDENT};
|
||||
$$et{INDENT} .= '| ';
|
||||
$et->VerboseDir("APEv$version", $count, $size);
|
||||
$et->VerboseDump(\$buff, DataPos => $raf->Tell() - $size);
|
||||
}
|
||||
$tagTablePtr = GetTagTable('Image::ExifTool::APE::Main');
|
||||
$dataPos = $raf->Tell() - $size;
|
||||
} else {
|
||||
$count = -1;
|
||||
}
|
||||
#
|
||||
# Process the APE tags
|
||||
#
|
||||
my $pos = 0;
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
# read next APE tag
|
||||
last if $pos + 8 > $size;
|
||||
my $len = Get32u(\$buff, $pos);
|
||||
my $flags = Get32u(\$buff, $pos + 4);
|
||||
pos($buff) = $pos + 8;
|
||||
last unless $buff =~ /\G(.*?)\0/sg;
|
||||
my $tag = $1;
|
||||
# avoid conflicts with our special table entries
|
||||
$tag .= '.' if $Image::ExifTool::specialTags{$tag};
|
||||
$pos = pos($buff);
|
||||
last if $pos + $len > $size;
|
||||
my $val = substr($buff, $pos, $len);
|
||||
MakeTag($tag, $tagTablePtr) unless $$tagTablePtr{$tag};
|
||||
# handle binary-value tags
|
||||
if (($flags & 0x06) == 0x02) {
|
||||
my $buf2 = $val;
|
||||
$val = \$buf2;
|
||||
# extract cover art description separately (hackitty hack)
|
||||
if ($tag =~ /^Cover Art/) {
|
||||
$buf2 =~ s/^([\x20-\x7f]*)\0//;
|
||||
if ($1) {
|
||||
my $t = "$tag Desc";
|
||||
my $v = $1;
|
||||
MakeTag($t, $tagTablePtr) unless $$tagTablePtr{$t};
|
||||
$et->HandleTag($tagTablePtr, $t, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
$et->HandleTag($tagTablePtr, $tag, $val,
|
||||
Index => $i,
|
||||
DataPt => \$buff,
|
||||
DataPos => $dataPos,
|
||||
Start => $pos,
|
||||
Size => $len,
|
||||
);
|
||||
$pos += $len;
|
||||
}
|
||||
$i == $count or $et->Warn('Bad APE trailer');
|
||||
$$et{INDENT} = $oldIndent if defined $oldIndent;
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::APE - Read Monkey's Audio meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to extract meta
|
||||
information from Monkey's Audio (APE) audio files.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Currently doesn't parse MAC header unless it is at the start of the file.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.monkeysaudio.com/>
|
||||
|
||||
=item L<http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/APE Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,322 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: APP12.pm
|
||||
#
|
||||
# Description: Read APP12 meta information
|
||||
#
|
||||
# Revisions: 10/18/2005 - P. Harvey Created
|
||||
#
|
||||
# References: 1) Heinrich Giesen private communication
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::APP12;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.13';
|
||||
|
||||
sub ProcessAPP12($$$);
|
||||
sub ProcessDucky($$$);
|
||||
sub WriteDucky($$$);
|
||||
|
||||
# APP12 tags (ref PH)
|
||||
%Image::ExifTool::APP12::PictureInfo = (
|
||||
PROCESS_PROC => \&ProcessAPP12,
|
||||
GROUPS => { 0 => 'APP12', 1 => 'PictureInfo', 2 => 'Image' },
|
||||
PRIORITY => 0,
|
||||
NOTES => q{
|
||||
The JPEG APP12 "Picture Info" segment was used by some older cameras, and
|
||||
contains ASCII-based meta information. Below are some tags which have been
|
||||
observed Agfa and Polaroid images, however ExifTool will extract information
|
||||
from any tags found in this segment.
|
||||
},
|
||||
FNumber => {
|
||||
ValueConv => '$val=~s/^[A-Za-z ]*//;$val', # Agfa leads with an 'F'
|
||||
PrintConv => 'sprintf("%.1f",$val)',
|
||||
},
|
||||
Aperture => {
|
||||
PrintConv => 'sprintf("%.1f",$val)',
|
||||
},
|
||||
TimeDate => {
|
||||
Name => 'DateTimeOriginal',
|
||||
Description => 'Date/Time Original',
|
||||
Groups => { 2 => 'Time' },
|
||||
ValueConv => '$val=~/^\d+$/ ? ConvertUnixTime($val) : $val',
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
},
|
||||
Shutter => {
|
||||
Name => 'ExposureTime',
|
||||
ValueConv => '$val * 1e-6',
|
||||
PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
||||
},
|
||||
shtr => {
|
||||
Name => 'ExposureTime',
|
||||
ValueConv => '$val * 1e-6',
|
||||
PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
||||
},
|
||||
'Serial#' => {
|
||||
Name => 'SerialNumber',
|
||||
Groups => { 2 => 'Camera' },
|
||||
},
|
||||
Flash => { PrintConv => { 0 => 'Off', 1 => 'On' } },
|
||||
Macro => { PrintConv => { 0 => 'Off', 1 => 'On' } },
|
||||
StrobeTime => { },
|
||||
Ytarget => { Name => 'YTarget' },
|
||||
ylevel => { Name => 'YLevel' },
|
||||
FocusPos => { },
|
||||
FocusMode => { },
|
||||
Quality => { },
|
||||
ExpBias => 'ExposureCompensation',
|
||||
FWare => 'FirmwareVersion',
|
||||
StrobeTime => { },
|
||||
Resolution => { },
|
||||
Protect => { },
|
||||
ConTake => { },
|
||||
ImageSize => { PrintConv => '$val=~tr/-/x/;$val' },
|
||||
ColorMode => { },
|
||||
Zoom => { },
|
||||
ZoomPos => { },
|
||||
LightS => { },
|
||||
Type => {
|
||||
Name => 'CameraType',
|
||||
Groups => { 2 => 'Camera' },
|
||||
DataMember => 'CameraType',
|
||||
RawConv => '$self->{CameraType} = $val',
|
||||
},
|
||||
Version => { Groups => { 2 => 'Camera' } },
|
||||
ID => { Groups => { 2 => 'Camera' } },
|
||||
);
|
||||
|
||||
# APP12 segment written in Photoshop "Save For Web" images
|
||||
# (from tests with Photoshop 7 files - PH/1)
|
||||
%Image::ExifTool::APP12::Ducky = (
|
||||
PROCESS_PROC => \&ProcessDucky,
|
||||
WRITE_PROC => \&WriteDucky,
|
||||
GROUPS => { 0 => 'Ducky', 1 => 'Ducky', 2 => 'Image' },
|
||||
WRITABLE => 'string',
|
||||
NOTES => q{
|
||||
Photoshop uses the JPEG APP12 "Ducky" segment to store some information in
|
||||
"Save for Web" images.
|
||||
},
|
||||
1 => { #PH
|
||||
Name => 'Quality',
|
||||
Priority => 0,
|
||||
Avoid => 1,
|
||||
Writable => 'int32u',
|
||||
ValueConv => 'unpack("N",$val)', # 4-byte integer
|
||||
ValueConvInv => 'pack("N",$val)',
|
||||
PrintConv => '"$val%"',
|
||||
PrintConvInv => '$val=~/(\d+)/ ? $1 : undef',
|
||||
},
|
||||
2 => { #1
|
||||
Name => 'Comment',
|
||||
Priority => 0,
|
||||
Avoid => 1,
|
||||
# (ignore 4-byte character count at start of value)
|
||||
ValueConv => '$self->Decode(substr($val,4),"UCS2","MM")',
|
||||
ValueConvInv => 'pack("N",length $val) . $self->Encode($val,"UCS2","MM")',
|
||||
},
|
||||
3 => { #PH
|
||||
Name => 'Copyright',
|
||||
Priority => 0,
|
||||
Avoid => 1,
|
||||
Groups => { 2 => 'Author' },
|
||||
# (ignore 4-byte character count at start of value)
|
||||
ValueConv => '$self->Decode(substr($val,4),"UCS2","MM")',
|
||||
ValueConvInv => 'pack("N",length $val) . $self->Encode($val,"UCS2","MM")',
|
||||
},
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Write APP12 Ducky segment
|
||||
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
||||
# Returns: New directory data or undefined on error
|
||||
sub WriteDucky($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
$et or return 1; # allow dummy access to autoload this package
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $pos = $$dirInfo{DirStart};
|
||||
my $newTags = $et->GetNewTagInfoHash($tagTablePtr);
|
||||
my @addTags = sort { $a <=> $b } keys(%$newTags);
|
||||
my ($dirEnd, %doneTags);
|
||||
if ($dataPt) {
|
||||
$dirEnd = $pos + $$dirInfo{DirLen};
|
||||
} else {
|
||||
my $tmp = '';
|
||||
$dataPt = \$tmp;
|
||||
$pos = $dirEnd = 0;
|
||||
}
|
||||
my $newData = '';
|
||||
SetByteOrder('MM');
|
||||
# process all data blocks in Ducky segment
|
||||
for (;;) {
|
||||
my ($tag, $len, $val);
|
||||
if ($pos + 4 <= $dirEnd) {
|
||||
$tag = Get16u($dataPt, $pos);
|
||||
$len = Get16u($dataPt, $pos + 2);
|
||||
$pos += 4;
|
||||
if ($pos + $len > $dirEnd) {
|
||||
$et->Warn('Invalid Ducky block length');
|
||||
return undef;
|
||||
}
|
||||
$val = substr($$dataPt, $pos, $len);
|
||||
$pos += $len;
|
||||
} else {
|
||||
last unless @addTags;
|
||||
$tag = pop @addTags;
|
||||
next if $doneTags{$tag};
|
||||
}
|
||||
$doneTags{$tag} = 1;
|
||||
my $tagInfo = $$newTags{$tag};
|
||||
if ($tagInfo) {
|
||||
my $nvHash = $et->GetNewValueHash($tagInfo);
|
||||
my $isNew;
|
||||
if (defined $val) {
|
||||
if ($et->IsOverwriting($nvHash, $val)) {
|
||||
$et->VerboseValue("- Ducky:$$tagInfo{Name}", $val);
|
||||
$isNew = 1;
|
||||
}
|
||||
} else {
|
||||
next unless $$nvHash{IsCreating};
|
||||
$isNew = 1;
|
||||
}
|
||||
if ($isNew) {
|
||||
$val = $et->GetNewValue($nvHash);
|
||||
++$$et{CHANGED};
|
||||
next unless defined $val; # next if tag is being deleted
|
||||
$et->VerboseValue("+ Ducky:$$tagInfo{Name}", $val);
|
||||
}
|
||||
}
|
||||
$newData .= pack('nn', $tag, length $val) . $val;
|
||||
}
|
||||
$newData .= "\0\0" if length $newData;
|
||||
return $newData;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process APP12 Ducky segment (ref PH)
|
||||
# Inputs: 0) ExifTool object reference, 1) Directory information ref, 2) tag table ref
|
||||
# Returns: 1 on success, 0 if this wasn't a recognized Ducky segment
|
||||
# Notes: This segment has the following format:
|
||||
# 1) 5 bytes: "Ducky"
|
||||
# 2) multiple data blocks (all integers are big endian):
|
||||
# a) 2 bytes: block type (0=end, 1=Quality, 2=Comment, 3=Copyright)
|
||||
# b) 2 bytes: block length (N)
|
||||
# c) N bytes: block data
|
||||
sub ProcessDucky($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $pos = $$dirInfo{DirStart};
|
||||
my $dirEnd = $pos + $$dirInfo{DirLen};
|
||||
SetByteOrder('MM');
|
||||
# process all data blocks in Ducky segment
|
||||
for (;;) {
|
||||
last if $pos + 4 > $dirEnd;
|
||||
my $tag = Get16u($dataPt, $pos);
|
||||
my $len = Get16u($dataPt, $pos + 2);
|
||||
$pos += 4;
|
||||
if ($pos + $len > $dirEnd) {
|
||||
$et->Warn('Invalid Ducky block length');
|
||||
last;
|
||||
}
|
||||
my $val = substr($$dataPt, $pos, $len);
|
||||
$et->HandleTag($tagTablePtr, $tag, $val,
|
||||
DataPt => $dataPt,
|
||||
DataPos => $$dirInfo{DataPos},
|
||||
Start => $pos,
|
||||
Size => $len,
|
||||
);
|
||||
$pos += $len;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process APP12 Picture Info segment (ref PH)
|
||||
# Inputs: 0) ExifTool object reference, 1) Directory information ref, 2) tag table ref
|
||||
# Returns: 1 on success, 0 if this wasn't a recognized APP12
|
||||
sub ProcessAPP12($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirStart = $$dirInfo{DirStart} || 0;
|
||||
my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart);
|
||||
if ($dirLen != $dirStart + length($$dataPt)) {
|
||||
my $buff = substr($$dataPt, $dirStart, $dirLen);
|
||||
$dataPt = \$buff;
|
||||
} else {
|
||||
pos($$dataPt) = $$dirInfo{DirStart};
|
||||
}
|
||||
my $verbose = $et->Options('Verbose');
|
||||
my $success = 0;
|
||||
my $section = '';
|
||||
pos($$dataPt) = 0;
|
||||
|
||||
# this regular expression is a bit complex, but basically we are looking for
|
||||
# section headers (eg. "[Camera Info]") and tag/value pairs (eg. "tag=value",
|
||||
# where "value" may contain white space), separated by spaces or CR/LF.
|
||||
# (APP12 uses CR/LF, but Olympus TextualInfo is similar and uses spaces)
|
||||
while ($$dataPt =~ /(\[.*?\]|[\w#-]+=[\x20-\x7e]+?(?=\s*([\n\r\0]|[\w#-]+=|\[|$)))/g) {
|
||||
my $token = $1;
|
||||
# was this a section name?
|
||||
if ($token =~ /^\[(.*)\]/) {
|
||||
$et->VerboseDir($1) if $verbose;
|
||||
$section = ($token =~ /\[(\S+) ?Info\]/i) ? $1 : '';
|
||||
$success = 1;
|
||||
next;
|
||||
}
|
||||
$et->VerboseDir($$dirInfo{DirName}) if $verbose and not $success;
|
||||
$success = 1;
|
||||
my ($tag, $val) = ($token =~ /(\S+)=(.+)/);
|
||||
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
||||
$verbose and $et->VerboseInfo($tag, $tagInfo, Value => $val);
|
||||
unless ($tagInfo) {
|
||||
# add new tag to table
|
||||
$tagInfo = { Name => ucfirst $tag };
|
||||
# put in Camera group if information in "Camera" section
|
||||
$$tagInfo{Groups} = { 2 => 'Camera' } if $section =~ /camera/i;
|
||||
AddTagToTable($tagTablePtr, $tag, $tagInfo);
|
||||
}
|
||||
$et->FoundTag($tagInfo, $val);
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
|
||||
1; #end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::APP12 - Read APP12 meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is loaded automatically by Image::ExifTool when required.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to interpret
|
||||
APP12 meta information.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 ACKNOWLEDGEMENTS
|
||||
|
||||
Thanks to Heinrich Giesen for his help decoding APP12 "Ducky" information.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/APP12 Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
@@ -1,898 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: ASF.pm
|
||||
#
|
||||
# Description: Read ASF/WMA/WMV meta information
|
||||
#
|
||||
# Revisions: 12/23/2005 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://www.microsoft.com/windows/windowsmedia/format/asfspec.aspx
|
||||
# 2) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart3.pdf (Oct 2008)
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::ASF;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
use Image::ExifTool::Exif;
|
||||
use Image::ExifTool::RIFF;
|
||||
|
||||
$VERSION = '1.25';
|
||||
|
||||
sub ProcessASF($$;$);
|
||||
sub ProcessContentDescription($$$);
|
||||
sub ProcessExtendedContentDescription($$$);
|
||||
sub ProcessMetadata($$$);
|
||||
sub ProcessPicture($$$);
|
||||
sub ProcessCodecList($$$);
|
||||
|
||||
# GUID definitions
|
||||
my %errorCorrection = (
|
||||
'20FB5700-5B55-11CF-A8FD-00805F5C442B' => 'No Error Correction',
|
||||
'BFC3CD50-618F-11CF-8BB2-00AA00B4E220' => 'Audio Spread',
|
||||
);
|
||||
|
||||
my %streamType = (
|
||||
'F8699E40-5B4D-11CF-A8FD-00805F5C442B' => 'Audio',
|
||||
'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B' => 'Video',
|
||||
'59DACFC0-59E6-11D0-A3AC-00A0C90348F6' => 'Command',
|
||||
'B61BE100-5B4E-11CF-A8FD-00805F5C442B' => 'JFIF',
|
||||
'35907DE0-E415-11CF-A917-00805F5C442B' => 'Degradable JPEG',
|
||||
'91BD222C-F21C-497A-8B6D-5AA86BFC0185' => 'File Transfer',
|
||||
'3AFB65E2-47EF-40F2-AC2C-70A90D71D343' => 'Binary',
|
||||
);
|
||||
|
||||
my %mutex = (
|
||||
'D6E22A00-35DA-11D1-9034-00A0C90349BE' => 'MutexLanguage',
|
||||
'D6E22A01-35DA-11D1-9034-00A0C90349BE' => 'MutexBitrate',
|
||||
'D6E22A02-35DA-11D1-9034-00A0C90349BE' => 'MutexUnknown',
|
||||
);
|
||||
|
||||
my %bandwidthSharing = (
|
||||
'AF6060AA-5197-11D2-B6AF-00C04FD908E9' => 'SharingExclusive',
|
||||
'AF6060AB-5197-11D2-B6AF-00C04FD908E9' => 'SharingPartial',
|
||||
);
|
||||
|
||||
my %typeSpecific = (
|
||||
'776257D4-C627-41CB-8F81-7AC7FF1C40CC' => 'WebStreamMediaSubtype',
|
||||
'DA1E6B13-8359-4050-B398-388E965BF00C' => 'WebStreamFormat',
|
||||
);
|
||||
|
||||
my %advancedContentEncryption = (
|
||||
'7A079BB6-DAA4-4e12-A5CA-91D38DC11A8D' => 'DRMNetworkDevices',
|
||||
);
|
||||
|
||||
# ASF top level objects
|
||||
%Image::ExifTool::ASF::Main = (
|
||||
PROCESS_PROC => \&ProcessASF,
|
||||
NOTES => q{
|
||||
The ASF format is used by Windows WMA and WMV files, and DIVX videos. Tag
|
||||
ID's aren't listed because they are huge 128-bit GUID's that would ruin the
|
||||
formatting of this table.
|
||||
},
|
||||
'75B22630-668E-11CF-A6D9-00AA0062CE6C' => {
|
||||
Name => 'Header',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::Header', Size => 6 },
|
||||
},
|
||||
'75B22636-668E-11CF-A6D9-00AA0062CE6C' => 'Data',
|
||||
'33000890-E5B1-11CF-89F4-00A0C90349CB' => 'SimpleIndex',
|
||||
'D6E229D3-35DA-11D1-9034-00A0C90349BE' => 'Index',
|
||||
'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C' => 'MediaIndex',
|
||||
'3CB73FD0-0C4A-4803-953D-EDF7B6228F0C' => 'TimecodeIndex',
|
||||
'BE7ACFCB-97A9-42E8-9C71-999491E3AFAC' => { #2
|
||||
Name => 'XMP',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
||||
},
|
||||
);
|
||||
|
||||
# ASF header objects
|
||||
%Image::ExifTool::ASF::Header = (
|
||||
PROCESS_PROC => \&ProcessASF,
|
||||
'8CABDCA1-A947-11CF-8EE4-00C00C205365' => {
|
||||
Name => 'FileProperties',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::FileProperties' },
|
||||
},
|
||||
'B7DC0791-A9B7-11CF-8EE6-00C00C205365' => {
|
||||
Name => 'StreamProperties',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::StreamProperties' },
|
||||
},
|
||||
'5FBF03B5-A92E-11CF-8EE3-00C00C205365' => {
|
||||
Name => 'HeaderExtension',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::HeaderExtension', Size => 22 },
|
||||
},
|
||||
'86D15240-311D-11D0-A3A4-00A0C90348F6' => {
|
||||
Name => 'CodecList',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::CodecList' },
|
||||
},
|
||||
'1EFB1A30-0B62-11D0-A39B-00A0C90348F6' => 'ScriptCommand',
|
||||
'F487CD01-A951-11CF-8EE6-00C00C205365' => 'Marker',
|
||||
'D6E229DC-35DA-11D1-9034-00A0C90349BE' => 'BitrateMutualExclusion',
|
||||
'75B22635-668E-11CF-A6D9-00AA0062CE6C' => 'ErrorCorrection',
|
||||
'75B22633-668E-11CF-A6D9-00AA0062CE6C' => {
|
||||
Name => 'ContentDescription',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::ContentDescr' },
|
||||
},
|
||||
'2211B3FA-BD23-11D2-B4B7-00A0C955FC6E' => {
|
||||
Name => 'ContentBranding',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::ContentBranding' },
|
||||
},
|
||||
'D2D0A440-E307-11D2-97F0-00A0C95EA850' => {
|
||||
Name => 'ExtendedContentDescr',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ASF::ExtendedDescr' },
|
||||
},
|
||||
'7BF875CE-468D-11D1-8D82-006097C9A2B2' => 'StreamBitrateProps',
|
||||
'2211B3FB-BD23-11D2-B4B7-00A0C955FC6E' => 'ContentEncryption',
|
||||
'298AE614-2622-4C17-B935-DAE07EE9289C' => 'ExtendedContentEncryption',
|
||||
'2211B3FC-BD23-11D2-B4B7-00A0C955FC6E' => 'DigitalSignature',
|
||||
'1806D474-CADF-4509-A4BA-9AABCB96AAE8' => 'Padding',
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::ContentDescr = (
|
||||
PROCESS_PROC => \&ProcessContentDescription,
|
||||
GROUPS => { 2 => 'Video' },
|
||||
0 => 'Title',
|
||||
1 => { Name => 'Author', Groups => { 2 => 'Author' } },
|
||||
2 => { Name => 'Copyright', Groups => { 2 => 'Author' } },
|
||||
3 => 'Description',
|
||||
4 => 'Rating',
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::ContentBranding = (
|
||||
PROCESS_PROC => \&ProcessContentBranding,
|
||||
GROUPS => { 2 => 'Author' },
|
||||
0 => {
|
||||
Name => 'BannerImageType',
|
||||
PrintConv => {
|
||||
0 => 'None',
|
||||
1 => 'Bitmap',
|
||||
2 => 'JPEG',
|
||||
3 => 'GIF',
|
||||
},
|
||||
},
|
||||
1 => { Name => 'BannerImage', Groups => { 2 => 'Preview' }, Binary => 1 },
|
||||
2 => 'BannerImageURL',
|
||||
3 => 'CopyrightURL',
|
||||
);
|
||||
|
||||
# Note: Many of these tags are similar to those in Image::ExifTool::Microsoft::Xtra
|
||||
# and Image::ExifTool::WTV::Metadata
|
||||
# (tags in this table may have a leading "WM/" removed)
|
||||
%Image::ExifTool::ASF::ExtendedDescr = (
|
||||
PROCESS_PROC => \&ProcessExtendedContentDescription,
|
||||
GROUPS => { 2 => 'Video' },
|
||||
ASFLeakyBucketPairs => { Binary => 1 },
|
||||
AspectRatioX => {},
|
||||
AspectRatioY => {},
|
||||
Author => { Groups => { 2 => 'Author' } },
|
||||
AverageLevel => {},
|
||||
BannerImageData => {},
|
||||
BannerImageType => {},
|
||||
BannerImageURL => {},
|
||||
Bitrate => { PrintConv => 'ConvertBitrate($val)' },
|
||||
Broadcast => {},
|
||||
BufferAverage => {},
|
||||
Can_Skip_Backward => {},
|
||||
Can_Skip_Forward => {},
|
||||
Copyright => { Groups => { 2 => 'Author' } },
|
||||
CopyrightURL => { Groups => { 2 => 'Author' } },
|
||||
CurrentBitrate => { PrintConv => 'ConvertBitrate($val)' },
|
||||
Description => {},
|
||||
DRM_ContentID => {},
|
||||
DRM_DRMHeader_ContentDistributor => {},
|
||||
DRM_DRMHeader_ContentID => {},
|
||||
DRM_DRMHeader_IndividualizedVersion => {},
|
||||
DRM_DRMHeader_KeyID => {},
|
||||
DRM_DRMHeader_LicenseAcqURL => {},
|
||||
DRM_DRMHeader_SubscriptionContentID => {},
|
||||
DRM_DRMHeader => {},
|
||||
DRM_IndividualizedVersion => {},
|
||||
DRM_KeyID => {},
|
||||
DRM_LASignatureCert => {},
|
||||
DRM_LASignatureLicSrvCert => {},
|
||||
DRM_LASignaturePrivKey => {},
|
||||
DRM_LASignatureRootCert => {},
|
||||
DRM_LicenseAcqURL => {},
|
||||
DRM_V1LicenseAcqURL => {},
|
||||
Duration => { PrintConv => 'ConvertDuration($val)' },
|
||||
FileSize => {},
|
||||
HasArbitraryDataStream => {},
|
||||
HasAttachedImages => {},
|
||||
HasAudio => {},
|
||||
HasFileTransferStream => {},
|
||||
HasImage => {},
|
||||
HasScript => {},
|
||||
HasVideo => {},
|
||||
Is_Protected => {},
|
||||
Is_Trusted => {},
|
||||
IsVBR => {},
|
||||
NSC_Address => {},
|
||||
NSC_Description => {},
|
||||
NSC_Email => {},
|
||||
NSC_Name => {},
|
||||
NSC_Phone => {},
|
||||
NumberOfFrames => {},
|
||||
OptimalBitrate => { PrintConv => 'ConvertBitrate($val)' },
|
||||
PeakValue => {},
|
||||
Rating => {},
|
||||
Seekable => {},
|
||||
Signature_Name => {},
|
||||
Stridable => {},
|
||||
Title => {},
|
||||
VBRPeak => {},
|
||||
# "WM/" tags...
|
||||
AlbumArtist => {},
|
||||
AlbumCoverURL => {},
|
||||
AlbumTitle => {},
|
||||
ASFPacketCount => {},
|
||||
ASFSecurityObjectsSize => {},
|
||||
AudioFileURL => {},
|
||||
AudioSourceURL => {},
|
||||
AuthorURL => { Groups => { 2 => 'Author' } },
|
||||
BeatsPerMinute => {},
|
||||
Category => {},
|
||||
Codec => {},
|
||||
Composer => {},
|
||||
Conductor => {},
|
||||
ContainerFormat => {},
|
||||
ContentDistributor => {},
|
||||
ContentGroupDescription => {},
|
||||
Director => {},
|
||||
DRM => {},
|
||||
DVDID => {},
|
||||
EncodedBy => {},
|
||||
EncodingSettings => {},
|
||||
EncodingTime => { Groups => { 2 => 'Time' }, PrintConv => '$self->ConvertDateTime($val)' },
|
||||
Genre => {},
|
||||
GenreID => {},
|
||||
InitialKey => {},
|
||||
ISRC => {},
|
||||
Language => {},
|
||||
Lyrics => {},
|
||||
Lyrics_Synchronised => {},
|
||||
MCDI => {},
|
||||
MediaClassPrimaryID => { ValueConv => 'Image::ExifTool::ASF::GetGUID($val)' },
|
||||
MediaClassSecondaryID => { ValueConv => 'Image::ExifTool::ASF::GetGUID($val)' },
|
||||
MediaCredits => {},
|
||||
MediaIsDelay => {},
|
||||
MediaIsFinale => {},
|
||||
MediaIsLive => {},
|
||||
MediaIsPremiere => {},
|
||||
MediaIsRepeat => {},
|
||||
MediaIsSAP => {},
|
||||
MediaIsStereo => {},
|
||||
MediaIsSubtitled => {},
|
||||
MediaIsTape => {},
|
||||
MediaNetworkAffiliation => {},
|
||||
MediaOriginalBroadcastDateTime => {
|
||||
Groups => { 2 => 'Time' },
|
||||
ValueConv => '$val=~tr/-T/: /; $val',
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
},
|
||||
MediaOriginalChannel => {},
|
||||
MediaStationCallSign => {},
|
||||
MediaStationName => {},
|
||||
ModifiedBy => {},
|
||||
Mood => {},
|
||||
OriginalAlbumTitle => {},
|
||||
OriginalArtist => {},
|
||||
OriginalFilename => 'OriginalFileName',
|
||||
OriginalLyricist => {},
|
||||
OriginalReleaseTime => {
|
||||
Groups => { 2 => 'Time' },
|
||||
ValueConv => '$val=~tr/-T/: /; $val',
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
},
|
||||
OriginalReleaseYear => { Groups => { 2 => 'Time' } },
|
||||
ParentalRating => {},
|
||||
ParentalRatingReason => {},
|
||||
PartOfSet => {},
|
||||
PeakBitrate => { PrintConv => 'ConvertBitrate($val)' },
|
||||
Period => {},
|
||||
Picture => {
|
||||
SubDirectory => {
|
||||
TagTable => 'Image::ExifTool::ASF::Picture',
|
||||
},
|
||||
},
|
||||
PlaylistDelay => {},
|
||||
Producer => {},
|
||||
PromotionURL => {},
|
||||
ProtectionType => {},
|
||||
Provider => {},
|
||||
ProviderCopyright => {},
|
||||
ProviderRating => {},
|
||||
ProviderStyle => {},
|
||||
Publisher => {},
|
||||
RadioStationName => {},
|
||||
RadioStationOwner => {},
|
||||
SharedUserRating => {},
|
||||
StreamTypeInfo => {},
|
||||
SubscriptionContentID => {},
|
||||
SubTitle => 'Subtitle',
|
||||
SubTitleDescription => 'SubtitleDescription',
|
||||
Text => {},
|
||||
ToolName => {},
|
||||
ToolVersion => {},
|
||||
Track => {},
|
||||
TrackNumber => {},
|
||||
UniqueFileIdentifier => {},
|
||||
UserWebURL => {},
|
||||
VideoClosedCaptioning => {},
|
||||
VideoFrameRate => {},
|
||||
VideoHeight => {},
|
||||
VideoWidth => {},
|
||||
WMADRCAverageReference => {},
|
||||
WMADRCAverageTarget => {},
|
||||
WMADRCPeakReference => {},
|
||||
WMADRCPeakTarget => {},
|
||||
WMCollectionGroupID => {},
|
||||
WMCollectionID => {},
|
||||
WMContentID => {},
|
||||
Writer => { Groups => { 2 => 'Author' } },
|
||||
Year => { Groups => { 2 => 'Time' } },
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::Picture = (
|
||||
PROCESS_PROC => \&ProcessPicture,
|
||||
GROUPS => { 2 => 'Image' },
|
||||
0 => {
|
||||
Name => 'PictureType',
|
||||
PrintConv => { # (Note: Duplicated in ID3, ASF and FLAC modules!)
|
||||
0 => 'Other',
|
||||
1 => '32x32 PNG Icon',
|
||||
2 => 'Other Icon',
|
||||
3 => 'Front Cover',
|
||||
4 => 'Back Cover',
|
||||
5 => 'Leaflet',
|
||||
6 => 'Media',
|
||||
7 => 'Lead Artist',
|
||||
8 => 'Artist',
|
||||
9 => 'Conductor',
|
||||
10 => 'Band',
|
||||
11 => 'Composer',
|
||||
12 => 'Lyricist',
|
||||
13 => 'Recording Studio or Location',
|
||||
14 => 'Recording Session',
|
||||
15 => 'Performance',
|
||||
16 => 'Capture from Movie or Video',
|
||||
17 => 'Bright(ly) Colored Fish',
|
||||
18 => 'Illustration',
|
||||
19 => 'Band Logo',
|
||||
20 => 'Publisher Logo',
|
||||
},
|
||||
},
|
||||
1 => 'PictureMIMEType',
|
||||
2 => 'PictureDescription',
|
||||
3 => {
|
||||
Name => 'Picture',
|
||||
Groups => { 2 => 'Preview' },
|
||||
Binary => 1,
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::FileProperties = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 2 => 'Video' },
|
||||
0 => {
|
||||
Name => 'FileID',
|
||||
Format => 'binary[16]',
|
||||
ValueConv => 'Image::ExifTool::ASF::GetGUID($val)',
|
||||
},
|
||||
16 => { Name => 'FileLength', Format => 'int64u' },
|
||||
24 => {
|
||||
Name => 'CreationDate',
|
||||
Format => 'int64u',
|
||||
Groups => { 2 => 'Time' },
|
||||
# time is in 100 ns intervals since 0:00 UTC Jan 1, 1601
|
||||
ValueConv => q{ # (89 leap years between 1601 and 1970)
|
||||
my $t = $val / 1e7 - (((1970-1601)*365+89)*24*3600);
|
||||
return Image::ExifTool::ConvertUnixTime($t) . 'Z';
|
||||
},
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
},
|
||||
32 => { Name => 'DataPackets', Format => 'int64u' },
|
||||
40 => {
|
||||
Name => 'Duration',
|
||||
Format => 'int64u',
|
||||
Notes => 'called PlayDuration by the ASF spec',
|
||||
Priority => 0,
|
||||
ValueConv => '$val / 1e7',
|
||||
PrintConv => 'ConvertDuration($val)',
|
||||
},
|
||||
48 => {
|
||||
Name => 'SendDuration',
|
||||
Format => 'int64u',
|
||||
ValueConv => '$val / 1e7',
|
||||
PrintConv => 'ConvertDuration($val)',
|
||||
},
|
||||
56 => { Name => 'Preroll', Format => 'int64u' },
|
||||
64 => { Name => 'Flags', Format => 'int32u' },
|
||||
68 => { Name => 'MinPacketSize',Format => 'int32u' },
|
||||
72 => { Name => 'MaxPacketSize',Format => 'int32u' },
|
||||
76 => { Name => 'MaxBitrate', Format => 'int32u', PrintConv => 'ConvertBitrate($val)' },
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::StreamProperties = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 2 => 'Video' },
|
||||
NOTES => 'Tags with index 54 and greater are conditional based on the StreamType.',
|
||||
0 => {
|
||||
Name => 'StreamType',
|
||||
Format => 'binary[16]',
|
||||
RawConv => sub { # set ASF_STREAM_TYPE for use in conditional tags
|
||||
my ($val, $et) = @_;
|
||||
$$et{ASF_STREAM_TYPE} = $streamType{GetGUID($val)} || '';
|
||||
return $val;
|
||||
},
|
||||
ValueConv => 'Image::ExifTool::ASF::GetGUID($val)',
|
||||
PrintConv => \%streamType,
|
||||
},
|
||||
16 => {
|
||||
Name => 'ErrorCorrectionType',
|
||||
Format => 'binary[16]',
|
||||
ValueConv => 'Image::ExifTool::ASF::GetGUID($val)',
|
||||
PrintConv => \%errorCorrection,
|
||||
},
|
||||
32 => {
|
||||
Name => 'TimeOffset',
|
||||
Format => 'int64u',
|
||||
ValueConv => '$val / 1e7',
|
||||
PrintConv => '"$val s"',
|
||||
},
|
||||
48 => {
|
||||
Name => 'StreamNumber',
|
||||
Format => 'int16u',
|
||||
PrintConv => '($val & 0x7f) . ($val & 0x8000 ? " (encrypted)" : "")',
|
||||
},
|
||||
54 => [
|
||||
{
|
||||
Condition => '$self->{ASF_STREAM_TYPE} eq "Audio"',
|
||||
Name => 'AudioCodecID',
|
||||
Format => 'int16u',
|
||||
PrintHex => 1,
|
||||
SeparateTable => 'RIFF AudioEncoding',
|
||||
PrintConv => \%Image::ExifTool::RIFF::audioEncoding,
|
||||
},
|
||||
{
|
||||
Condition => '$self->{ASF_STREAM_TYPE} =~ /^(Video|JFIF|Degradable JPEG)$/',
|
||||
Name => 'ImageWidth',
|
||||
Format => 'int32u',
|
||||
},
|
||||
],
|
||||
56 => {
|
||||
Condition => '$self->{ASF_STREAM_TYPE} eq "Audio"',
|
||||
Name => 'AudioChannels',
|
||||
Format => 'int16u',
|
||||
},
|
||||
58 => [
|
||||
{
|
||||
Condition => '$self->{ASF_STREAM_TYPE} eq "Audio"',
|
||||
Name => 'AudioSampleRate',
|
||||
Format => 'int32u',
|
||||
},
|
||||
{
|
||||
Condition => '$self->{ASF_STREAM_TYPE} =~ /^(Video|JFIF|Degradable JPEG)$/',
|
||||
Name => 'ImageHeight',
|
||||
Format => 'int32u',
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::HeaderExtension = (
|
||||
PROCESS_PROC => \&ProcessASF,
|
||||
'14E6A5CB-C672-4332-8399-A96952065B5A' => 'ExtendedStreamProps',
|
||||
'A08649CF-4775-4670-8A16-6E35357566CD' => 'AdvancedMutualExcl',
|
||||
'D1465A40-5A79-4338-B71B-E36B8FD6C249' => 'GroupMutualExclusion',
|
||||
'D4FED15B-88D3-454F-81F0-ED5C45999E24' => 'StreamPrioritization',
|
||||
'A69609E6-517B-11D2-B6AF-00C04FD908E9' => 'BandwidthSharing',
|
||||
'7C4346A9-EFE0-4BFC-B229-393EDE415C85' => 'LanguageList',
|
||||
'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA' => {
|
||||
Name => 'Metadata',
|
||||
SubDirectory => {
|
||||
# have seen some tags same as ExtendedDescr, so use this table - PH
|
||||
TagTable => 'Image::ExifTool::ASF::ExtendedDescr',
|
||||
ProcessProc => \&ProcessMetadata,
|
||||
},
|
||||
},
|
||||
'44231C94-9498-49D1-A141-1D134E457054' => {
|
||||
Name => 'MetadataLibrary',
|
||||
SubDirectory => {
|
||||
# have seen some tags same as ExtendedDescr, so use this table - PH
|
||||
TagTable => 'Image::ExifTool::ASF::ExtendedDescr',
|
||||
ProcessProc => \&ProcessMetadata,
|
||||
},
|
||||
},
|
||||
'D6E229DF-35DA-11D1-9034-00A0C90349BE' => 'IndexParameters',
|
||||
'6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7' => 'TimecodeIndexParms',
|
||||
'75B22630-668E-11CF-A6D9-00AA0062CE6C' => 'Compatibility',
|
||||
'43058533-6981-49E6-9B74-AD12CB86D58C' => 'AdvancedContentEncryption',
|
||||
'ABD3D211-A9BA-11cf-8EE6-00C00C205365' => 'Reserved1',
|
||||
);
|
||||
|
||||
%Image::ExifTool::ASF::CodecList = (
|
||||
PROCESS_PROC => \&ProcessCodecList,
|
||||
VideoCodecName => {},
|
||||
VideoCodecDescription => {},
|
||||
AudioCodecName => {},
|
||||
AudioCodecDescription => {},
|
||||
OtherCodecName => {},
|
||||
OtherCodecDescription => {},
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Generate GUID from 16 bytes of binary data
|
||||
# Inputs: 0) data
|
||||
# Returns: GUID
|
||||
sub GetGUID($)
|
||||
{
|
||||
# must do some byte swapping
|
||||
my $val = shift;
|
||||
return $val unless length($val) == 16;
|
||||
my $buff = unpack('H*',pack('NnnNN',unpack('VvvNN',$val)));
|
||||
$buff =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/;
|
||||
return uc($buff);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process ASF content description
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessContentDescription($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
return 0 if $dirLen < 10;
|
||||
my @len = unpack('v5', $$dataPt);
|
||||
my $pos = 10;
|
||||
my $tag;
|
||||
foreach $tag (0..4) {
|
||||
my $len = shift @len;
|
||||
next unless $len;
|
||||
return 0 if $pos + $len > $dirLen;
|
||||
my $val = $et->Decode(substr($$dataPt,$pos,$len),'UCS2','II');
|
||||
$et->HandleTag($tagTablePtr, $tag, $val);
|
||||
$pos += $len;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process ASF content branding
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessContentBranding($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
return 0 if $dirLen < 40;
|
||||
# decode banner image type
|
||||
$et->HandleTag($tagTablePtr, 0, unpack('V', $$dataPt));
|
||||
# decode banner image, banner URL and copyright URL
|
||||
my $pos = 4;
|
||||
my $tag;
|
||||
foreach $tag (1..3) {
|
||||
return 0 if $pos + 4 > $dirLen;
|
||||
my $size = unpack("x${pos}V", $$dataPt);
|
||||
$pos += 4;
|
||||
next unless $size;
|
||||
return 0 if $pos + $size > $dirLen;
|
||||
my $val = substr($$dataPt, $pos, $size);
|
||||
$et->HandleTag($tagTablePtr, $tag, $val);
|
||||
$pos += $size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Read ASF value
|
||||
# Inputs: 0) ExifTool object ref, 1) data reference, 2) value offset,
|
||||
# 3) format number, 4) size
|
||||
# Returns: converted value
|
||||
sub ReadASF($$$$$)
|
||||
{
|
||||
my ($et, $dataPt, $pos, $format, $size) = @_;
|
||||
my @vals;
|
||||
if ($format == 0) { # unicode string
|
||||
$vals[0] = $et->Decode(substr($$dataPt,$pos,$size),'UCS2','II');
|
||||
} elsif ($format == 2) { # 4-byte boolean
|
||||
@vals = ReadValue($dataPt, $pos, 'int32u', undef, $size);
|
||||
foreach (@vals) {
|
||||
$_ = $_ ? 'True' : 'False';
|
||||
}
|
||||
} elsif ($format == 3) { # int32u
|
||||
@vals = ReadValue($dataPt, $pos, 'int32u', undef, $size);
|
||||
} elsif ($format == 4) { # int64u
|
||||
@vals = ReadValue($dataPt, $pos, 'int64u', undef, $size);
|
||||
} elsif ($format == 5) { # int16u
|
||||
@vals = ReadValue($dataPt, $pos, 'int16u', undef, $size);
|
||||
} else { # any other format (including 1, byte array): return raw data
|
||||
$vals[0] = substr($$dataPt,$pos,$size);
|
||||
}
|
||||
return join ' ', @vals;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process extended content description
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessExtendedContentDescription($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
return 0 if $dirLen < 2;
|
||||
my $count = Get16u($dataPt, 0);
|
||||
$et->VerboseDir($dirInfo, $count);
|
||||
my $pos = 2;
|
||||
my $i;
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
return 0 if $pos + 6 > $dirLen;
|
||||
my $nameLen = unpack("x${pos}v", $$dataPt);
|
||||
$pos += 2;
|
||||
return 0 if $pos + $nameLen + 4 > $dirLen;
|
||||
my $tag = Image::ExifTool::Decode(undef,substr($$dataPt,$pos,$nameLen),'UCS2','II','Latin');
|
||||
$tag =~ s/^WM\///; # remove leading "WM/"
|
||||
$pos += $nameLen;
|
||||
my ($dType, $dLen) = unpack("x${pos}v2", $$dataPt);
|
||||
$pos += 4;
|
||||
return 0 if $pos + $dLen > $dirLen;
|
||||
my $val = ReadASF($et,$dataPt,$pos,$dType,$dLen);
|
||||
$et->HandleTag($tagTablePtr, $tag, $val,
|
||||
DataPt => $dataPt,
|
||||
Start => $pos,
|
||||
Size => $dLen,
|
||||
);
|
||||
$pos += $dLen;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process ASF metadata library (similar to ProcessExtendedContentDescription above)
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessMetadata($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
return 0 if $dirLen < 2;
|
||||
my $count = Get16u($dataPt, 0);
|
||||
$et->VerboseDir($dirInfo, $count);
|
||||
my $pos = 2;
|
||||
my $i;
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
return 0 if $pos + 12 > $dirLen;
|
||||
my ($index, $stream, $nameLen, $dType, $dLen) = unpack("x${pos}v4V", $$dataPt);
|
||||
$pos += 12;
|
||||
return 0 if $pos + $nameLen + $dLen > $dirLen;
|
||||
my $tag = Image::ExifTool::Decode(undef,substr($$dataPt,$pos,$nameLen),'UCS2','II','Latin');
|
||||
$tag =~ s/^WM\///; # remove leading "WM/"
|
||||
$pos += $nameLen;
|
||||
my $val = ReadASF($et,$dataPt,$pos,$dType,$dLen);
|
||||
$et->HandleTag($tagTablePtr, $tag, $val,
|
||||
DataPt => $dataPt,
|
||||
Start => $pos,
|
||||
Size => $dLen,
|
||||
);
|
||||
$pos += $dLen;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process WM/Picture preview
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessPicture($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirStart = $$dirInfo{DirStart};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
return 0 unless $dirLen > 9;
|
||||
# extract picture type and length
|
||||
my ($type, $picLen) = unpack("x${dirStart}CV", $$dataPt);
|
||||
$et->VerboseDir('Picture');
|
||||
$et->HandleTag($tagTablePtr, 0, $type);
|
||||
# extract mime type and description strings (null-terminated unicode strings)
|
||||
my $n = $dirLen - 5 - $picLen;
|
||||
return 0 if $n & 0x01 or $n < 4;
|
||||
my $str = substr($$dataPt, $dirStart+5, $n);
|
||||
if ($str =~ /^((?:..)*?)\0\0((?:..)*?)\0\0/s) {
|
||||
my ($mime, $desc) = ($1, $2);
|
||||
$et->HandleTag($tagTablePtr, 1, $et->Decode($mime,'UCS2','II'));
|
||||
$et->HandleTag($tagTablePtr, 2, $et->Decode($desc,'UCS2','II')) if length $desc;
|
||||
}
|
||||
$et->HandleTag($tagTablePtr, 3, substr($$dataPt, $dirStart+5+$n, $picLen));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process codec list
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessCodecList($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dirLen = $$dirInfo{DirLen};
|
||||
return 0 if $dirLen < 20;
|
||||
my $count = Get32u($dataPt, 16);
|
||||
$et->VerboseDir($dirInfo, $count);
|
||||
my $pos = 20;
|
||||
my $i;
|
||||
my %codecType = ( 1 => 'Video', 2 => 'Audio' );
|
||||
for ($i=0; $i<$count; ++$i) {
|
||||
return 0 if $pos + 8 > $dirLen;
|
||||
my $type = ($codecType{Get16u($dataPt, $pos)} || 'Other') . 'Codec';
|
||||
# stupid Windows programmers: these lengths are in characters (others are in bytes)
|
||||
my $nameLen = Get16u($dataPt, $pos + 2) * 2;
|
||||
$pos += 4;
|
||||
return 0 if $pos + $nameLen + 2 > $dirLen;
|
||||
my $name = $et->Decode(substr($$dataPt,$pos,$nameLen),'UCS2','II');
|
||||
$et->HandleTag($tagTablePtr, "${type}Name", $name);
|
||||
my $descLen = Get16u($dataPt, $pos + $nameLen) * 2;
|
||||
$pos += $nameLen + 2;
|
||||
return 0 if $pos + $descLen + 2 > $dirLen;
|
||||
my $desc = $et->Decode(substr($$dataPt,$pos,$descLen),'UCS2','II');
|
||||
$et->HandleTag($tagTablePtr, "${type}Description", $desc);
|
||||
my $infoLen = Get16u($dataPt, $pos + $descLen);
|
||||
$pos += $descLen + 2 + $infoLen;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract information from a ASF file
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
|
||||
# Returns: 1 on success, 0 if this wasn't a valid ASF file
|
||||
sub ProcessASF($$;$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my $verbose = $et->Options('Verbose');
|
||||
my $rtnVal = 0;
|
||||
my $pos = 0;
|
||||
my ($buff, $err, @parentTable, @childEnd);
|
||||
|
||||
for (;;) {
|
||||
last unless $raf->Read($buff, 24) == 24;
|
||||
$pos += 24;
|
||||
my $tag = GetGUID(substr($buff,0,16));
|
||||
unless ($tagTablePtr) {
|
||||
# verify this is a valid ASF file
|
||||
last unless $tag eq '75B22630-668E-11CF-A6D9-00AA0062CE6C';
|
||||
my $fileType = $$et{FILE_EXT};
|
||||
$fileType = 'ASF' unless $fileType and $fileType =~ /^(ASF|WMV|WMA|DIVX)$/;
|
||||
$et->SetFileType($fileType);
|
||||
SetByteOrder('II');
|
||||
$tagTablePtr = GetTagTable('Image::ExifTool::ASF::Main');
|
||||
$rtnVal = 1;
|
||||
}
|
||||
my $size = Image::ExifTool::Get64u(\$buff, 16) - 24;
|
||||
if ($size < 0) {
|
||||
$err = 'Invalid ASF object size';
|
||||
last;
|
||||
}
|
||||
if ($size > 0x7fffffff) {
|
||||
if ($size > 0x7fffffff * 4294967296) {
|
||||
$err = 'Invalid ASF object size';
|
||||
} elsif ($et->Options('LargeFileSupport')) {
|
||||
if ($raf->Seek($size, 1)) {
|
||||
$et->VPrint(0, " Skipped large ASF object ($size bytes)\n");
|
||||
$pos += $size;
|
||||
next;
|
||||
}
|
||||
$err = 'Error seeking past large ASF object';
|
||||
} else {
|
||||
$err = 'Large ASF objects not supported (LargeFileSupport not set)';
|
||||
}
|
||||
last;
|
||||
}
|
||||
# go back to parent tag table if done with previous children
|
||||
if (@childEnd and $pos >= $childEnd[-1]) {
|
||||
pop @childEnd;
|
||||
$tagTablePtr = pop @parentTable;
|
||||
$$et{INDENT} = substr($$et{INDENT},0,-2);
|
||||
}
|
||||
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
|
||||
$verbose and $et->VerboseInfo($tag, $tagInfo);
|
||||
if ($tagInfo) {
|
||||
my $subdir = $$tagInfo{SubDirectory};
|
||||
if ($subdir) {
|
||||
my $subTable = GetTagTable($$subdir{TagTable});
|
||||
if ($$subTable{PROCESS_PROC} eq \&ProcessASF) {
|
||||
if (defined $$subdir{Size}) {
|
||||
my $s = $$subdir{Size};
|
||||
if ($verbose > 2) {
|
||||
$raf->Read($buff, $s) == $s or $err = 'Truncated file', last;
|
||||
$et->VerboseDump(\$buff);
|
||||
} elsif (not $raf->Seek($s, 1)) {
|
||||
$err = 'Seek error';
|
||||
last;
|
||||
}
|
||||
# continue processing linearly using subTable
|
||||
push @parentTable, $tagTablePtr;
|
||||
push @childEnd, $pos + $size;
|
||||
$tagTablePtr = $subTable;
|
||||
$pos += $$subdir{Size};
|
||||
if ($verbose) {
|
||||
$$et{INDENT} .= '| ';
|
||||
$et->VerboseDir($$tagInfo{Name});
|
||||
}
|
||||
next;
|
||||
}
|
||||
} elsif ($raf->Read($buff, $size) == $size) {
|
||||
my %subdirInfo = (
|
||||
DataPt => \$buff,
|
||||
DirStart => 0,
|
||||
DirLen => $size,
|
||||
DirName => $$tagInfo{Name},
|
||||
);
|
||||
$et->VerboseDump(\$buff) if $verbose > 2;
|
||||
unless ($et->ProcessDirectory(\%subdirInfo, $subTable, $$subdir{ProcessProc})) {
|
||||
$et->Warn("Error processing $$tagInfo{Name} directory");
|
||||
}
|
||||
$pos += $size;
|
||||
next;
|
||||
} else {
|
||||
$err = 'Unexpected end of file';
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($verbose > 2) {
|
||||
$raf->Read($buff, $size) == $size or $err = 'Truncated file', last;
|
||||
$et->VerboseDump(\$buff);
|
||||
} elsif (not $raf->Seek($size, 1)) { # skip the block
|
||||
$err = 'Seek error';
|
||||
last;
|
||||
}
|
||||
$pos += $size;
|
||||
}
|
||||
$err and $et->Warn($err);
|
||||
return $rtnVal;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::ASF - Read ASF/WMA/WMV meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains routines required by Image::ExifTool to extract
|
||||
information from Microsoft Advanced Systems Format (ASF) files, including
|
||||
Windows Media Audio (WMA) and Windows Media Video (WMV) files.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.microsoft.com/windows/windowsmedia/format/asfspec.aspx>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/ASF Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Apple.pm
|
||||
#
|
||||
# Description: Apple EXIF maker notes tags
|
||||
#
|
||||
# Revisions: 2013-09-13 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://www.photoinvestigator.co/blog/the-mystery-of-maker-apple-metadata/
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::Apple;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool::Exif;
|
||||
use Image::ExifTool::PLIST;
|
||||
|
||||
$VERSION = '1.04';
|
||||
|
||||
# Apple iPhone metadata (ref PH)
|
||||
%Image::ExifTool::Apple::Main = (
|
||||
WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
|
||||
CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
|
||||
WRITABLE => 1,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
NOTES => 'Tags extracted from the maker notes of iPhone images.',
|
||||
# 0x0001 - int32s: seen 0,1,2,3,4,9
|
||||
# 0x0002 - binary plist with a single data object of size 512 bytes (iPhone5s)
|
||||
0x0003 => {
|
||||
Name => 'RunTime', # (includes time plugged in, but not when suspended, ref 1)
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Apple::RunTime' },
|
||||
},
|
||||
# 0x0004 - int32s: normally 1, but 0 for low-light images
|
||||
# 0x0005 - int32s: seen values 113-247, and 100 for blank images
|
||||
# 0x0006 - int32s: seen values 27-258, and 20 for blank images
|
||||
# 0x0007 - int32s: seen 1
|
||||
0x0008 => { #1
|
||||
Name => 'AccelerationVector',
|
||||
Groups => { 2 => 'Camera' },
|
||||
Writable => 'rational64s',
|
||||
Count => 3,
|
||||
# Note: the directions are contrary to the Apple documentation (which have the
|
||||
# signs of all axes reversed -- apparently the Apple geeks aren't very good
|
||||
# with basic physics, and don't understand the concept of acceleration. See
|
||||
# http://nscookbook.com/2013/03/ios-programming-recipe-19-using-core-motion-to-access-gyro-and-accelerometer/
|
||||
# for one of the few correct descriptions of this). Note that this leads to
|
||||
# a left-handed coordinate system for acceleration.
|
||||
Notes => q{
|
||||
XYZ coordinates of the acceleration vector in units of g. As viewed from
|
||||
the front of the phone, positive X is toward the left side, positive Y is
|
||||
toward the bottom, and positive Z points into the face of the phone
|
||||
},
|
||||
},
|
||||
# 0x0009 - int32s: seen 19,275,531,4371
|
||||
0x000a => {
|
||||
Name => 'HDRImageType',
|
||||
Writable => 'int32s',
|
||||
PrintConv => {
|
||||
# 2 => ? (iPad mini 2)
|
||||
3 => 'HDR Image',
|
||||
4 => 'Original Image',
|
||||
},
|
||||
},
|
||||
0x000b => {
|
||||
Name => 'BurstUUID',
|
||||
Writable => 'string',
|
||||
Notes => 'unique ID for all images in a burst',
|
||||
},
|
||||
# 0x000c - rational64s[2]: eg) "0.1640625 0.19921875"
|
||||
# 0x000d - int32s: 0,1,6,20,24,32,40
|
||||
# 0x000e - int32s: 0,1,4,12 (Orienation? 0=landscape? 4=portrait? ref 1)
|
||||
# 0x000f - int32s: 2,3
|
||||
# 0x0010 - int32s: 1
|
||||
0x0011 => {
|
||||
Name => 'ContentIdentifier', #forum8750
|
||||
Writable => 'string',
|
||||
},
|
||||
# 0x0014 - int32s: 1,2,3,4,5 (iPhone 6s, iOS 6.1)
|
||||
0x0015 => {
|
||||
Name => 'ImageUniqueID',
|
||||
Writable => 'string',
|
||||
},
|
||||
# 0x0016 - string[29]: "AXZ6pMTOh2L+acSh4Kg630XCScoO\0"
|
||||
# 0x0017 - int32s: 0,8192
|
||||
# 0x0019 - int32s: 0,2,128
|
||||
# 0x001a - string[6]: "q825s\0"
|
||||
# 0x001f - int32s: 0
|
||||
);
|
||||
|
||||
# PLIST-format CMTime structure (ref PH)
|
||||
# (CMTime ref https://developer.apple.com/library/ios/documentation/CoreMedia/Reference/CMTime/Reference/reference.html)
|
||||
%Image::ExifTool::Apple::RunTime = (
|
||||
PROCESS_PROC => \&Image::ExifTool::PLIST::ProcessBinaryPLIST,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
NOTES => q{
|
||||
This PLIST-format information contains the elements of a CMTime structure
|
||||
representing the amount of time the phone has been running since the last
|
||||
boot, not including standby time.
|
||||
},
|
||||
timescale => { Name => 'RunTimeScale' }, # (seen 1000000000 --> ns)
|
||||
epoch => { Name => 'RunTimeEpoch' }, # (seen 0)
|
||||
value => { Name => 'RunTimeValue' }, # (should divide by RunTimeScale to get seconds)
|
||||
flags => {
|
||||
Name => 'RunTimeFlags',
|
||||
PrintConv => { BITMASK => {
|
||||
0 => 'Valid',
|
||||
1 => 'Has been rounded',
|
||||
2 => 'Positive infinity',
|
||||
3 => 'Negative infinity',
|
||||
4 => 'Indefinite',
|
||||
}},
|
||||
},
|
||||
);
|
||||
|
||||
# Apple composite tags
|
||||
%Image::ExifTool::Apple::Composite = (
|
||||
GROUPS => { 2 => 'Camera' },
|
||||
RunTimeSincePowerUp => {
|
||||
Require => {
|
||||
0 => 'Apple:RunTimeValue',
|
||||
1 => 'Apple:RunTimeScale',
|
||||
},
|
||||
ValueConv => '$val[1] ? $val[0] / $val[1] : undef',
|
||||
PrintConv => 'ConvertDuration($val)',
|
||||
},
|
||||
);
|
||||
|
||||
# add our composite tags
|
||||
Image::ExifTool::AddCompositeTags('Image::ExifTool::Apple');
|
||||
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::Apple - Apple EXIF maker notes tags
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is loaded automatically by Image::ExifTool when required.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to interpret
|
||||
Apple maker notes in EXIF information.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/Apple Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
@@ -1,317 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Audible.pm
|
||||
#
|
||||
# Description: Read metadata from Audible audio books
|
||||
#
|
||||
# Revisions: 2015/04/05 - P. Harvey Created
|
||||
#
|
||||
# References: 1) https://github.com/jteeuwen/audible
|
||||
# 2) https://code.google.com/p/pyaudibletags/
|
||||
# 3) http://wiki.multimedia.cx/index.php?title=Audible_Audio
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::Audible;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.02';
|
||||
|
||||
sub ProcessAudible_meta($$$);
|
||||
sub ProcessAudible_cvrx($$$);
|
||||
|
||||
%Image::ExifTool::Audible::Main = (
|
||||
GROUPS => { 2 => 'Audio' },
|
||||
NOTES => q{
|
||||
ExifTool will extract any information found in the metadata dictionary of
|
||||
Audible .AA files, even if not listed in the table below.
|
||||
},
|
||||
# tags found in the metadata dictionary (chunk 2)
|
||||
pubdate => { Name => 'PublishDate', Groups => { 2 => 'Time' } },
|
||||
pub_date_start => { Name => 'PublishDateStart', Groups => { 2 => 'Time' } },
|
||||
author => { Name => 'Author', Groups => { 2 => 'Author' } },
|
||||
copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } },
|
||||
# also seen (ref PH):
|
||||
# product_id, parent_id, title, provider, narrator, price, description,
|
||||
# long_description, short_title, is_aggregation, title_id, codec, HeaderSeed,
|
||||
# EncryptedBlocks, HeaderKey, license_list, CPUType, license_count, <12 hex digits>,
|
||||
# parent_short_title, parent_title, aggregation_id, short_description, user_alias
|
||||
|
||||
# information extracted from other chunks
|
||||
_chapter_count => { Name => 'ChapterCount' }, # from chunk 6
|
||||
_cover_art => { # from chunk 11
|
||||
Name => 'CoverArt',
|
||||
Groups => { 2 => 'Preview' },
|
||||
Binary => 1,
|
||||
},
|
||||
);
|
||||
|
||||
# 'tags' atoms observed in Audible .m4b audio books (ref PH)
|
||||
%Image::ExifTool::Audible::tags = (
|
||||
GROUPS => { 0 => 'QuickTime', 2 => 'Audio' },
|
||||
NOTES => 'Information found in "tags" atom of Audible M4B audio books.',
|
||||
meta => {
|
||||
Name => 'Audible_meta',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Audible::meta' },
|
||||
},
|
||||
cvrx => {
|
||||
Name => 'Audible_cvrx',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Audible::cvrx' },
|
||||
},
|
||||
tseg => {
|
||||
Name => 'Audible_tseg',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Audible::tseg' },
|
||||
},
|
||||
);
|
||||
|
||||
# 'meta' information observed in Audible .m4b audio books (ref PH)
|
||||
%Image::ExifTool::Audible::meta = (
|
||||
PROCESS_PROC => \&ProcessAudible_meta,
|
||||
GROUPS => { 0 => 'QuickTime', 2 => 'Audio' },
|
||||
NOTES => 'Information found in Audible M4B "meta" atom.',
|
||||
Album => 'Album',
|
||||
ALBUMARTIST => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } },
|
||||
Artist => { Name => 'Artist', Groups => { 2 => 'Author' } },
|
||||
Comment => 'Comment',
|
||||
Genre => 'Genre',
|
||||
itunesmediatype => { Name => 'iTunesMediaType', Description => 'iTunes Media Type' },
|
||||
SUBTITLE => 'Subtitle',
|
||||
Title => 'Title',
|
||||
TOOL => 'CreatorTool',
|
||||
Year => { Name => 'Year', Groups => { 2 => 'Time' } },
|
||||
track => 'ChapterName', # (found in 'meta' of 'tseg' atom)
|
||||
);
|
||||
|
||||
# 'cvrx' information observed in Audible .m4b audio books (ref PH)
|
||||
%Image::ExifTool::Audible::cvrx = (
|
||||
PROCESS_PROC => \&ProcessAudible_cvrx,
|
||||
GROUPS => { 0 => 'QuickTime', 2 => 'Audio' },
|
||||
NOTES => 'Audible cover art information in M4B audio books.',
|
||||
VARS => { NO_ID => 1 },
|
||||
CoverArtType => 'CoverArtType',
|
||||
CoverArt => {
|
||||
Name => 'CoverArt',
|
||||
Groups => { 2 => 'Preview' },
|
||||
Binary => 1,
|
||||
},
|
||||
);
|
||||
|
||||
# 'tseg' information observed in Audible .m4b audio books (ref PH)
|
||||
%Image::ExifTool::Audible::tseg = (
|
||||
GROUPS => { 0 => 'QuickTime', 2 => 'Audio' },
|
||||
tshd => {
|
||||
Name => 'ChapterNumber',
|
||||
Format => 'int32u',
|
||||
ValueConv => '$val + 1', # start counting from 1
|
||||
},
|
||||
meta => {
|
||||
Name => 'Audible_meta2',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Audible::meta' },
|
||||
},
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process Audible 'meta' tags from M4B files (ref PH)
|
||||
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
||||
# Returns: 1 on success
|
||||
sub ProcessAudible_meta($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dataPos = $$dirInfo{DataPos};
|
||||
my $dirLen = length $$dataPt;
|
||||
return 0 if $dirLen < 4;
|
||||
my $num = Get32u($dataPt, 0);
|
||||
$et->VerboseDir('Audible_meta', $num);
|
||||
my $pos = 4;
|
||||
my $index;
|
||||
for ($index=0; $index<$num; ++$index) {
|
||||
last if $pos + 3 > $dirLen;
|
||||
my $unk = Get8u($dataPt, $pos); # ? (0x80 or 0x00)
|
||||
last unless $unk eq 0x80 or $unk eq 0x00;
|
||||
my $len = Get16u($dataPt, $pos + 1); # tag length
|
||||
$pos += 3;
|
||||
last if $pos + $len + 6 > $dirLen or not $len;
|
||||
my $tag = substr($$dataPt, $pos, $len); # tag ID
|
||||
my $ver = Get16u($dataPt, $pos + $len); # version?
|
||||
last unless $ver eq 0x0001;
|
||||
my $size = Get32u($dataPt, $pos + $len + 2);# data size
|
||||
$pos += $len + 6;
|
||||
last if $pos + $size > $dirLen;
|
||||
my $val = $et->Decode(substr($$dataPt, $pos, $size), 'UTF8');
|
||||
unless ($$tagTablePtr{$tag}) {
|
||||
my $name = Image::ExifTool::MakeTagName(($tag =~ /[a-z]/) ? $tag : lc($tag));
|
||||
AddTagToTable($tagTablePtr, $tag, { Name => $name });
|
||||
}
|
||||
$et->HandleTag($tagTablePtr, $tag, $val,
|
||||
DataPt => $dataPt,
|
||||
DataPos => $dataPos,
|
||||
Start => $pos,
|
||||
Size => $size,
|
||||
Index => $index,
|
||||
);
|
||||
$pos += $size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process Audible 'cvrx' cover art atom from M4B files (ref PH)
|
||||
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
||||
# Returns: 1 on success
|
||||
sub ProcessAudible_cvrx($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $dataPt = $$dirInfo{DataPt};
|
||||
my $dataPos = $$dirInfo{DataPos};
|
||||
my $dirLen = length $$dataPt;
|
||||
return 0 if 0x0a > $dirLen;
|
||||
my $len = Get16u($dataPt, 0x08);
|
||||
return 0 if 0x0a + $len + 6 > $dirLen;
|
||||
my $size = Get32u($dataPt, 0x0a + $len + 2);
|
||||
return 0 if 0x0a + $len + 6 + $size > $dirLen;
|
||||
$et->VerboseDir('Audible_cvrx', undef, $dirLen);
|
||||
$et->HandleTag($tagTablePtr, 'CoverArtType', undef,
|
||||
DataPt => $dataPt,
|
||||
DataPos => $dataPos,
|
||||
Start => 0x0a,
|
||||
Size => $len,
|
||||
);
|
||||
$et->HandleTag($tagTablePtr, 'CoverArt', undef,
|
||||
DataPt => $dataPt,
|
||||
DataPos => $dataPos,
|
||||
Start => 0x0a + $len + 6,
|
||||
Size => $size,
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Read information from an Audible .AA file
|
||||
# Inputs: 0) ExifTool ref, 1) dirInfo ref
|
||||
# Returns: 1 on success, 0 if this wasn't a valid AA file
|
||||
sub ProcessAA($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my ($buff, $toc, $entry, $i);
|
||||
|
||||
# check magic number
|
||||
return 0 unless $raf->Read($buff, 16) == 16 and $buff=~/^.{4}\x57\x90\x75\x36/s;
|
||||
# check file size
|
||||
if (defined $$et{VALUE}{FileSize}) {
|
||||
# first 4 bytes of the file should be the filesize
|
||||
unpack('N', $buff) == $$et{VALUE}{FileSize} or return 0;
|
||||
}
|
||||
$et->SetFileType();
|
||||
SetByteOrder('MM');
|
||||
my $bytes = 12 * Get32u(\$buff, 8); # table of contents size in bytes
|
||||
$bytes > 0xc00 and $et->Warn('Invalid TOC'), return 1;
|
||||
# read the table of contents
|
||||
$raf->Read($toc, $bytes) == $bytes or $et->Warn('Truncated TOC'), return 1;
|
||||
my $tagTablePtr = GetTagTable('Image::ExifTool::Audible::Main');
|
||||
# parse table of contents (in $toc)
|
||||
for ($entry=0; $entry<$bytes; $entry+=12) {
|
||||
my $type = Get32u(\$toc, $entry);
|
||||
next unless $type == 2 or $type == 6 or $type == 11;
|
||||
my $offset = Get32u(\$toc, $entry + 4);
|
||||
my $length = Get32u(\$toc, $entry + 8) or next;
|
||||
$raf->Seek($offset, 0) or $et->Warn("Chunk $type seek error"), last;
|
||||
if ($type == 6) { # offset table
|
||||
next if $length < 4 or $raf->Read($buff, 4) != 4; # only read the chapter count
|
||||
$et->HandleTag($tagTablePtr, '_chapter_count', Get32u(\$buff, 0));
|
||||
next;
|
||||
}
|
||||
# read the chunk
|
||||
$length > 100000000 and $et->Warn("Chunk $type too big"), next;
|
||||
$raf->Read($buff, $length) == $length or $et->Warn("Chunk $type read error"), last;
|
||||
if ($type == 11) { # cover art
|
||||
next if $length < 8;
|
||||
my $len = Get32u(\$buff, 0);
|
||||
my $off = Get32u(\$buff, 4);
|
||||
next if $off < $offset + 8 or $off - $offset + $len > $length;
|
||||
$et->HandleTag($tagTablePtr, '_cover_art', substr($buff, $off-$offset, $len));
|
||||
next;
|
||||
}
|
||||
# parse metadata dictionary (in $buff)
|
||||
$length < 4 and $et->Warn('Bad dictionary'), next;
|
||||
my $num = Get32u(\$buff, 0);
|
||||
$num > 0x200 and $et->Warn('Bad dictionary count'), next;
|
||||
my $pos = 4; # dictionary starts immediately after count
|
||||
require Image::ExifTool::HTML; # (for UnescapeHTML)
|
||||
$et->VerboseDir('Audible Metadata', $num);
|
||||
for ($i=0; $i<$num; ++$i) {
|
||||
my $tagPos = $pos + 9; # position of tag string
|
||||
$tagPos > $length and $et->Warn('Truncated dictionary'), last;
|
||||
# (1 unknown byte ignored at start of each dictionary entry)
|
||||
my $tagLen = Get32u(\$buff, $pos + 1); # tag string length
|
||||
my $valLen = Get32u(\$buff, $pos + 5); # value string length
|
||||
my $valPos = $tagPos + $tagLen; # position of value string
|
||||
my $nxtPos = $valPos + $valLen; # position of next entry
|
||||
$nxtPos > $length and $et->Warn('Bad dictionary entry'), last;
|
||||
my $tag = substr($buff, $tagPos, $tagLen);
|
||||
my $val = substr($buff, $valPos, $valLen);
|
||||
unless ($$tagTablePtr{$tag}) {
|
||||
my $name = Image::ExifTool::MakeTagName($tag);
|
||||
$name =~ s/_(.)/\U$1/g; # change from underscore-separated to mixed case
|
||||
AddTagToTable($tagTablePtr, $tag, { Name => $name });
|
||||
}
|
||||
# unescape HTML character references and convert from UTF-8
|
||||
$val = $et->Decode(Image::ExifTool::HTML::UnescapeHTML($val), 'UTF8');
|
||||
$et->HandleTag($tagTablePtr, $tag, $val,
|
||||
DataPos => $offset,
|
||||
DataPt => \$buff,
|
||||
Start => $valPos,
|
||||
Size => $valLen,
|
||||
Index => $i,
|
||||
);
|
||||
$pos = $nxtPos; # step to next dictionary entry
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::Audible - Read meta information from Audible audio books
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to read meta
|
||||
information from Audible audio books.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<https://github.com/jteeuwen/audible>
|
||||
|
||||
=item L<https://code.google.com/p/pyaudibletags/>
|
||||
|
||||
=item L<http://wiki.multimedia.cx/index.php?title=Audible_Audio>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/Audible Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,361 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: BMP.pm
|
||||
#
|
||||
# Description: Read BMP meta information
|
||||
#
|
||||
# Revisions: 07/16/2005 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
|
||||
# 2) http://www.fourcc.org/rgb.php
|
||||
# 3) https://msdn.microsoft.com/en-us/library/dd183381(v=vs.85).aspx
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::BMP;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.09';
|
||||
|
||||
# conversions for fixed-point 2.30 format values
|
||||
my %fixed2_30 = (
|
||||
ValueConv => q{
|
||||
my @a = split ' ', $val;
|
||||
$_ /= 0x40000000 foreach @a;
|
||||
"@a";
|
||||
},
|
||||
PrintConv => q{
|
||||
my @a = split ' ', $val;
|
||||
$_ = sprintf('%.6f', $_) foreach @a;
|
||||
"@a";
|
||||
},
|
||||
);
|
||||
|
||||
# BMP chunks
|
||||
%Image::ExifTool::BMP::Main = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
|
||||
NOTES => q{
|
||||
There really isn't much meta information in a BMP file as such, just a bit
|
||||
of image related information.
|
||||
},
|
||||
0 => {
|
||||
Name => 'BMPVersion',
|
||||
Format => 'int32u',
|
||||
Notes => q{
|
||||
this is actually the size of the BMP header, but used to determine the BMP
|
||||
version
|
||||
},
|
||||
RawConv => '$$self{BMPVersion} = $val',
|
||||
PrintConv => {
|
||||
40 => 'Windows V3',
|
||||
68 => 'AVI BMP structure?', #PH (seen in AVI movies from some Casio and Nikon cameras)
|
||||
108 => 'Windows V4',
|
||||
124 => 'Windows V5',
|
||||
},
|
||||
},
|
||||
4 => {
|
||||
Name => 'ImageWidth',
|
||||
Format => 'int32u',
|
||||
},
|
||||
8 => {
|
||||
Name => 'ImageHeight',
|
||||
Format => 'int32s', # (negative when stored in top-to-bottom order)
|
||||
ValueConv => 'abs($val)',
|
||||
},
|
||||
12 => {
|
||||
Name => 'Planes',
|
||||
Format => 'int16u',
|
||||
# values: 0,1,4,8,16,24,32
|
||||
},
|
||||
14 => {
|
||||
Name => 'BitDepth',
|
||||
Format => 'int16u',
|
||||
},
|
||||
16 => {
|
||||
Name => 'Compression',
|
||||
Format => 'int32u',
|
||||
RawConv => '$$self{BMPCompression} = $val',
|
||||
# (formatted as string[4] for some values in AVI images)
|
||||
ValueConv => '$val > 256 ? unpack("A4",pack("V",$val)) : $val',
|
||||
PrintConv => {
|
||||
0 => 'None',
|
||||
1 => '8-Bit RLE',
|
||||
2 => '4-Bit RLE',
|
||||
3 => 'Bitfields',
|
||||
4 => 'JPEG', #2
|
||||
5 => 'PNG', #2
|
||||
# pass through ASCII video compression codec ID's
|
||||
OTHER => sub {
|
||||
my $val = shift;
|
||||
# convert non-ascii characters
|
||||
$val =~ s/([\0-\x1f\x7f-\xff])/sprintf('\\x%.2x',ord $1)/eg;
|
||||
return $val;
|
||||
},
|
||||
},
|
||||
},
|
||||
20 => {
|
||||
Name => 'ImageLength',
|
||||
Format => 'int32u',
|
||||
RawConv => '$$self{BMPImageLength} = $val',
|
||||
},
|
||||
24 => {
|
||||
Name => 'PixelsPerMeterX',
|
||||
Format => 'int32u',
|
||||
},
|
||||
28 => {
|
||||
Name => 'PixelsPerMeterY',
|
||||
Format => 'int32u',
|
||||
},
|
||||
32 => {
|
||||
Name => 'NumColors',
|
||||
Format => 'int32u',
|
||||
PrintConv => '$val ? $val : "Use BitDepth"',
|
||||
},
|
||||
36 => {
|
||||
Name => 'NumImportantColors',
|
||||
Format => 'int32u',
|
||||
Hook => '$varSize += $size if $$self{BMPVersion} == 68', # (the rest is invalid for AVI BMP's)
|
||||
PrintConv => '$val ? $val : "All"',
|
||||
},
|
||||
40 => {
|
||||
Name => 'RedMask',
|
||||
Format => 'int32u',
|
||||
PrintConv => 'sprintf("0x%.8x",$val)',
|
||||
},
|
||||
44 => {
|
||||
Name => 'GreenMask',
|
||||
Format => 'int32u',
|
||||
PrintConv => 'sprintf("0x%.8x",$val)',
|
||||
},
|
||||
48 => {
|
||||
Name => 'BlueMask',
|
||||
Format => 'int32u',
|
||||
PrintConv => 'sprintf("0x%.8x",$val)',
|
||||
},
|
||||
52 => {
|
||||
Name => 'AlphaMask',
|
||||
Format => 'int32u',
|
||||
PrintConv => 'sprintf("0x%.8x",$val)',
|
||||
},
|
||||
56 => {
|
||||
Name => 'ColorSpace',
|
||||
Format => 'undef[4]',
|
||||
RawConv => '$$self{BMPColorSpace} = $val =~ /\0/ ? Get32u(\$val, 0) : pack("N",unpack("V",$val))',
|
||||
PrintConv => {
|
||||
0 => 'Calibrated RGB',
|
||||
1 => 'Device RGB',
|
||||
2 => 'Device CMYK',
|
||||
LINK => 'Linked Color Profile',
|
||||
MBED => 'Embedded Color Profile',
|
||||
sRGB => 'sRGB',
|
||||
'Win ' => 'Windows Color Space',
|
||||
},
|
||||
},
|
||||
60 => {
|
||||
Name => 'RedEndpoint',
|
||||
Condition => '$$self{BMPColorSpace} eq "0"',
|
||||
Format => 'int32u[3]',
|
||||
%fixed2_30,
|
||||
},
|
||||
72 => {
|
||||
Name => 'GreenEndpoint',
|
||||
Condition => '$$self{BMPColorSpace} eq "0"',
|
||||
Format => 'int32u[3]',
|
||||
%fixed2_30,
|
||||
},
|
||||
84 => {
|
||||
Name => 'BlueEndpoint',
|
||||
Condition => '$$self{BMPColorSpace} eq "0"',
|
||||
Format => 'int32u[3]',
|
||||
%fixed2_30,
|
||||
},
|
||||
96 => {
|
||||
Name => 'GammaRed',
|
||||
Condition => '$$self{BMPColorSpace} eq "0"',
|
||||
Format => 'fixed32u',
|
||||
},
|
||||
100 => {
|
||||
Name => 'GammaGreen',
|
||||
Condition => '$$self{BMPColorSpace} eq "0"',
|
||||
Format => 'fixed32u',
|
||||
},
|
||||
104 => {
|
||||
Name => 'GammaBlue',
|
||||
Condition => '$$self{BMPColorSpace} eq "0"',
|
||||
Format => 'fixed32u',
|
||||
},
|
||||
108 => {
|
||||
Name => 'RenderingIntent',
|
||||
Format => 'int32u',
|
||||
PrintConv => {
|
||||
1 => 'Graphic (LCS_GM_BUSINESS)',
|
||||
2 => 'Proof (LCS_GM_GRAPHICS)',
|
||||
4 => 'Picture (LCS_GM_IMAGES)',
|
||||
8 => 'Absolute Colorimetric (LCS_GM_ABS_COLORIMETRIC)',
|
||||
},
|
||||
},
|
||||
112 => {
|
||||
Name => 'ProfileDataOffset',
|
||||
Condition => '$$self{BMPColorSpace} eq "LINK" or $$self{BMPColorSpace} eq "MBED"',
|
||||
Format => 'int32u',
|
||||
RawConv => '$$self{BMPProfileOffset} = $val',
|
||||
},
|
||||
116 => {
|
||||
Name => 'ProfileSize',
|
||||
Condition => '$$self{BMPColorSpace} eq "LINK" or $$self{BMPColorSpace} eq "MBED"',
|
||||
Format => 'int32u',
|
||||
RawConv => '$$self{BMPProfileSize} = $val',
|
||||
},
|
||||
# 120 - reserved
|
||||
);
|
||||
|
||||
# OS/2 12-byte bitmap header (ref http://www.fileformat.info/format/bmp/egff.htm)
|
||||
%Image::ExifTool::BMP::OS2 = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
|
||||
NOTES => 'Information extracted from OS/2-format BMP images.',
|
||||
0 => {
|
||||
Name => 'BMPVersion',
|
||||
Format => 'int32u',
|
||||
Notes => 'again, the header size is used to determine the BMP version',
|
||||
PrintConv => {
|
||||
12 => 'OS/2 V1',
|
||||
64 => 'OS/2 V2',
|
||||
},
|
||||
},
|
||||
4 => { Name => 'ImageWidth', Format => 'int16u' },
|
||||
6 => { Name => 'ImageHeight', Format => 'int16u' },
|
||||
8 => { Name => 'Planes', Format => 'int16u' },
|
||||
10 => { Name => 'BitDepth', Format => 'int16u' },
|
||||
);
|
||||
|
||||
%Image::ExifTool::BMP::Extra = (
|
||||
GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
|
||||
NOTES => 'Extra information extracted from some BMP images.',
|
||||
VARS => { NO_ID => 1 },
|
||||
LinkedProfileName => { },
|
||||
ICC_Profile => { SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' } },
|
||||
EmbeddedJPG => {
|
||||
Groups => { 2 => 'Preview' },
|
||||
Binary => 1,
|
||||
},
|
||||
EmbeddedPNG => {
|
||||
Groups => { 2 => 'Preview' },
|
||||
Binary => 1,
|
||||
},
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract EXIF information from a BMP image
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# Returns: 1 on success, 0 if this wasn't a valid BMP file
|
||||
sub ProcessBMP($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my ($buff, $tagTablePtr);
|
||||
|
||||
# verify this is a valid BMP file
|
||||
return 0 unless $raf->Read($buff, 18) == 18;
|
||||
return 0 unless $buff =~ /^BM/;
|
||||
SetByteOrder('II');
|
||||
my $len = Get32u(\$buff, 14);
|
||||
# len = v1:12, v4:108, v5:124
|
||||
return 0 unless $len == 12 or $len == 16 or ($len >= 40 and $len < 1000000);
|
||||
return 0 unless $raf->Seek(-4, 1) and $raf->Read($buff, $len) == $len;
|
||||
$et->SetFileType(); # set the FileType tag
|
||||
#
|
||||
# process the BMP header
|
||||
#
|
||||
my %dirInfo = (
|
||||
DataPt => \$buff,
|
||||
DirStart => 0,
|
||||
DirLen => length($buff),
|
||||
);
|
||||
if ($len == 12 or $len == 16 or $len == 64) { # old OS/2 format BMP
|
||||
$tagTablePtr = GetTagTable('Image::ExifTool::BMP::OS2');
|
||||
} else {
|
||||
$tagTablePtr = GetTagTable('Image::ExifTool::BMP::Main');
|
||||
}
|
||||
$et->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
||||
#
|
||||
# extract any embedded images
|
||||
#
|
||||
my $extraTable = GetTagTable('Image::ExifTool::BMP::Extra');
|
||||
if ($$et{BMPCompression} and $$et{BMPImageLength} and
|
||||
($$et{BMPCompression} == 4 or $$et{BMPCompression} == 5))
|
||||
{
|
||||
my $tag = $$et{BMPCompression} == 4 ? 'EmbeddedJPG' : 'EmbeddedPNG';
|
||||
my $val = $et->ExtractBinary($raf->Tell(), $$et{BMPImageLength}, $tag);
|
||||
if ($val) {
|
||||
$et->HandleTag($extraTable, $tag, $val);
|
||||
}
|
||||
}
|
||||
#
|
||||
# process profile data if it exists (v5 header only)
|
||||
#
|
||||
if ($len == 124 and $$et{BMPProfileOffset}) {
|
||||
my $pos = $$et{BMPProfileOffset} + 14; # (note the 14-byte shift!)
|
||||
my $size = $$et{BMPProfileSize};
|
||||
if ($raf->Seek($pos, 0) and $raf->Read($buff, $size) == $size) {
|
||||
my $tag;
|
||||
if ($$et{BMPColorSpace} eq 'LINK') {
|
||||
$buff =~ s/\0+$//; # remove null terminator(s)
|
||||
$buff = $et->Decode($buff, 'Latin'); # convert from Latin
|
||||
$tag = 'LinkedProfileName';
|
||||
} else {
|
||||
$tag = 'ICC_Profile';
|
||||
}
|
||||
$et->HandleTag($extraTable, $tag => $buff, Size => $size, DataPos => $pos);
|
||||
} else {
|
||||
$et->Warn('Error loading profile data', 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::BMP - Read BMP meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to read BMP
|
||||
(Windows Bitmap) images.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html>
|
||||
|
||||
=item L<http://www.fourcc.org/rgb.php>
|
||||
|
||||
=item L<https://msdn.microsoft.com/en-us/library/dd183381(v=vs.85).aspx>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/BMP Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: BPG.pm
|
||||
#
|
||||
# Description: Read BPG meta information
|
||||
#
|
||||
# Revisions: 2016-07-05 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://bellard.org/bpg/
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::BPG;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.00';
|
||||
|
||||
# BPG information
|
||||
%Image::ExifTool::BPG::Main = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
|
||||
NOTES => q{
|
||||
The information listed below is extracted from BPG (Better Portable
|
||||
Graphics) images. See L<http://bellard.org/bpg/> for the specification.
|
||||
},
|
||||
4 => {
|
||||
Name => 'PixelFormat',
|
||||
Format => 'int16u',
|
||||
Mask => 0xe000,
|
||||
PrintConv => {
|
||||
0x0000 => 'Grayscale',
|
||||
0x2000 => '4:2:0 (chroma at 0.5, 0.5)',
|
||||
0x4000 => '4:2:2 (chroma at 0.5, 0)',
|
||||
0x6000 => '4:4:4',
|
||||
0x8000 => '4:2:0 (chroma at 0, 0.5)',
|
||||
0xa000 => '4:2:2 (chroma at 0, 0)',
|
||||
},
|
||||
},
|
||||
4.1 => {
|
||||
Name => 'Alpha',
|
||||
Format => 'int16u',
|
||||
Mask => 0x1004,
|
||||
PrintConv => {
|
||||
0x0000 => 'No Alpha Plane',
|
||||
0x1000 => 'Alpha Exists (color not premultiplied)',
|
||||
0x1004 => 'Alpha Exists (color premultiplied)',
|
||||
0x0004 => 'Alpha Exists (W color component)',
|
||||
},
|
||||
},
|
||||
4.2 => {
|
||||
Name => 'BitDepth',
|
||||
Format => 'int16u',
|
||||
Mask => 0x0f00,
|
||||
ValueConv => '($val >> 8) + 8',
|
||||
},
|
||||
4.3 => {
|
||||
Name => 'ColorSpace',
|
||||
Format => 'int16u',
|
||||
Mask => 0x00f0,
|
||||
PrintConv => {
|
||||
0x0000 => 'YCbCr (BT 601)',
|
||||
0x0010 => 'RGB',
|
||||
0x0020 => 'YCgCo',
|
||||
0x0030 => 'YCbCr (BT 709)',
|
||||
0x0040 => 'YCbCr (BT 2020)',
|
||||
0x0050 => 'BT 2020 Constant Luminance',
|
||||
},
|
||||
},
|
||||
4.4 => {
|
||||
Name => 'Flags',
|
||||
Format => 'int16u',
|
||||
Mask => 0x000b,
|
||||
PrintConv => { BITMASK => {
|
||||
0 => 'Animation',
|
||||
1 => 'Limited Range',
|
||||
3 => 'Extension Present',
|
||||
}},
|
||||
},
|
||||
6 => { Name => 'ImageWidth', Format => 'var_ue7' },
|
||||
7 => { Name => 'ImageHeight', Format => 'var_ue7' },
|
||||
# length of image data or 0 to EOF
|
||||
# (must be decoded so we know where the extension data starts)
|
||||
8 => { Name => 'ImageLength', Format => 'var_ue7' },
|
||||
);
|
||||
|
||||
%Image::ExifTool::BPG::Extensions = (
|
||||
GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' },
|
||||
VARS => { ALPHA_FIRST => 1 },
|
||||
1 => {
|
||||
Name => 'EXIF',
|
||||
SubDirectory => {
|
||||
TagTable => 'Image::ExifTool::Exif::Main',
|
||||
ProcessProc => \&Image::ExifTool::ProcessTIFF,
|
||||
},
|
||||
},
|
||||
2 => {
|
||||
Name => 'ICC_Profile',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
|
||||
},
|
||||
3 => {
|
||||
Name => 'XMP',
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
||||
},
|
||||
4 => {
|
||||
Name => 'ThumbnailBPG',
|
||||
Binary => 1,
|
||||
},
|
||||
5 => {
|
||||
Name => 'AnimationControl',
|
||||
Binary => 1,
|
||||
Unknown => 1,
|
||||
},
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Get ue7 integer from binary data (max 32 bits)
|
||||
# Inputs: 0) data ref, 1) location in data (undef for 0)
|
||||
# Returns: 0) ue7 as integer or undef on error, 1) length of ue7 in bytes
|
||||
sub Get_ue7($;$)
|
||||
{
|
||||
my $dataPt = shift;
|
||||
my $pos = shift || 0;
|
||||
my $size = length $$dataPt;
|
||||
my $val = 0;
|
||||
my $i;
|
||||
for ($i=0; ; ) {
|
||||
return() if $pos+$i >= $size or $i >= 5;
|
||||
my $byte = Get8u($dataPt, $pos + $i);
|
||||
$val = ($val << 7) | ($byte & 0x7f);
|
||||
unless ($byte & 0x80) {
|
||||
return() if $i == 4 and $byte & 0x70; # error if bits 32-34 are set
|
||||
last; # this was the last byte
|
||||
}
|
||||
return() if $i == 0 and $byte == 0x80; # error if first byte is 0x80
|
||||
++$i; # step to the next byte
|
||||
}
|
||||
return($val, $i+1);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract EXIF information from a BPG image
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# Returns: 1 on success, 0 if this wasn't a valid BPG file
|
||||
sub ProcessBPG($$)
|
||||
{
|
||||
local $_;
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my ($buff, $size, $n, $len, $pos);
|
||||
|
||||
# verify this is a valid BPG file
|
||||
return 0 unless $raf->Read($buff, 21) == 21; # (21 bytes is maximum header length)
|
||||
return 0 unless $buff =~ /^BPG\xfb/;
|
||||
$et->SetFileType(); # set the FileType tag
|
||||
|
||||
SetByteOrder('MM');
|
||||
my %dirInfo = (
|
||||
DataPt => \$buff,
|
||||
DirStart => 0,
|
||||
DirLen => length($buff),
|
||||
VarFormatData => [ ],
|
||||
);
|
||||
$et->ProcessDirectory(\%dirInfo, GetTagTable('Image::ExifTool::BPG::Main'));
|
||||
|
||||
return 1 unless $$et{VALUE}{Flags} & 0x0008; # all done unless extension flag is set
|
||||
|
||||
# add varSize from last entry in VarFormatData to determine
|
||||
# the current read position in the file
|
||||
my $dataPos = 9 + $dirInfo{VarFormatData}[-1][1];
|
||||
# read extension length
|
||||
unless ($raf->Seek($dataPos, 0) and $raf->Read($buff, 5) == 5) {
|
||||
$et->Warn('Missing BPG extension data');
|
||||
return 1;
|
||||
}
|
||||
($size, $n) = Get_ue7(\$buff);
|
||||
defined $size or $et->Warn('Corrupted BPG extension length'), return 1;
|
||||
$dataPos += $n;
|
||||
$size > 10000000 and $et->Warn('BPG extension is too large'), return 1;
|
||||
unless ($raf->Seek($dataPos, 0) and $raf->Read($buff, $size) == $size) {
|
||||
$et->Warn('Truncated BPG extension');
|
||||
return 1;
|
||||
}
|
||||
my $tagTablePtr = GetTagTable('Image::ExifTool::BPG::Extensions');
|
||||
# loop through the individual extensions
|
||||
for ($pos=0; $pos<$size; $pos+=$len) {
|
||||
my $type = Get8u(\$buff, $pos);
|
||||
# get length of this extension
|
||||
($len, $n) = Get_ue7(\$buff, ++$pos);
|
||||
defined $len or $et->Warn('Corrupted BPG extension'), last;
|
||||
$pos += $n; # point to start of data for this extension
|
||||
$pos + $len > $size and $et->Warn('Invalid BPG extension size'), last;
|
||||
$$tagTablePtr{$type} or $et->Warn("Unrecognized BPG extension $type ($len bytes)", 1), next;
|
||||
# libbpg (in my opinion) incorrectly copies the padding byte after the
|
||||
# "EXIF\0" APP1 header to the start of the BPG EXIF extension, so issue a
|
||||
# minor warning and ignore the padding if we find it before the TIFF header
|
||||
if ($type == 1 and $len > 3 and substr($buff,$pos,3)=~/^.(II|MM)/s) {
|
||||
$et->Warn("Ignored extra byte at start of EXIF extension", 1);
|
||||
++$pos;
|
||||
--$len;
|
||||
}
|
||||
$et->HandleTag($tagTablePtr, $type, undef,
|
||||
DataPt => \$buff,
|
||||
DataPos => $dataPos,
|
||||
Start => $pos,
|
||||
Size => $len,
|
||||
Parent => 'BPG',
|
||||
);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::BPG - Read BPG meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to read BPG
|
||||
(Better Portable Graphics) images.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://bellard.org/bpg/>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/BPG Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,472 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: BZZ.pm
|
||||
#
|
||||
# Description: Utility to decode BZZ compressed data
|
||||
#
|
||||
# Revisions: 09/22/2008 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://djvu.sourceforge.net/
|
||||
# 2) http://www.djvu.org/
|
||||
#
|
||||
# Notes: This code based on ZPCodec and BSByteStream of DjVuLibre 3.5.21
|
||||
# (see NOTES documentation below for license/copyright details)
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::BZZ;
|
||||
|
||||
use strict;
|
||||
use integer; # IMPORTANT!! use integer arithmetic throughout
|
||||
require Exporter;
|
||||
use vars qw($VERSION @ISA @EXPORT_OK);
|
||||
|
||||
$VERSION = '1.00';
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(Decode);
|
||||
|
||||
# constants
|
||||
sub FREQMAX { 4 }
|
||||
sub CTXIDS { 3 }
|
||||
sub MAXBLOCK { 4096 }
|
||||
|
||||
# This table has been designed for the ZPCoder
|
||||
# by running the following command in file 'zptable.sn':
|
||||
# (fast-crude (steady-mat 0.0035 0.0002) 260)))
|
||||
my @default_ztable_p = (
|
||||
0x8000, 0x8000, 0x8000, 0x6bbd, 0x6bbd, 0x5d45, 0x5d45, 0x51b9, 0x51b9, 0x4813,
|
||||
0x4813, 0x3fd5, 0x3fd5, 0x38b1, 0x38b1, 0x3275, 0x3275, 0x2cfd, 0x2cfd, 0x2825,
|
||||
0x2825, 0x23ab, 0x23ab, 0x1f87, 0x1f87, 0x1bbb, 0x1bbb, 0x1845, 0x1845, 0x1523,
|
||||
0x1523, 0x1253, 0x1253, 0x0fcf, 0x0fcf, 0x0d95, 0x0d95, 0x0b9d, 0x0b9d, 0x09e3,
|
||||
0x09e3, 0x0861, 0x0861, 0x0711, 0x0711, 0x05f1, 0x05f1, 0x04f9, 0x04f9, 0x0425,
|
||||
0x0425, 0x0371, 0x0371, 0x02d9, 0x02d9, 0x0259, 0x0259, 0x01ed, 0x01ed, 0x0193,
|
||||
0x0193, 0x0149, 0x0149, 0x010b, 0x010b, 0x00d5, 0x00d5, 0x00a5, 0x00a5, 0x007b,
|
||||
0x007b, 0x0057, 0x0057, 0x003b, 0x003b, 0x0023, 0x0023, 0x0013, 0x0013, 0x0007,
|
||||
0x0007, 0x0001, 0x0001, 0x5695, 0x24ee, 0x8000, 0x0d30, 0x481a, 0x0481, 0x3579,
|
||||
0x017a, 0x24ef, 0x007b, 0x1978, 0x0028, 0x10ca, 0x000d, 0x0b5d, 0x0034, 0x078a,
|
||||
0x00a0, 0x050f, 0x0117, 0x0358, 0x01ea, 0x0234, 0x0144, 0x0173, 0x0234, 0x00f5,
|
||||
0x0353, 0x00a1, 0x05c5, 0x011a, 0x03cf, 0x01aa, 0x0285, 0x0286, 0x01ab, 0x03d3,
|
||||
0x011a, 0x05c5, 0x00ba, 0x08ad, 0x007a, 0x0ccc, 0x01eb, 0x1302, 0x02e6, 0x1b81,
|
||||
0x045e, 0x24ef, 0x0690, 0x2865, 0x09de, 0x3987, 0x0dc8, 0x2c99, 0x10ca, 0x3b5f,
|
||||
0x0b5d, 0x5695, 0x078a, 0x8000, 0x050f, 0x24ee, 0x0358, 0x0d30, 0x0234, 0x0481,
|
||||
0x0173, 0x017a, 0x00f5, 0x007b, 0x00a1, 0x0028, 0x011a, 0x000d, 0x01aa, 0x0034,
|
||||
0x0286, 0x00a0, 0x03d3, 0x0117, 0x05c5, 0x01ea, 0x08ad, 0x0144, 0x0ccc, 0x0234,
|
||||
0x1302, 0x0353, 0x1b81, 0x05c5, 0x24ef, 0x03cf, 0x2b74, 0x0285, 0x201d, 0x01ab,
|
||||
0x1715, 0x011a, 0x0fb7, 0x00ba, 0x0a67, 0x01eb, 0x06e7, 0x02e6, 0x0496, 0x045e,
|
||||
0x030d, 0x0690, 0x0206, 0x09de, 0x0155, 0x0dc8, 0x00e1, 0x2b74, 0x0094, 0x201d,
|
||||
0x0188, 0x1715, 0x0252, 0x0fb7, 0x0383, 0x0a67, 0x0547, 0x06e7, 0x07e2, 0x0496,
|
||||
0x0bc0, 0x030d, 0x1178, 0x0206, 0x19da, 0x0155, 0x24ef, 0x00e1, 0x320e, 0x0094,
|
||||
0x432a, 0x0188, 0x447d, 0x0252, 0x5ece, 0x0383, 0x8000, 0x0547, 0x481a, 0x07e2,
|
||||
0x3579, 0x0bc0, 0x24ef, 0x1178, 0x1978, 0x19da, 0x2865, 0x24ef, 0x3987, 0x320e,
|
||||
0x2c99, 0x432a, 0x3b5f, 0x447d, 0x5695, 0x5ece, 0x8000, 0x8000, 0x5695, 0x481a,
|
||||
0x481a, 0, 0, 0, 0, 0
|
||||
);
|
||||
my @default_ztable_m = (
|
||||
0x0000, 0x0000, 0x0000, 0x10a5, 0x10a5, 0x1f28, 0x1f28, 0x2bd3, 0x2bd3, 0x36e3,
|
||||
0x36e3, 0x408c, 0x408c, 0x48fd, 0x48fd, 0x505d, 0x505d, 0x56d0, 0x56d0, 0x5c71,
|
||||
0x5c71, 0x615b, 0x615b, 0x65a5, 0x65a5, 0x6962, 0x6962, 0x6ca2, 0x6ca2, 0x6f74,
|
||||
0x6f74, 0x71e6, 0x71e6, 0x7404, 0x7404, 0x75d6, 0x75d6, 0x7768, 0x7768, 0x78c2,
|
||||
0x78c2, 0x79ea, 0x79ea, 0x7ae7, 0x7ae7, 0x7bbe, 0x7bbe, 0x7c75, 0x7c75, 0x7d0f,
|
||||
0x7d0f, 0x7d91, 0x7d91, 0x7dfe, 0x7dfe, 0x7e5a, 0x7e5a, 0x7ea6, 0x7ea6, 0x7ee6,
|
||||
0x7ee6, 0x7f1a, 0x7f1a, 0x7f45, 0x7f45, 0x7f6b, 0x7f6b, 0x7f8d, 0x7f8d, 0x7faa,
|
||||
0x7faa, 0x7fc3, 0x7fc3, 0x7fd7, 0x7fd7, 0x7fe7, 0x7fe7, 0x7ff2, 0x7ff2, 0x7ffa,
|
||||
0x7ffa, 0x7fff, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
);
|
||||
my @default_ztable_up = (
|
||||
84, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
|
||||
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
|
||||
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
|
||||
66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
|
||||
82, 81, 82, 9, 86, 5, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
82, 99, 76, 101, 70, 103, 66, 105, 106, 107, 66, 109, 60, 111, 56, 69,
|
||||
114, 65, 116, 61, 118, 57, 120, 53, 122, 49, 124, 43, 72, 39, 60, 33,
|
||||
56, 29, 52, 23, 48, 23, 42, 137, 38, 21, 140, 15, 142, 9, 144, 141,
|
||||
146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 70, 157, 66, 81, 62, 75,
|
||||
58, 69, 54, 65, 50, 167, 44, 65, 40, 59, 34, 55, 30, 175, 24, 177,
|
||||
178, 179, 180, 181, 182, 183, 184, 69, 186, 59, 188, 55, 190, 51, 192, 47,
|
||||
194, 41, 196, 37, 198, 199, 72, 201, 62, 203, 58, 205, 54, 207, 50, 209,
|
||||
46, 211, 40, 213, 36, 215, 30, 217, 26, 219, 20, 71, 14, 61, 14, 57,
|
||||
8, 53, 228, 49, 230, 45, 232, 39, 234, 35, 138, 29, 24, 25, 240, 19,
|
||||
22, 13, 16, 13, 10, 7, 244, 249, 10, 89, 230, 0, 0, 0, 0, 0
|
||||
);
|
||||
my @default_ztable_dn = (
|
||||
145, 4, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
|
||||
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
|
||||
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
|
||||
78, 79, 80, 85, 226, 6, 176, 143, 138, 141, 112, 135, 104, 133, 100, 129,
|
||||
98, 127, 72, 125, 102, 123, 60, 121, 110, 119, 108, 117, 54, 115, 48, 113,
|
||||
134, 59, 132, 55, 130, 51, 128, 47, 126, 41, 62, 37, 66, 31, 54, 25,
|
||||
50, 131, 46, 17, 40, 15, 136, 7, 32, 139, 172, 9, 170, 85, 168, 248,
|
||||
166, 247, 164, 197, 162, 95, 160, 173, 158, 165, 156, 161, 60, 159, 56, 71,
|
||||
52, 163, 48, 59, 42, 171, 38, 169, 32, 53, 26, 47, 174, 193, 18, 191,
|
||||
222, 189, 218, 187, 216, 185, 214, 61, 212, 53, 210, 49, 208, 45, 206, 39,
|
||||
204, 195, 202, 31, 200, 243, 64, 239, 56, 237, 52, 235, 48, 233, 44, 231,
|
||||
38, 229, 34, 227, 28, 225, 22, 223, 16, 221, 220, 63, 8, 55, 224, 51,
|
||||
2, 47, 87, 43, 246, 37, 244, 33, 238, 27, 236, 21, 16, 15, 8, 241,
|
||||
242, 7, 10, 245, 2, 1, 83, 250, 2, 143, 246, 0, 0, 0, 0, 0
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# New - create new BZZ object
|
||||
# Inputs: 0) reference to BZZ object or BZZ class name
|
||||
# Returns: blessed BZZ object ref
|
||||
sub new
|
||||
{
|
||||
local $_;
|
||||
my $that = shift;
|
||||
my $class = ref($that) || $that || 'Image::ExifTool::BZZ';
|
||||
return bless {}, $class;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Initialize BZZ object
|
||||
# Inputs: 0) BZZ object ref, 1) data ref, 2) true for DjVu compatibility
|
||||
sub Init($$)
|
||||
{
|
||||
my ($self, $dataPt, $djvucompat) = @_;
|
||||
# Create machine independent ffz table
|
||||
my $ffzt = $$self{ffzt} = [ ];
|
||||
my ($i, $j);
|
||||
for ($i=0; $i<256; $i++) {
|
||||
$$ffzt[$i] = 0;
|
||||
for ($j=$i; $j&0x80; $j<<=1) {
|
||||
$$ffzt[$i] += 1;
|
||||
}
|
||||
}
|
||||
# Initialize table
|
||||
$$self{p} = [ @default_ztable_p ];
|
||||
$$self{'m'} = [ @default_ztable_m ];
|
||||
$$self{up} = [ @default_ztable_up ];
|
||||
$$self{dn} = [ @default_ztable_dn ];
|
||||
# Patch table (and lose DjVu compatibility)
|
||||
unless ($djvucompat) {
|
||||
my ($p, $m, $dn) = ($$self{p}, $$self{'m'}, $$self{dn});
|
||||
for ($j=0; $j<256; $j++) {
|
||||
my $a = (0x10000 - $$p[$j]) & 0xffff;
|
||||
while ($a >= 0x8000) { $a = ($a<<1) & 0xffff }
|
||||
if ($$m[$j]>0 && $a+$$p[$j]>=0x8000 && $a>=$$m[$j]) {
|
||||
$$dn[$j] = $default_ztable_dn[$default_ztable_dn[$j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
$$self{ctx} = [ (0) x 300 ];
|
||||
$$self{DataPt} = $dataPt;
|
||||
$$self{Pos} = 0;
|
||||
$$self{DataLen} = length $$dataPt;
|
||||
$$self{a} = 0;
|
||||
$$self{buffer} = 0;
|
||||
$$self{fence} = 0;
|
||||
$$self{blocksize} = 0;
|
||||
# Read first 16 bits of code
|
||||
if (length($$dataPt) >= 2) {
|
||||
$$self{code} = unpack('n', $$dataPt);
|
||||
$$self{Pos} += 2;
|
||||
} elsif (length($$dataPt) >= 1) {
|
||||
$$self{code} = (unpack('C', $$dataPt) << 8) | 0xff;
|
||||
$$self{Pos}++;
|
||||
} else {
|
||||
$$self{code} = 0xffff;
|
||||
}
|
||||
$$self{byte} = $$self{code} & 0xff;
|
||||
# Preload buffer
|
||||
$$self{delay} = 25;
|
||||
$$self{scount} = 0;
|
||||
# Compute initial fence
|
||||
$$self{fence} = $$self{code} >= 0x8000 ? 0x7fff : $$self{code};
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Decode data block
|
||||
# Inputs: 0) optional BZZ object ref, 1) optional data ref
|
||||
# Returns: decoded data or undefined on error
|
||||
# Notes: If called without a data ref, an input BZZ object ref must be given and
|
||||
# the BZZ object must have been initialized by a previous call to Init()
|
||||
sub Decode($;$)
|
||||
{
|
||||
# Decode input stream
|
||||
local $_;
|
||||
my $self;
|
||||
if (ref $_[0] and UNIVERSAL::isa($_[0],'Image::ExifTool::BZZ')) {
|
||||
$self = shift;
|
||||
} else {
|
||||
$self = new Image::ExifTool::BZZ;
|
||||
}
|
||||
my $dataPt = shift;
|
||||
if ($dataPt) {
|
||||
$self->Init($dataPt, 1);
|
||||
} else {
|
||||
$dataPt = $$self{DataPt} or return undef;
|
||||
}
|
||||
# Decode block size
|
||||
my $n = 1;
|
||||
my $m = (1 << 24);
|
||||
while ($n < $m) {
|
||||
my $b = $self->decode_sub(0x8000 + ($$self{a}>>1));
|
||||
$n = ($n<<1) | $b;
|
||||
}
|
||||
$$self{size} = $n - $m;
|
||||
|
||||
return '' unless $$self{size};
|
||||
return undef if $$self{size} > MAXBLOCK()*1024;
|
||||
# Allocate
|
||||
if ($$self{blocksize} < $$self{size}) {
|
||||
$$self{blocksize} = $$self{size};
|
||||
}
|
||||
# Decode Estimation Speed
|
||||
my $fshift = 0;
|
||||
if ($self->decode_sub(0x8000 + ($$self{a}>>1))) {
|
||||
$fshift += 1;
|
||||
$fshift += 1 if $self->decode_sub(0x8000 + ($$self{a}>>1));
|
||||
}
|
||||
# Prepare Quasi MTF
|
||||
my @mtf = (0..255);
|
||||
my @freq = (0) x FREQMAX();
|
||||
my $fadd = 4;
|
||||
# Decode
|
||||
my $mtfno = 3;
|
||||
my $markerpos = -1;
|
||||
my $cx = $$self{ctx};
|
||||
my ($i, @dat);
|
||||
byte: for ($i=0; $i<$$self{size}; $i++) {
|
||||
# dummy loop avoids use of "goto" statement
|
||||
dummy: for (;;) {
|
||||
my $ctxid = CTXIDS() - 1;
|
||||
$ctxid = $mtfno if $ctxid > $mtfno;
|
||||
my $cp = 0;
|
||||
my ($imtf, $bits);
|
||||
for ($imtf=0; $imtf<2; ++$imtf) {
|
||||
if ($self->decoder($$cx[$cp+$ctxid])) {
|
||||
$mtfno = $imtf;
|
||||
$dat[$i] = $mtf[$mtfno];
|
||||
# (a "goto" here could give a segfault due to a Perl bug)
|
||||
last dummy; # do rotation
|
||||
}
|
||||
$cp += CTXIDS();
|
||||
}
|
||||
for ($bits=1; $bits<8; ++$bits, $imtf<<=1) {
|
||||
if ($self->decoder($$cx[$cp])) {
|
||||
my $n = 1;
|
||||
my $m = (1 << $bits);
|
||||
while ($n < $m) {
|
||||
my $b = $self->decoder($$cx[$cp+$n]);
|
||||
$n = ($n<<1) | $b;
|
||||
}
|
||||
$mtfno = $imtf + $n - $m;
|
||||
$dat[$i] = $mtf[$mtfno];
|
||||
last dummy; # do rotation
|
||||
}
|
||||
$cp += $imtf;
|
||||
}
|
||||
$mtfno=256;
|
||||
$dat[$i] = 0;
|
||||
$markerpos=$i;
|
||||
next byte; # no rotation necessary
|
||||
}
|
||||
# Rotate mtf according to empirical frequencies (new!)
|
||||
# Adjust frequencies for overflow
|
||||
$fadd = $fadd + ($fadd >> $fshift);
|
||||
if ($fadd > 0x10000000) {
|
||||
$fadd >>= 24;
|
||||
$_ >>= 24 foreach @freq;
|
||||
}
|
||||
# Relocate new char according to new freq
|
||||
my $fc = $fadd;
|
||||
$fc += $freq[$mtfno] if $mtfno < FREQMAX();
|
||||
my $k;
|
||||
for ($k=$mtfno; $k>=FREQMAX(); $k--) {
|
||||
$mtf[$k] = $mtf[$k-1];
|
||||
}
|
||||
for (; $k>0 && $fc>=$freq[$k-1]; $k--) {
|
||||
$mtf[$k] = $mtf[$k-1];
|
||||
$freq[$k] = $freq[$k-1];
|
||||
}
|
||||
$mtf[$k] = $dat[$i];
|
||||
$freq[$k] = $fc;
|
||||
# when "goto" was used, Perl 5.8.6 could segfault here
|
||||
# unless "next" was explicitly stated
|
||||
}
|
||||
#
|
||||
# Reconstruct the string
|
||||
#
|
||||
return undef if $markerpos<1 || $markerpos>=$$self{size};
|
||||
# Allocate pointers
|
||||
# Prepare count buffer
|
||||
my @count = (0) x 256;
|
||||
my @posn;
|
||||
# Fill count buffer
|
||||
no integer;
|
||||
for ($i=0; $i<$markerpos; $i++) {
|
||||
my $c = $dat[$i];
|
||||
$posn[$i] = ($c<<24) | ($count[$c]++ & 0xffffff);
|
||||
}
|
||||
$posn[$i++] = 0; # (initialize marker entry just to be safe)
|
||||
for ( ; $i<$$self{size}; $i++) {
|
||||
my $c = $dat[$i];
|
||||
$posn[$i] = ($c<<24) | ($count[$c]++ & 0xffffff);
|
||||
}
|
||||
use integer;
|
||||
# Compute sorted char positions
|
||||
my $last = 1;
|
||||
for ($i=0; $i<256; $i++) {
|
||||
my $tmp = $count[$i];
|
||||
$count[$i] = $last;
|
||||
$last += $tmp;
|
||||
}
|
||||
# Undo the sort transform
|
||||
$i = 0;
|
||||
$last = $$self{size}-1;
|
||||
while ($last > 0) {
|
||||
my $n = $posn[$i];
|
||||
no integer;
|
||||
my $c = $n >> 24;
|
||||
use integer;
|
||||
$dat[--$last] = $c;
|
||||
$i = $count[$c] + ($n & 0xffffff);
|
||||
}
|
||||
# Final check and return decoded data
|
||||
return undef if $i != $markerpos;
|
||||
pop @dat; # (last byte isn't real)
|
||||
return pack 'C*', @dat;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Inputs: 0) BZZ object ref, 1) ctx
|
||||
# Returns: decoded bit
|
||||
sub decoder($$)
|
||||
{
|
||||
my ($self, $ctx) = @_;
|
||||
my $z = $$self{a} + $self->{p}[$ctx];
|
||||
if ($z <= $$self{fence}) {
|
||||
$$self{a} = $z;
|
||||
return ($ctx & 1);
|
||||
}
|
||||
# must pass $_[1] so subroutine can modify value (darned C++ pass-by-reference!)
|
||||
return $self->decode_sub($z, $_[1]);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Inputs: 0) BZZ object ref, 1) z, 2) ctx (or undef)
|
||||
# Returns: decoded bit
|
||||
sub decode_sub($$;$)
|
||||
{
|
||||
my ($self, $z, $ctx) = @_;
|
||||
|
||||
# ensure that we have at least 16 bits of encoded data available
|
||||
if ($$self{scount} < 16) {
|
||||
# preload byte by byte until we have at least 24 bits
|
||||
while ($$self{scount} <= 24) {
|
||||
if ($$self{Pos} < $$self{DataLen}) {
|
||||
$$self{byte} = ord(substr(${$$self{DataPt}}, $$self{Pos}, 1));
|
||||
++$$self{Pos};
|
||||
} else {
|
||||
$$self{byte} = 0xff;
|
||||
if (--$$self{delay} < 1) {
|
||||
# setting size to zero forces error return from Decode()
|
||||
$$self{size} = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$$self{buffer} = ($$self{buffer}<<8) | $$self{byte};
|
||||
$$self{scount} += 8;
|
||||
}
|
||||
}
|
||||
# Save bit
|
||||
my $a = $$self{a};
|
||||
my ($bit, $code);
|
||||
if (defined $ctx) {
|
||||
$bit = ($ctx & 1);
|
||||
# Avoid interval reversion
|
||||
my $d = 0x6000 + (($z+$a)>>2);
|
||||
$z = $d if $z > $d;
|
||||
} else {
|
||||
$bit = 0;
|
||||
}
|
||||
# Test MPS/LPS
|
||||
if ($z > ($code = $$self{code})) {
|
||||
$bit ^= 1;
|
||||
# LPS branch
|
||||
$z = 0x10000 - $z;
|
||||
$a += $z;
|
||||
$code += $z;
|
||||
# LPS adaptation
|
||||
$_[2] = $self->{dn}[$ctx] if defined $ctx;
|
||||
# LPS renormalization
|
||||
my $sft = $a>=0xff00 ? $self->{ffzt}[$a&0xff] + 8 : $self->{ffzt}[($a>>8)&0xff];
|
||||
$$self{scount} -= $sft;
|
||||
$$self{a} = ($a<<$sft) & 0xffff;
|
||||
$code = (($code<<$sft) & 0xffff) | (($$self{buffer}>>$$self{scount}) & ((1<<$sft)-1));
|
||||
} else {
|
||||
# MPS adaptation
|
||||
$_[2] = $self->{up}[$ctx] if defined $ctx and $a >= $self->{'m'}[$ctx];
|
||||
# MPS renormalization
|
||||
$$self{scount} -= 1;
|
||||
$$self{a} = ($z<<1) & 0xffff;
|
||||
$code = (($code<<1) & 0xffff) | (($$self{buffer}>>$$self{scount}) & 1);
|
||||
}
|
||||
# Adjust fence and save new code
|
||||
$$self{fence} = $code >= 0x8000 ? 0x7fff : $code;
|
||||
$$self{code} = $code;
|
||||
return $bit;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::BZZ - Utility to decode BZZ compressed data
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to decode BZZ
|
||||
compressed data in DjVu images.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
This code is based on ZPCodec and BSByteStream of DjVuLibre 3.5.21 (see
|
||||
additional copyrights and the first reference below), which are covered
|
||||
under the GNU GPL license.
|
||||
|
||||
This is implemented as Image::ExifTool::BZZ instead of Compress::BZZ because
|
||||
I am hoping that someone else will write a proper Compress::BZZ module (with
|
||||
compression ability).
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
Copyright 2002, Leon Bottou and Yann Le Cun
|
||||
Copyright 2001, AT&T
|
||||
Copyright 1999-2001, LizardTech Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://djvu.sourceforge.net/>
|
||||
|
||||
=item L<http://www.djvu.org/>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::DjVu(3pm)|Image::ExifTool::DjVu>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: BigTIFF.pm
|
||||
#
|
||||
# Description: Read Big TIFF meta information
|
||||
#
|
||||
# Revisions: 07/03/2007 - P. Harvey Created
|
||||
#
|
||||
# References: 1) http://www.awaresystems.be/imaging/tiff/bigtiff.html
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::BigTIFF;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
use Image::ExifTool::Exif;
|
||||
|
||||
$VERSION = '1.06';
|
||||
|
||||
my $maxOffset = 0x7fffffff; # currently supported maximum data offset/size
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process Big IFD directory
|
||||
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
||||
# Returns: 1 on success, otherwise returns 0 and sets a Warning
|
||||
sub ProcessBigIFD($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $tagTablePtr) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my $verbose = $$et{OPTIONS}{Verbose};
|
||||
my $htmlDump = $$et{HTML_DUMP};
|
||||
my $dirName = $$dirInfo{DirName};
|
||||
my $dirStart = $$dirInfo{DirStart};
|
||||
|
||||
$verbose = -1 if $htmlDump; # mix htmlDump into verbose so we can test for both at once
|
||||
|
||||
# loop through IFD chain
|
||||
for (;;) {
|
||||
if ($dirStart > $maxOffset and not $et->Options('LargeFileSupport')) {
|
||||
$et->Warn('Huge offsets not supported (LargeFileSupport not set)');
|
||||
last;
|
||||
}
|
||||
unless ($raf->Seek($dirStart, 0)) {
|
||||
$et->Warn("Bad $dirName offset");
|
||||
return 0;
|
||||
}
|
||||
my ($dirBuff, $index);
|
||||
unless ($raf->Read($dirBuff, 8) == 8) {
|
||||
$et->Warn("Truncated $dirName count");
|
||||
return 0;
|
||||
}
|
||||
my $numEntries = Image::ExifTool::Get64u(\$dirBuff, 0);
|
||||
$verbose > 0 and $et->VerboseDir($dirName, $numEntries);
|
||||
my $bsize = $numEntries * 20;
|
||||
if ($bsize > $maxOffset) {
|
||||
$et->Warn('Huge directory counts not yet supported');
|
||||
last;
|
||||
}
|
||||
my $bufPos = $raf->Tell();
|
||||
unless ($raf->Read($dirBuff, $bsize) == $bsize) {
|
||||
$et->Warn("Truncated $dirName directory");
|
||||
return 0;
|
||||
}
|
||||
my $nextIFD;
|
||||
$raf->Read($nextIFD, 8) == 8 or undef $nextIFD; # try to read next IFD pointer
|
||||
if ($htmlDump) {
|
||||
$et->HDump($bufPos-8, 8, "$dirName entries", "Entry count: $numEntries");
|
||||
if (defined $nextIFD) {
|
||||
my $tip = sprintf("Offset: 0x%.8x", Image::ExifTool::Get64u(\$nextIFD, 0));
|
||||
$et->HDump($bufPos + 20 * $numEntries, 8, "Next IFD", $tip, 0);
|
||||
}
|
||||
}
|
||||
# loop through all entries in this BigTIFF IFD
|
||||
for ($index=0; $index<$numEntries; ++$index) {
|
||||
my $entry = 20 * $index;
|
||||
my $tagID = Get16u(\$dirBuff, $entry);
|
||||
my $format = Get16u(\$dirBuff, $entry+2);
|
||||
my $count = Image::ExifTool::Get64u(\$dirBuff, $entry+4);
|
||||
my $formatSize = $Image::ExifTool::Exif::formatSize[$format];
|
||||
unless (defined $formatSize) {
|
||||
$et->HDump($bufPos+$entry,20,"[invalid IFD entry]",
|
||||
"Bad format value: $format", 1);
|
||||
# warn unless the IFD was just padded with zeros
|
||||
$et->Warn(sprintf("Unknown format ($format) for $dirName tag 0x%x",$tagID));
|
||||
return 0; # assume corrupted IFD
|
||||
}
|
||||
my $formatStr = $Image::ExifTool::Exif::formatName[$format];
|
||||
my $size = $count * $formatSize;
|
||||
my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID);
|
||||
next unless defined $tagInfo or $verbose;
|
||||
my $valuePtr = $entry + 12;
|
||||
my ($valBuff, $valBase, $rational);
|
||||
if ($size > 8) {
|
||||
if ($size > $maxOffset) {
|
||||
$et->Warn("Can't handle $dirName entry $index (huge size)");
|
||||
next;
|
||||
}
|
||||
$valuePtr = Image::ExifTool::Get64u(\$dirBuff, $valuePtr);
|
||||
if ($valuePtr > $maxOffset and not $et->Options('LargeFileSupport')) {
|
||||
$et->Warn("Can't handle $dirName entry $index (LargeFileSupport not set)");
|
||||
next;
|
||||
}
|
||||
unless ($raf->Seek($valuePtr, 0) and $raf->Read($valBuff, $size) == $size) {
|
||||
$et->Warn("Error reading $dirName entry $index");
|
||||
next;
|
||||
}
|
||||
$valBase = 0;
|
||||
} else {
|
||||
$valBuff = substr($dirBuff, $valuePtr, $size);
|
||||
$valBase = $bufPos;
|
||||
}
|
||||
if (defined $tagInfo and not $tagInfo) {
|
||||
# GetTagInfo() required the value for a Condition
|
||||
$tagInfo = $et->GetTagInfo($tagTablePtr, $tagID, \$valBuff);
|
||||
}
|
||||
my $val = ReadValue(\$valBuff, 0, $formatStr, $count, $size, \$rational);
|
||||
if ($htmlDump) {
|
||||
my $tval = $val;
|
||||
# show numerator/denominator separately for rational numbers
|
||||
$tval .= " ($rational)" if defined $rational;
|
||||
my ($tagName, $colName);
|
||||
if ($tagID == 0x927c and $dirName eq 'ExifIFD') {
|
||||
$tagName = 'MakerNotes';
|
||||
} elsif ($tagInfo) {
|
||||
$tagName = $$tagInfo{Name};
|
||||
} else {
|
||||
$tagName = sprintf("Tag 0x%.4x",$tagID);
|
||||
}
|
||||
my $dname = sprintf("$dirName-%.2d", $index);
|
||||
# build our tool tip
|
||||
my $tip = sprintf("Tag ID: 0x%.4x\n", $tagID) .
|
||||
"Format: $formatStr\[$count]\nSize: $size bytes\n";
|
||||
if ($size > 8) {
|
||||
$tip .= sprintf("Value offset: 0x%.8x\n", $valuePtr);
|
||||
$colName = "<span class=H>$tagName</span>";
|
||||
} else {
|
||||
$colName = $tagName;
|
||||
}
|
||||
$tval = substr($tval,0,28) . '[...]' if length($tval) > 32;
|
||||
if ($formatStr =~ /^(string|undef|binary)/) {
|
||||
# translate non-printable characters
|
||||
$tval =~ tr/\x00-\x1f\x7f-\xff/./;
|
||||
} elsif ($tagInfo and Image::ExifTool::IsInt($tval)) {
|
||||
if ($$tagInfo{IsOffset}) {
|
||||
$tval = sprintf('0x%.4x', $tval);
|
||||
} elsif ($$tagInfo{PrintHex}) {
|
||||
$tval = sprintf('0x%x', $tval);
|
||||
}
|
||||
}
|
||||
$tip .= "Value: $tval";
|
||||
$et->HDump($entry+$bufPos, 20, "$dname $colName", $tip, 1);
|
||||
if ($size > 8) {
|
||||
# add value data block
|
||||
my $flg = ($tagInfo and $$tagInfo{SubDirectory} and $$tagInfo{MakerNotes}) ? 4 : 0;
|
||||
$et->HDump($valuePtr,$size,"$tagName value",'SAME', $flg);
|
||||
}
|
||||
}
|
||||
if ($tagInfo and $$tagInfo{SubIFD}) {
|
||||
# process all SubIFD's as BigTIFF
|
||||
$verbose > 0 and $et->VerboseInfo($tagID, $tagInfo,
|
||||
Table => $tagTablePtr,
|
||||
Index => $index,
|
||||
Value => $val,
|
||||
DataPt => \$valBuff,
|
||||
DataPos => $valBase + $valuePtr,
|
||||
Start => 0,
|
||||
Size => $size,
|
||||
Format => $formatStr,
|
||||
Count => $count,
|
||||
);
|
||||
my @offsets = split ' ', $val;
|
||||
my $i;
|
||||
for ($i=0; $i<scalar(@offsets); ++$i) {
|
||||
my $subdirName = $$tagInfo{Name};
|
||||
$subdirName .= $i if $i;
|
||||
my %subdirInfo = (
|
||||
RAF => $raf,
|
||||
DataPos => 0,
|
||||
DirStart => $offsets[$i],
|
||||
DirName => $subdirName,
|
||||
Parent => $dirInfo,
|
||||
);
|
||||
$et->ProcessDirectory(\%subdirInfo, $tagTablePtr, \&ProcessBigIFD);
|
||||
}
|
||||
} else {
|
||||
my $tagKey = $et->HandleTag($tagTablePtr, $tagID, $val,
|
||||
Index => $index,
|
||||
DataPt => \$valBuff,
|
||||
DataPos => $valBase + $valuePtr,
|
||||
Start => 0,
|
||||
Size => $size,
|
||||
Format => $formatStr,
|
||||
TagInfo => $tagInfo,
|
||||
RAF => $raf,
|
||||
);
|
||||
$tagKey and $et->SetGroup($tagKey, $dirName);
|
||||
}
|
||||
}
|
||||
last unless $dirName =~ /^(IFD|SubIFD)(\d*)$/;
|
||||
$dirName = $1 . (($2 || 0) + 1);
|
||||
defined $nextIFD or $et->Warn("Bad $dirName pointer"), return 0;
|
||||
$dirStart = Image::ExifTool::Get64u(\$nextIFD, 0);
|
||||
$dirStart or last;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract meta information from a BigTIFF image
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# Returns: 1 on success, 0 if this wasn't a valid BigTIFF image
|
||||
sub ProcessBTF($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my $buff;
|
||||
|
||||
return 0 unless $raf->Read($buff, 16) == 16;
|
||||
return 0 unless $buff =~ /^(MM\0\x2b\0\x08\0\0|II\x2b\0\x08\0\0\0)/;
|
||||
if ($$dirInfo{OutFile}) {
|
||||
$et->Error('ExifTool does not support writing of BigTIFF images');
|
||||
return 1;
|
||||
}
|
||||
$et->SetFileType('BTF'); # set the FileType tag
|
||||
SetByteOrder(substr($buff, 0, 2));
|
||||
my $offset = Image::ExifTool::Get64u(\$buff, 8);
|
||||
if ($$et{HTML_DUMP}) {
|
||||
my $o = (GetByteOrder() eq 'II') ? 'Little' : 'Big';
|
||||
$et->HDump(0, 8, "BigTIFF header", "Byte order: $o endian", 0);
|
||||
$et->HDump(8, 8, "IFD0 pointer", sprintf("Offset: 0x%.8x",$offset), 0);
|
||||
}
|
||||
my %dirInfo = (
|
||||
RAF => $raf,
|
||||
DataPos => 0,
|
||||
DirStart => $offset,
|
||||
DirName => 'IFD0',
|
||||
Parent => 'BigTIFF',
|
||||
);
|
||||
my $tagTablePtr = GetTagTable('Image::ExifTool::Exif::Main');
|
||||
$et->ProcessDirectory(\%dirInfo, $tagTablePtr, \&ProcessBigIFD);
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::BigTIFF - Read Big TIFF meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains routines required by Image::ExifTool to read meta
|
||||
information in BigTIFF images.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.awaresystems.be/imaging/tiff/bigtiff.html>
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/EXIF Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,910 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: CanonRaw.pm
|
||||
#
|
||||
# Description: Read Canon RAW (CRW) meta information
|
||||
#
|
||||
# Revisions: 11/25/2003 - P. Harvey Created
|
||||
# 12/02/2003 - P. Harvey Completely reworked and figured out many
|
||||
# more tags
|
||||
#
|
||||
# References: 1) http://www.cybercom.net/~dcoffin/dcraw/
|
||||
# 2) http://www.wonderland.org/crw/
|
||||
# 3) http://xyrion.org/ciff/CIFFspecV1R04.pdf
|
||||
# 4) Dave Nicholson private communication (PowerShot S30)
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::CanonRaw;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION $AUTOLOAD %crwTagFormat);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
use Image::ExifTool::Exif;
|
||||
use Image::ExifTool::Canon;
|
||||
|
||||
$VERSION = '1.58';
|
||||
|
||||
sub WriteCRW($$);
|
||||
sub ProcessCanonRaw($$$);
|
||||
sub WriteCanonRaw($$$);
|
||||
sub CheckCanonRaw($$$);
|
||||
sub InitMakerNotes($);
|
||||
sub SaveMakerNotes($);
|
||||
sub BuildMakerNotes($$$$$$);
|
||||
|
||||
# formats for CRW tag types (($tag >> 8) & 0x38)
|
||||
# Note: don't define format for undefined types
|
||||
%crwTagFormat = (
|
||||
0x00 => 'int8u',
|
||||
0x08 => 'string',
|
||||
0x10 => 'int16u',
|
||||
0x18 => 'int32u',
|
||||
# 0x20 => 'undef',
|
||||
# 0x28 => 'undef',
|
||||
# 0x30 => 'undef',
|
||||
);
|
||||
|
||||
# Canon raw file tag table
|
||||
# Note: Tag ID's have upper 2 bits set to zero, since these 2 bits
|
||||
# just specify the location of the information
|
||||
%Image::ExifTool::CanonRaw::Main = (
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
|
||||
PROCESS_PROC => \&ProcessCanonRaw,
|
||||
WRITE_PROC => \&WriteCanonRaw,
|
||||
CHECK_PROC => \&CheckCanonRaw,
|
||||
WRITABLE => 1,
|
||||
0x0000 => { Name => 'NullRecord', Writable => 'undef' }, #3
|
||||
0x0001 => { #3
|
||||
Name => 'FreeBytes',
|
||||
Format => 'undef',
|
||||
Binary => 1,
|
||||
},
|
||||
0x0032 => { Name => 'CanonColorInfo1', Writable => 0 },
|
||||
0x0805 => [
|
||||
# this tag is found in more than one directory...
|
||||
{
|
||||
Condition => '$self->{DIR_NAME} eq "ImageDescription"',
|
||||
Name => 'CanonFileDescription',
|
||||
Writable => 'string[32]',
|
||||
},
|
||||
{
|
||||
Name => 'UserComment',
|
||||
Writable => 'string[256]',
|
||||
},
|
||||
],
|
||||
0x080a => {
|
||||
Name => 'CanonRawMakeModel',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::MakeModel' },
|
||||
},
|
||||
0x080b => { Name => 'CanonFirmwareVersion', Writable => 'string[32]' },
|
||||
0x080c => { Name => 'ComponentVersion', Writable => 'string' }, #3
|
||||
0x080d => { Name => 'ROMOperationMode', Writable => 'string[8]' }, #3
|
||||
0x0810 => { Name => 'OwnerName', Writable => 'string[32]' },
|
||||
0x0815 => { Name => 'CanonImageType', Writable => 'string[32]' },
|
||||
0x0816 => { Name => 'OriginalFileName', Writable => 'string[32]' },
|
||||
0x0817 => { Name => 'ThumbnailFileName', Writable => 'string[32]' },
|
||||
0x100a => { #3
|
||||
Name => 'TargetImageType',
|
||||
Writable => 'int16u',
|
||||
PrintConv => {
|
||||
0 => 'Real-world Subject',
|
||||
1 => 'Written Document',
|
||||
},
|
||||
},
|
||||
0x1010 => { #3
|
||||
Name => 'ShutterReleaseMethod',
|
||||
Writable => 'int16u',
|
||||
PrintConv => {
|
||||
0 => 'Single Shot',
|
||||
2 => 'Continuous Shooting',
|
||||
},
|
||||
},
|
||||
0x1011 => { #3
|
||||
Name => 'ShutterReleaseTiming',
|
||||
Writable => 'int16u',
|
||||
PrintConv => {
|
||||
0 => 'Priority on shutter',
|
||||
1 => 'Priority on focus',
|
||||
},
|
||||
},
|
||||
0x1016 => { Name => 'ReleaseSetting', Writable => 'int16u' }, #3
|
||||
0x101c => { Name => 'BaseISO', Writable => 'int16u' }, #3
|
||||
0x1028=> { #PH
|
||||
Name => 'CanonFlashInfo',
|
||||
Writable => 'int16u',
|
||||
Count => 4,
|
||||
Unknown => 1,
|
||||
},
|
||||
0x1029 => {
|
||||
Name => 'CanonFocalLength',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Canon::FocalLength' },
|
||||
},
|
||||
0x102a => {
|
||||
Name => 'CanonShotInfo',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Canon::ShotInfo' },
|
||||
},
|
||||
0x102c => {
|
||||
Name => 'CanonColorInfo2',
|
||||
Writable => 0,
|
||||
# for the S30, the following information has been decoded: (ref 4)
|
||||
# offset 66: int32u - shutter half press time in ms
|
||||
# offset 70: int32u - image capture time in ms
|
||||
# offset 74: int16u - custom white balance flag (0=Off, 512=On)
|
||||
},
|
||||
0x102d => {
|
||||
Name => 'CanonCameraSettings',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Canon::CameraSettings' },
|
||||
},
|
||||
0x1030 => { #4
|
||||
Name => 'WhiteSample',
|
||||
Writable => 0,
|
||||
SubDirectory => {
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
|
||||
TagTable => 'Image::ExifTool::CanonRaw::WhiteSample',
|
||||
},
|
||||
},
|
||||
0x1031 => {
|
||||
Name => 'SensorInfo',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Canon::SensorInfo' },
|
||||
},
|
||||
# this tag has only be verified for the 10D in CRW files, but the D30 and D60
|
||||
# also produce CRW images and have CustomFunction information in their JPEG's
|
||||
0x1033 => [
|
||||
{
|
||||
Name => 'CustomFunctions10D',
|
||||
Condition => '$self->{Model} =~ /EOS 10D/',
|
||||
SubDirectory => {
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
|
||||
TagTable => 'Image::ExifTool::CanonCustom::Functions10D',
|
||||
},
|
||||
},
|
||||
{
|
||||
Name => 'CustomFunctionsD30',
|
||||
Condition => '$self->{Model} =~ /EOS D30\b/',
|
||||
SubDirectory => {
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
|
||||
TagTable => 'Image::ExifTool::CanonCustom::FunctionsD30',
|
||||
},
|
||||
},
|
||||
{
|
||||
Name => 'CustomFunctionsD60',
|
||||
Condition => '$self->{Model} =~ /EOS D60\b/',
|
||||
SubDirectory => {
|
||||
# the stored size in the D60 apparently doesn't include the size word:
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size-2,$size)',
|
||||
# (D60 custom functions are basically the same as D30)
|
||||
TagTable => 'Image::ExifTool::CanonCustom::FunctionsD30',
|
||||
},
|
||||
},
|
||||
{
|
||||
Name => 'CustomFunctionsUnknown',
|
||||
SubDirectory => {
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
|
||||
TagTable => 'Image::ExifTool::CanonCustom::FuncsUnknown',
|
||||
},
|
||||
},
|
||||
],
|
||||
0x1038 => {
|
||||
Name => 'CanonAFInfo',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Canon::AFInfo' },
|
||||
},
|
||||
0x1093 => {
|
||||
Name => 'CanonFileInfo',
|
||||
SubDirectory => {
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
|
||||
TagTable => 'Image::ExifTool::Canon::FileInfo',
|
||||
},
|
||||
},
|
||||
0x10a9 => {
|
||||
Name => 'ColorBalance',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorBalance' },
|
||||
},
|
||||
0x10b5 => { #PH
|
||||
Name => 'RawJpgInfo',
|
||||
SubDirectory => {
|
||||
Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)',
|
||||
TagTable => 'Image::ExifTool::CanonRaw::RawJpgInfo',
|
||||
},
|
||||
},
|
||||
0x10ae => {
|
||||
Name => 'ColorTemperature',
|
||||
Writable => 'int16u',
|
||||
},
|
||||
0x10b4 => {
|
||||
Name => 'ColorSpace',
|
||||
Writable => 'int16u',
|
||||
PrintConv => {
|
||||
1 => 'sRGB',
|
||||
2 => 'Adobe RGB',
|
||||
0xffff => 'Uncalibrated',
|
||||
},
|
||||
},
|
||||
0x1803 => { #3
|
||||
Name => 'ImageFormat',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::ImageFormat' },
|
||||
},
|
||||
0x1804 => { Name => 'RecordID', Writable => 'int32u' }, #3
|
||||
0x1806 => { #3
|
||||
Name => 'SelfTimerTime',
|
||||
Writable => 'int32u',
|
||||
ValueConv => '$val / 1000',
|
||||
ValueConvInv => '$val * 1000',
|
||||
PrintConv => '"$val s"',
|
||||
PrintConvInv => '$val=~s/\s*s.*//;$val',
|
||||
},
|
||||
0x1807 => {
|
||||
Name => 'TargetDistanceSetting',
|
||||
Format => 'float',
|
||||
PrintConv => '"$val mm"',
|
||||
PrintConvInv => '$val=~s/\s*mm$//;$val',
|
||||
},
|
||||
0x180b => [
|
||||
{
|
||||
# D30
|
||||
Name => 'SerialNumber',
|
||||
Condition => '$$self{Model} =~ /EOS D30\b/',
|
||||
Writable => 'int32u',
|
||||
PrintConv => 'sprintf("%x-%.5d",$val>>16,$val&0xffff)',
|
||||
PrintConvInv => '$val=~/(.*)-(\d+)/ ? (hex($1)<<16)+$2 : undef',
|
||||
},
|
||||
{
|
||||
# all EOS models (D30, 10D, 300D)
|
||||
Name => 'SerialNumber',
|
||||
Condition => '$$self{Model} =~ /EOS/',
|
||||
Writable => 'int32u',
|
||||
PrintConv => 'sprintf("%.10d",$val)',
|
||||
PrintConvInv => '$val',
|
||||
},
|
||||
{
|
||||
# this is not SerialNumber for PowerShot models (but what is it?) - PH
|
||||
Name => 'UnknownNumber',
|
||||
Unknown => 1,
|
||||
},
|
||||
],
|
||||
0x180e => {
|
||||
Name => 'TimeStamp',
|
||||
Writable => 0,
|
||||
SubDirectory => {
|
||||
TagTable => 'Image::ExifTool::CanonRaw::TimeStamp',
|
||||
},
|
||||
},
|
||||
0x1810 => {
|
||||
Name => 'ImageInfo',
|
||||
Writable => 0,
|
||||
SubDirectory => {
|
||||
TagTable => 'Image::ExifTool::CanonRaw::ImageInfo',
|
||||
},
|
||||
},
|
||||
0x1813 => { #3
|
||||
Name => 'FlashInfo',
|
||||
Writable => 0,
|
||||
SubDirectory => {
|
||||
TagTable => 'Image::ExifTool::CanonRaw::FlashInfo',
|
||||
},
|
||||
},
|
||||
0x1814 => { #3
|
||||
Name => 'MeasuredEV',
|
||||
Notes => q{
|
||||
this is the Canon name for what could better be called MeasuredLV, and
|
||||
should be close to the calculated LightValue for a proper exposure with most
|
||||
models
|
||||
},
|
||||
Format => 'float',
|
||||
ValueConv => '$val + 5',
|
||||
ValueConvInv => '$val - 5',
|
||||
},
|
||||
0x1817 => {
|
||||
Name => 'FileNumber',
|
||||
Writable => 'int32u',
|
||||
Groups => { 2 => 'Image' },
|
||||
PrintConv => '$_=$val;s/(\d+)(\d{4})/$1-$2/;$_',
|
||||
PrintConvInv => '$_=$val;s/-//;$_',
|
||||
},
|
||||
0x1818 => { #3
|
||||
Name => 'ExposureInfo',
|
||||
Groups => { 1 => 'CIFF' }, # (only so CIFF shows up in group lists)
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::ExposureInfo' },
|
||||
},
|
||||
0x1834 => { #PH
|
||||
Name => 'CanonModelID',
|
||||
Writable => 'int32u',
|
||||
PrintHex => 1,
|
||||
Notes => q{
|
||||
this is the complete list of model ID numbers, but note that many of these
|
||||
models do not produce CRW images
|
||||
},
|
||||
SeparateTable => 'Canon CanonModelID',
|
||||
PrintConv => \%Image::ExifTool::Canon::canonModelID,
|
||||
},
|
||||
0x1835 => {
|
||||
Name => 'DecoderTable',
|
||||
Writable => 0,
|
||||
SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::DecoderTable' },
|
||||
},
|
||||
0x183b => { #PH
|
||||
# display format for serial number
|
||||
Name => 'SerialNumberFormat',
|
||||
Writable => 'int32u',
|
||||
PrintHex => 1,
|
||||
PrintConv => {
|
||||
0x90000000 => 'Format 1',
|
||||
0xa0000000 => 'Format 2',
|
||||
},
|
||||
},
|
||||
0x2005 => {
|
||||
Name => 'RawData',
|
||||
Writable => 0,
|
||||
Binary => 1,
|
||||
},
|
||||
0x2007 => {
|
||||
Name => 'JpgFromRaw',
|
||||
Groups => { 2 => 'Preview' },
|
||||
Writable => 'resize', # 'resize' allows this value to change size
|
||||
Permanent => 0,
|
||||
RawConv => '$self->ValidateImage(\$val,$tag)',
|
||||
},
|
||||
0x2008 => {
|
||||
Name => 'ThumbnailImage',
|
||||
Groups => { 2 => 'Preview' },
|
||||
Writable => 'resize', # 'resize' allows this value to change size
|
||||
WriteCheck => '$self->CheckImage(\$val)',
|
||||
Permanent => 0,
|
||||
RawConv => '$self->ValidateImage(\$val,$tag)',
|
||||
},
|
||||
# the following entries are subdirectories
|
||||
# (any 0x28 and 0x30 tag types are handled automatically by the decoding logic)
|
||||
0x2804 => {
|
||||
Name => 'ImageDescription',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
0x2807 => { #3
|
||||
Name => 'CameraObject',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
0x3002 => { #3
|
||||
Name => 'ShootingRecord',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
0x3003 => { #3
|
||||
Name => 'MeasuredInfo',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
0x3004 => { #3
|
||||
Name => 'CameraSpecification',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
0x300a => { #3
|
||||
Name => 'ImageProps',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
0x300b => {
|
||||
Name => 'ExifInformation',
|
||||
SubDirectory => { },
|
||||
Writable => 0,
|
||||
},
|
||||
);
|
||||
|
||||
# Canon binary data blocks
|
||||
%Image::ExifTool::CanonRaw::MakeModel = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
DATAMEMBER => [ 0, 6 ], # indices of data members to extract when writing
|
||||
WRITABLE => 1,
|
||||
FORMAT => 'string',
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
|
||||
# (can't specify a first entry because this isn't
|
||||
# a simple binary table with fixed offsets)
|
||||
0 => {
|
||||
Name => 'Make',
|
||||
Format => 'string[6]', # "Canon\0"
|
||||
DataMember => 'Make',
|
||||
RawConv => '$self->{Make} = $val',
|
||||
},
|
||||
6 => {
|
||||
Name => 'Model',
|
||||
Format => 'string', # no size = to the end of the data
|
||||
Description => 'Camera Model Name',
|
||||
DataMember => 'Model',
|
||||
RawConv => '$self->{Model} = $val',
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::CanonRaw::TimeStamp = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
WRITABLE => 1,
|
||||
FORMAT => 'int32u',
|
||||
FIRST_ENTRY => 0,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Time' },
|
||||
0 => {
|
||||
Name => 'DateTimeOriginal',
|
||||
Description => 'Date/Time Original',
|
||||
Shift => 'Time',
|
||||
ValueConv => 'ConvertUnixTime($val)',
|
||||
ValueConvInv => 'GetUnixTime($val)',
|
||||
PrintConv => '$self->ConvertDateTime($val)',
|
||||
PrintConvInv => '$self->InverseDateTime($val)',
|
||||
},
|
||||
1 => { #3
|
||||
Name => 'TimeZoneCode',
|
||||
Format => 'int32s',
|
||||
ValueConv => '$val / 3600',
|
||||
ValueConvInv => '$val * 3600',
|
||||
},
|
||||
2 => { #3
|
||||
Name => 'TimeZoneInfo',
|
||||
Notes => 'set to 0x80000000 if TimeZoneCode is valid',
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::CanonRaw::ImageFormat = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
WRITABLE => 1,
|
||||
FORMAT => 'int32u',
|
||||
FIRST_ENTRY => 0,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
0 => {
|
||||
Name => 'FileFormat',
|
||||
Flags => 'PrintHex',
|
||||
PrintConv => {
|
||||
0x00010000 => 'JPEG (lossy)',
|
||||
0x00010002 => 'JPEG (non-quantization)',
|
||||
0x00010003 => 'JPEG (lossy/non-quantization toggled)',
|
||||
0x00020001 => 'CRW',
|
||||
},
|
||||
},
|
||||
1 => {
|
||||
Name => 'TargetCompressionRatio',
|
||||
Format => 'float',
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::CanonRaw::RawJpgInfo = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
WRITABLE => 1,
|
||||
FORMAT => 'int16u',
|
||||
FIRST_ENTRY => 1,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
# 0 => 'RawJpgInfoSize',
|
||||
1 => { #PH
|
||||
Name => 'RawJpgQuality',
|
||||
PrintConv => {
|
||||
1 => 'Economy',
|
||||
2 => 'Normal',
|
||||
3 => 'Fine',
|
||||
5 => 'Superfine',
|
||||
},
|
||||
},
|
||||
2 => { #PH
|
||||
Name => 'RawJpgSize',
|
||||
PrintConv => {
|
||||
0 => 'Large',
|
||||
1 => 'Medium',
|
||||
2 => 'Small',
|
||||
},
|
||||
},
|
||||
3 => 'RawJpgWidth', #PH
|
||||
4 => 'RawJpgHeight', #PH
|
||||
);
|
||||
|
||||
%Image::ExifTool::CanonRaw::FlashInfo = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
WRITABLE => 1,
|
||||
FORMAT => 'float',
|
||||
FIRST_ENTRY => 0,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
0 => 'FlashGuideNumber',
|
||||
1 => 'FlashThreshold',
|
||||
);
|
||||
|
||||
%Image::ExifTool::CanonRaw::ExposureInfo = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
WRITABLE => 1,
|
||||
FORMAT => 'float',
|
||||
FIRST_ENTRY => 0,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
0 => 'ExposureCompensation',
|
||||
1 => {
|
||||
Name => 'ShutterSpeedValue',
|
||||
ValueConv => 'abs($val)<100 ? 1/(2**$val) : 0',
|
||||
ValueConvInv => '$val>0 ? -log($val)/log(2) : -100',
|
||||
PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
|
||||
PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
|
||||
},
|
||||
2 => {
|
||||
Name => 'ApertureValue',
|
||||
ValueConv => '2 ** ($val / 2)',
|
||||
ValueConvInv => '$val>0 ? 2*log($val)/log(2) : 0',
|
||||
PrintConv => 'sprintf("%.1f",$val)',
|
||||
PrintConvInv => '$val',
|
||||
},
|
||||
);
|
||||
|
||||
%Image::ExifTool::CanonRaw::ImageInfo = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
FORMAT => 'int32u',
|
||||
FIRST_ENTRY => 0,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
|
||||
# Note: Don't make these writable (except rotation) because it confuses
|
||||
# Canon decoding software if the are changed
|
||||
0 => 'ImageWidth', #3
|
||||
1 => 'ImageHeight', #3
|
||||
2 => { #3
|
||||
Name => 'PixelAspectRatio',
|
||||
Format => 'float',
|
||||
},
|
||||
3 => {
|
||||
Name => 'Rotation',
|
||||
Format => 'int32s',
|
||||
Writable => 'int32s',
|
||||
},
|
||||
4 => 'ComponentBitDepth', #3
|
||||
5 => 'ColorBitDepth', #3
|
||||
6 => 'ColorBW', #3
|
||||
);
|
||||
|
||||
# ref 4
|
||||
%Image::ExifTool::CanonRaw::DecoderTable = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
|
||||
FORMAT => 'int32u',
|
||||
FIRST_ENTRY => 0,
|
||||
0 => 'DecoderTableNumber',
|
||||
2 => 'CompressedDataOffset',
|
||||
3 => 'CompressedDataLength',
|
||||
);
|
||||
|
||||
# ref 1/4
|
||||
%Image::ExifTool::CanonRaw::WhiteSample = (
|
||||
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
||||
WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
|
||||
CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
|
||||
GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
|
||||
FORMAT => 'int16u',
|
||||
FIRST_ENTRY => 1,
|
||||
1 => 'WhiteSampleWidth',
|
||||
2 => 'WhiteSampleHeight',
|
||||
3 => 'WhiteSampleLeftBorder',
|
||||
4 => 'WhiteSampleTopBorder',
|
||||
5 => 'WhiteSampleBits',
|
||||
# this is followed by the encrypted white sample values (ref 1)
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# AutoLoad our writer routines when necessary
|
||||
#
|
||||
sub AUTOLOAD
|
||||
{
|
||||
return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Process Raw file directory
|
||||
# Inputs: 0) ExifTool object reference
|
||||
# 1) directory information reference, 2) tag table reference
|
||||
# Returns: 1 on success
|
||||
sub ProcessCanonRaw($$$)
|
||||
{
|
||||
my ($et, $dirInfo, $rawTagTable) = @_;
|
||||
my $blockStart = $$dirInfo{DirStart};
|
||||
my $blockSize = $$dirInfo{DirLen};
|
||||
my $raf = $$dirInfo{RAF} or return 0;
|
||||
my $buff;
|
||||
my $verbose = $et->Options('Verbose');
|
||||
my $buildMakerNotes = $et->Options('MakerNotes');
|
||||
|
||||
# 4 bytes at end of block give directory position within block
|
||||
$raf->Seek($blockStart+$blockSize-4, 0) or return 0;
|
||||
$raf->Read($buff, 4) == 4 or return 0;
|
||||
my $dirOffset = Get32u(\$buff,0) + $blockStart;
|
||||
$raf->Seek($dirOffset, 0) or return 0;
|
||||
$raf->Read($buff, 2) == 2 or return 0;
|
||||
my $entries = Get16u(\$buff,0); # get number of entries in directory
|
||||
# read the directory (10 bytes per entry)
|
||||
$raf->Read($buff, 10 * $entries) == 10 * $entries or return 0;
|
||||
|
||||
$verbose and $et->VerboseDir('CIFF', $entries);
|
||||
my $index;
|
||||
for ($index=0; $index<$entries; ++$index) {
|
||||
my $pt = 10 * $index;
|
||||
my $tag = Get16u(\$buff, $pt);
|
||||
my $size = Get32u(\$buff, $pt+2);
|
||||
my $valuePtr = Get32u(\$buff, $pt+6);
|
||||
my $ptr = $valuePtr + $blockStart; # all pointers relative to block start
|
||||
if ($tag & 0x8000) {
|
||||
$et->Warn('Bad CRW directory entry');
|
||||
return 1;
|
||||
}
|
||||
my $tagID = $tag & 0x3fff; # get tag ID
|
||||
my $tagType = ($tag >> 8) & 0x38; # get tag type
|
||||
my $valueInDir = ($tag & 0x4000); # flag for value in directory
|
||||
my $tagInfo = $et->GetTagInfo($rawTagTable, $tagID);
|
||||
if (($tagType==0x28 or $tagType==0x30) and not $valueInDir) {
|
||||
# this type of tag specifies a raw subdirectory
|
||||
my $name;
|
||||
$tagInfo and $name = $$tagInfo{Name};
|
||||
$name or $name = sprintf("CanonRaw_0x%.4x", $tag);
|
||||
my %subdirInfo = (
|
||||
DirName => $name,
|
||||
DataLen => 0,
|
||||
DirStart => $ptr,
|
||||
DirLen => $size,
|
||||
Nesting => $$dirInfo{Nesting} + 1,
|
||||
RAF => $raf,
|
||||
Parent => $$dirInfo{DirName},
|
||||
);
|
||||
if ($verbose) {
|
||||
my $fakeInfo = { Name => $name, SubDirectory => { } };
|
||||
$et->VerboseInfo($tagID, $fakeInfo,
|
||||
'Index' => $index,
|
||||
'Size' => $size,
|
||||
'Start' => $ptr,
|
||||
);
|
||||
}
|
||||
$et->ProcessDirectory(\%subdirInfo, $rawTagTable);
|
||||
next;
|
||||
}
|
||||
my ($valueDataPos, $count, $subdir);
|
||||
my $format = $crwTagFormat{$tagType};
|
||||
if ($tagInfo) {
|
||||
$subdir = $$tagInfo{SubDirectory};
|
||||
$format = $$tagInfo{Format} if $$tagInfo{Format};
|
||||
$count = $$tagInfo{Count};
|
||||
}
|
||||
# get value data
|
||||
my ($value, $delRawConv);
|
||||
if ($valueInDir) { # is the value data in the directory?
|
||||
# this type of tag stores the value in the 'size' and 'ptr' fields
|
||||
$valueDataPos = $dirOffset + $pt + 4;
|
||||
$size = 8;
|
||||
$value = substr($buff, $pt+2, $size);
|
||||
# set count to 1 by default for normal values in directory
|
||||
$count = 1 if not defined $count and $format and
|
||||
$format ne 'string' and not $subdir;
|
||||
} else {
|
||||
$valueDataPos = $ptr;
|
||||
if ($size <= 512 or ($verbose > 2 and $size <= 65536)
|
||||
or ($tagInfo and ($$tagInfo{SubDirectory}
|
||||
or grep(/^$$tagInfo{Name}$/i, $et->GetRequestedTags()) )))
|
||||
{
|
||||
# read value if size is small or specifically requested
|
||||
# or if this is a SubDirectory
|
||||
unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
|
||||
$et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
|
||||
next;
|
||||
}
|
||||
} else {
|
||||
$value = "Binary data $size bytes";
|
||||
if ($tagInfo) {
|
||||
if ($et->Options('Binary') or $verbose) {
|
||||
# read the value anyway
|
||||
unless ($raf->Seek($ptr, 0) and $raf->Read($value, $size) == $size) {
|
||||
$et->Warn(sprintf("Error reading %d bytes from 0x%x",$size,$ptr));
|
||||
next;
|
||||
}
|
||||
}
|
||||
# force this to be a binary (scalar reference)
|
||||
$$tagInfo{RawConv} = '\$val';
|
||||
$delRawConv = 1;
|
||||
}
|
||||
$size = length $value;
|
||||
undef $format;
|
||||
}
|
||||
}
|
||||
# set count from tagInfo count if necessary
|
||||
if ($format and not $count) {
|
||||
# set count according to format and size
|
||||
my $fnum = $Image::ExifTool::Exif::formatNumber{$format};
|
||||
my $fsiz = $Image::ExifTool::Exif::formatSize[$fnum];
|
||||
$count = int($size / $fsiz);
|
||||
}
|
||||
if ($verbose) {
|
||||
my $val = $value;
|
||||
$format and $val = ReadValue(\$val, 0, $format, $count, $size);
|
||||
$et->VerboseInfo($tagID, $tagInfo,
|
||||
Table => $rawTagTable,
|
||||
Index => $index,
|
||||
Value => $val,
|
||||
DataPt => \$value,
|
||||
DataPos => $valueDataPos,
|
||||
Size => $size,
|
||||
Format => $format,
|
||||
Count => $count,
|
||||
);
|
||||
}
|
||||
if ($buildMakerNotes) {
|
||||
# build maker notes information if requested
|
||||
BuildMakerNotes($et, $tagID, $tagInfo, \$value, $format, $count);
|
||||
}
|
||||
next unless defined $tagInfo;
|
||||
|
||||
if ($subdir) {
|
||||
my $name = $$tagInfo{Name};
|
||||
my $newTagTable;
|
||||
if ($$subdir{TagTable}) {
|
||||
$newTagTable = GetTagTable($$subdir{TagTable});
|
||||
unless ($newTagTable) {
|
||||
warn "Unknown tag table $$subdir{TagTable}\n";
|
||||
next;
|
||||
}
|
||||
} else {
|
||||
warn "Must specify TagTable for SubDirectory $name\n";
|
||||
next;
|
||||
}
|
||||
my $subdirStart = 0;
|
||||
#### eval Start ()
|
||||
$subdirStart = eval $$subdir{Start} if $$subdir{Start};
|
||||
my $dirData = \$value;
|
||||
my %subdirInfo = (
|
||||
Name => $name,
|
||||
DataPt => $dirData,
|
||||
DataLen => $size,
|
||||
DataPos => $valueDataPos,
|
||||
DirStart => $subdirStart,
|
||||
DirLen => $size - $subdirStart,
|
||||
Nesting => $$dirInfo{Nesting} + 1,
|
||||
RAF => $raf,
|
||||
DirName => $name,
|
||||
Parent => $$dirInfo{DirName},
|
||||
);
|
||||
#### eval Validate ($dirData, $subdirStart, $size)
|
||||
if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
|
||||
$et->Warn("Invalid $name data");
|
||||
} else {
|
||||
$et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
|
||||
}
|
||||
} else {
|
||||
# convert to specified format if necessary
|
||||
$format and $value = ReadValue(\$value, 0, $format, $count, $size);
|
||||
# save the information
|
||||
$et->FoundTag($tagInfo, $value);
|
||||
delete $$tagInfo{RawConv} if $delRawConv;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# get information from raw file
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# Returns: 1 if this was a valid Canon RAW file
|
||||
sub ProcessCRW($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my ($buff, $sig);
|
||||
my $raf = $$dirInfo{RAF};
|
||||
my $buildMakerNotes = $et->Options('MakerNotes');
|
||||
|
||||
$raf->Read($buff,2) == 2 or return 0;
|
||||
SetByteOrder($buff) or return 0;
|
||||
$raf->Read($buff,4) == 4 or return 0;
|
||||
$raf->Read($sig,8) == 8 or return 0; # get file signature
|
||||
$sig =~ /^HEAP(CCDR|JPGM)/ or return 0; # validate signature
|
||||
my $hlen = Get32u(\$buff, 0);
|
||||
|
||||
$raf->Seek(0, 2) or return 0; # seek to end of file
|
||||
my $filesize = $raf->Tell() or return 0;
|
||||
|
||||
# initialize maker note data if building maker notes
|
||||
$buildMakerNotes and InitMakerNotes($et);
|
||||
|
||||
# set the FileType tag unless already done (eg. APP0 CIFF record in JPEG image)
|
||||
$et->SetFileType();
|
||||
|
||||
# build directory information for main raw directory
|
||||
my %dirInfo = (
|
||||
DataLen => 0,
|
||||
DirStart => $hlen,
|
||||
DirLen => $filesize - $hlen,
|
||||
Nesting => 0,
|
||||
RAF => $raf,
|
||||
Parent => 'CRW',
|
||||
);
|
||||
|
||||
# process the raw directory
|
||||
my $rawTagTable = GetTagTable('Image::ExifTool::CanonRaw::Main');
|
||||
my $oldIndent = $$et{INDENT};
|
||||
$$et{INDENT} .= '| ';
|
||||
unless (ProcessCanonRaw($et, \%dirInfo, $rawTagTable)) {
|
||||
$et->Warn('CRW file format error');
|
||||
}
|
||||
$$et{INDENT} = $oldIndent;
|
||||
|
||||
# finish building maker notes if necessary
|
||||
$buildMakerNotes and SaveMakerNotes($et);
|
||||
|
||||
# process trailers if they exist in CRW file (not in CIFF information!)
|
||||
if ($$et{FILE_TYPE} eq 'CRW') {
|
||||
my $trailInfo = Image::ExifTool::IdentifyTrailer($raf);
|
||||
$et->ProcessTrailers($trailInfo) if $trailInfo;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::CanonRaw - Read Canon RAW (CRW) meta information
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is loaded automatically by Image::ExifTool when required.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to interpret
|
||||
meta information from Canon CRW raw files. These files are written directly
|
||||
by some Canon cameras, and contain meta information similar to that found in
|
||||
the EXIF Canon maker notes.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
The CR2 format written by some Canon cameras is very different the CRW
|
||||
format processed by this module. (CR2 is TIFF-based and uses standard EXIF
|
||||
tags.)
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<http://www.cybercom.net/~dcoffin/dcraw/>
|
||||
|
||||
=item L<http://www.wonderland.org/crw/>
|
||||
|
||||
=item L<http://xyrion.org/ciff/>
|
||||
|
||||
=item L<http://owl.phy.queensu.ca/~phil/exiftool/canon_raw.html>
|
||||
|
||||
=back
|
||||
|
||||
=head1 ACKNOWLEDGEMENTS
|
||||
|
||||
Thanks to Dave Nicholson for decoding a number of new tags.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/CanonRaw Tags>,
|
||||
L<Image::ExifTool::Canon(3pm)|Image::ExifTool::Canon>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: CaptureOne.pm
|
||||
#
|
||||
# Description: Read Capture One EIP and COS files
|
||||
#
|
||||
# Revisions: 2009/11/01 - P. Harvey Created
|
||||
#
|
||||
# Notes: The EIP format is a ZIP file containing an image (IIQ or TIFF)
|
||||
# and some settings files (COS). COS files are XML based.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::CaptureOne;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
use Image::ExifTool::XMP;
|
||||
use Image::ExifTool::ZIP;
|
||||
|
||||
$VERSION = '1.04';
|
||||
|
||||
# CaptureOne COS XML tags
|
||||
# - tags are added dynamically when encountered
|
||||
# - this table is not listed in tag name docs
|
||||
%Image::ExifTool::CaptureOne::Main = (
|
||||
GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
|
||||
PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP,
|
||||
VARS => { NO_ID => 1 },
|
||||
ColorCorrections => { ValueConv => '\$val' }, # (long list of floating point numbers)
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# We found an XMP property name/value
|
||||
# Inputs: 0) attribute list ref, 1) attr hash ref,
|
||||
# 2) property name ref, 3) property value ref
|
||||
# Returns: true if value was changed
|
||||
sub HandleCOSAttrs($$$$)
|
||||
{
|
||||
my ($attrList, $attrs, $prop, $valPt) = @_;
|
||||
my $changed;
|
||||
if (not length $$valPt and defined $$attrs{K} and defined $$attrs{V}) {
|
||||
$$prop = $$attrs{K};
|
||||
$$valPt = $$attrs{V};
|
||||
# remove these attributes from the list
|
||||
my @attrs = @$attrList;
|
||||
@$attrList = ( );
|
||||
my $a;
|
||||
foreach $a (@attrs) {
|
||||
if ($a eq 'K' or $a eq 'V') {
|
||||
delete $$attrs{$a};
|
||||
} else {
|
||||
push @$attrList, $a;
|
||||
}
|
||||
}
|
||||
$changed = 1;
|
||||
}
|
||||
return $changed;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# We found a COS property name/value
|
||||
# Inputs: 0) ExifTool object ref, 1) tag table ref
|
||||
# 2) reference to array of XMP property names (last is current property)
|
||||
# 3) property value, 4) attribute hash ref (not used here)
|
||||
# Returns: 1 if valid tag was found
|
||||
sub FoundCOS($$$$;$)
|
||||
{
|
||||
my ($et, $tagTablePtr, $props, $val, $attrs) = @_;
|
||||
|
||||
my $tag = $$props[-1];
|
||||
unless ($$tagTablePtr{$tag}) {
|
||||
$et->VPrint(0, " | [adding $tag]\n");
|
||||
my $name = ucfirst $tag;
|
||||
$name =~ tr/-_a-zA-Z0-9//dc;
|
||||
return 0 unless length $tag;
|
||||
my %tagInfo = ( Name => $tag );
|
||||
# try formatting any tag with "Date" in the name as a date
|
||||
# (shouldn't affect non-date tags)
|
||||
if ($name =~ /Date(?![a-z])/) {
|
||||
$tagInfo{Groups} = { 2 => 'Time' };
|
||||
$tagInfo{ValueConv} = 'Image::ExifTool::XMP::ConvertXMPDate($val,1)';
|
||||
$tagInfo{PrintConv} = '$self->ConvertDateTime($val)';
|
||||
}
|
||||
AddTagToTable($tagTablePtr, $tag, \%tagInfo);
|
||||
}
|
||||
# convert from UTF8 to ExifTool Charset
|
||||
$val = $et->Decode($val, "UTF8");
|
||||
# un-escape XML character entities
|
||||
$val = Image::ExifTool::XMP::UnescapeXML($val);
|
||||
$et->HandleTag($tagTablePtr, $tag, $val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract information from a COS file
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# Returns: 1 on success, 0 if this wasn't a valid XML file
|
||||
sub ProcessCOS($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
|
||||
# process using XMP module, but override handling of attributes and tags
|
||||
$$dirInfo{XMPParseOpts} = {
|
||||
AttrProc => \&HandleCOSAttrs,
|
||||
FoundProc => \&FoundCOS,
|
||||
};
|
||||
my $tagTablePtr = GetTagTable('Image::ExifTool::CaptureOne::Main');
|
||||
my $success = $et->ProcessDirectory($dirInfo, $tagTablePtr);
|
||||
delete $$dirInfo{XMLParseArgs};
|
||||
return $success;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Extract information from a CaptureOne EIP file
|
||||
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
||||
# Returns: 1
|
||||
# Notes: Upon entry to this routine, the file type has already been verified
|
||||
# and the dirInfo hash contains a ZIP element unique to this process proc:
|
||||
# ZIP - reference to Archive::Zip object for this file
|
||||
sub ProcessEIP($$)
|
||||
{
|
||||
my ($et, $dirInfo) = @_;
|
||||
my $zip = $$dirInfo{ZIP};
|
||||
my ($file, $buff, $status, $member, %parseFile);
|
||||
|
||||
$et->SetFileType('EIP');
|
||||
|
||||
# must catch all Archive::Zip warnings
|
||||
local $SIG{'__WARN__'} = \&Image::ExifTool::ZIP::WarnProc;
|
||||
# find all manifest files
|
||||
my @members = $zip->membersMatching('^manifest\d*.xml$');
|
||||
# and choose the one with the highest version number (any better ideas?)
|
||||
while (@members) {
|
||||
my $m = shift @members;
|
||||
my $f = $m->fileName();
|
||||
next if $file and $file gt $f;
|
||||
$member = $m;
|
||||
$file = $f;
|
||||
}
|
||||
# get file names from our chosen manifest file
|
||||
if ($member) {
|
||||
($buff, $status) = $zip->contents($member);
|
||||
if (not $status) {
|
||||
my $foundImage;
|
||||
while ($buff =~ m{<(RawPath|SettingsPath)>(.*?)</\1>}sg) {
|
||||
$file = $2;
|
||||
next unless $file =~ /\.(cos|iiq|jpe?g|tiff?)$/i;
|
||||
$parseFile{$file} = 1; # set flag to parse this file
|
||||
$foundImage = 1 unless $file =~ /\.cos$/i;
|
||||
}
|
||||
# ignore manifest unless it contained a valid image
|
||||
undef %parseFile unless $foundImage;
|
||||
}
|
||||
}
|
||||
# extract meta information from embedded files
|
||||
my $docNum = 0;
|
||||
@members = $zip->members(); # get all members
|
||||
foreach $member (@members) {
|
||||
# get filename of this ZIP member
|
||||
$file = $member->fileName();
|
||||
next unless defined $file;
|
||||
$et->VPrint(0, "File: $file\n");
|
||||
# set the document number and extract ZIP tags
|
||||
$$et{DOC_NUM} = ++$docNum;
|
||||
Image::ExifTool::ZIP::HandleMember($et, $member);
|
||||
if (%parseFile) {
|
||||
next unless $parseFile{$file};
|
||||
} else {
|
||||
# reading the manifest didn't work, so look for image files in the
|
||||
# root directory and .cos files in the CaptureOne directory
|
||||
next unless $file =~ m{^([^/]+\.(iiq|jpe?g|tiff?)|CaptureOne/.*\.cos)$}i;
|
||||
}
|
||||
# extract the contents of the file
|
||||
# Note: this could use a LOT of memory here for RAW images...
|
||||
($buff, $status) = $zip->contents($member);
|
||||
$status and $et->Warn("Error extracting $file"), next;
|
||||
if ($file =~ /\.cos$/i) {
|
||||
# process Capture One Settings files
|
||||
my %dirInfo = (
|
||||
DataPt => \$buff,
|
||||
DirLen => length $buff,
|
||||
DataLen => length $buff,
|
||||
);
|
||||
ProcessCOS($et, \%dirInfo);
|
||||
} else {
|
||||
# set HtmlDump error if necessary because it doesn't work with embedded files
|
||||
if ($$et{HTML_DUMP}) {
|
||||
$$et{HTML_DUMP}{Error} = "Sorry, can't dump images embedded in ZIP files";
|
||||
}
|
||||
# process IIQ, JPEG and TIFF images
|
||||
$et->ExtractInfo(\$buff, { ReEntry => 1 });
|
||||
}
|
||||
undef $buff; # (free memory now)
|
||||
}
|
||||
delete $$et{DOC_NUM};
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::CaptureOne - Read Capture One EIP and COS files
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is used by Image::ExifTool
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains definitions required by Image::ExifTool to extract meta
|
||||
information from Capture One EIP (Enhanced Image Package) and COS (Capture
|
||||
One Settings) files.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
The EIP format is a ZIP file containing an image (IIQ or TIFF) and some
|
||||
settings files (COS).
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool::TagNames/ZIP Tags>,
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Charset.pm
|
||||
#
|
||||
# Description: ExifTool character encoding routines
|
||||
#
|
||||
# Revisions: 2009/08/28 - P. Harvey created
|
||||
# 2010/01/20 - P. Harvey complete re-write
|
||||
# 2010/07/16 - P. Harvey added UTF-16 support
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
package Image::ExifTool::Charset;
|
||||
|
||||
use strict;
|
||||
use vars qw($VERSION %csType);
|
||||
use Image::ExifTool qw(:DataAccess :Utils);
|
||||
|
||||
$VERSION = '1.11';
|
||||
|
||||
my %charsetTable; # character set tables we've loaded
|
||||
|
||||
# lookup for converting Unicode to 1-byte character sets
|
||||
my %unicode2byte = (
|
||||
Latin => { # pre-load Latin (cp1252) for speed
|
||||
0x20ac => 0x80, 0x0160 => 0x8a, 0x2013 => 0x96,
|
||||
0x201a => 0x82, 0x2039 => 0x8b, 0x2014 => 0x97,
|
||||
0x0192 => 0x83, 0x0152 => 0x8c, 0x02dc => 0x98,
|
||||
0x201e => 0x84, 0x017d => 0x8e, 0x2122 => 0x99,
|
||||
0x2026 => 0x85, 0x2018 => 0x91, 0x0161 => 0x9a,
|
||||
0x2020 => 0x86, 0x2019 => 0x92, 0x203a => 0x9b,
|
||||
0x2021 => 0x87, 0x201c => 0x93, 0x0153 => 0x9c,
|
||||
0x02c6 => 0x88, 0x201d => 0x94, 0x017e => 0x9e,
|
||||
0x2030 => 0x89, 0x2022 => 0x95, 0x0178 => 0x9f,
|
||||
},
|
||||
);
|
||||
|
||||
# bit flags for all supported character sets
|
||||
# (this number must be correct because it dictates the decoding algorithm!)
|
||||
# 0x001 = character set requires a translation module
|
||||
# 0x002 = inverse conversion not yet supported by Recompose()
|
||||
# 0x080 = some characters with codepoints in the range 0x00-0x7f are remapped
|
||||
# 0x100 = 1-byte fixed-width characters
|
||||
# 0x200 = 2-byte fixed-width characters
|
||||
# 0x400 = 4-byte fixed-width characters
|
||||
# 0x800 = 1- and 2-byte variable-width characters, or 1-byte
|
||||
# fixed-width characters that map into multiple codepoints
|
||||
# Note: In its public interface, ExifTool can currently only support type 0x101
|
||||
# and lower character sets because strings are only converted if they
|
||||
# contain characters above 0x7f and there is no provision for specifying
|
||||
# the byte order for input/output values
|
||||
%csType = (
|
||||
UTF8 => 0x100,
|
||||
ASCII => 0x100, # (treated like UTF8)
|
||||
Arabic => 0x101,
|
||||
Baltic => 0x101,
|
||||
Cyrillic => 0x101,
|
||||
Greek => 0x101,
|
||||
Hebrew => 0x101,
|
||||
Latin => 0x101,
|
||||
Latin2 => 0x101,
|
||||
DOSLatinUS => 0x101,
|
||||
DOSLatin1 => 0x101,
|
||||
MacCroatian => 0x101,
|
||||
MacCyrillic => 0x101,
|
||||
MacGreek => 0x101,
|
||||
MacIceland => 0x101,
|
||||
MacLatin2 => 0x101,
|
||||
MacRoman => 0x101,
|
||||
MacRomanian => 0x101,
|
||||
MacTurkish => 0x101,
|
||||
Thai => 0x101,
|
||||
Turkish => 0x101,
|
||||
Vietnam => 0x101,
|
||||
MacArabic => 0x103, # (directional characters not supported)
|
||||
PDFDoc => 0x181,
|
||||
Unicode => 0x200, # (UCS2)
|
||||
UCS2 => 0x200,
|
||||
UTF16 => 0x200,
|
||||
Symbol => 0x201,
|
||||
JIS => 0x201,
|
||||
UCS4 => 0x400,
|
||||
MacChineseCN => 0x803,
|
||||
MacChineseTW => 0x803,
|
||||
MacHebrew => 0x803, # (directional characters not supported)
|
||||
MacKorean => 0x803,
|
||||
MacRSymbol => 0x803,
|
||||
MacThai => 0x803,
|
||||
MacJapanese => 0x883,
|
||||
ShiftJIS => 0x883,
|
||||
);
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Load character set module
|
||||
# Inputs: 0) Module name
|
||||
# Returns: Reference to lookup hash, or undef on error
|
||||
sub LoadCharset($)
|
||||
{
|
||||
my $charset = shift;
|
||||
my $conv = $charsetTable{$charset};
|
||||
unless ($conv) {
|
||||
# load translation module
|
||||
my $module = "Image::ExifTool::Charset::$charset";
|
||||
no strict 'refs';
|
||||
if (%$module or eval "require $module") {
|
||||
$conv = $charsetTable{$charset} = \%$module;
|
||||
}
|
||||
}
|
||||
return $conv;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Does an array contain valid UTF-16 characters?
|
||||
# Inputs: 0) array reference to list of UCS-2 values
|
||||
# Returns: 0=invalid UTF-16, 1=valid UTF-16 with no surrogates, 2=valid UTF-16 with surrogates
|
||||
sub IsUTF16($)
|
||||
{
|
||||
local $_;
|
||||
my $uni = shift;
|
||||
my $surrogate;
|
||||
foreach (@$uni) {
|
||||
my $hiBits = ($_ & 0xfc00);
|
||||
if ($hiBits == 0xfc00) {
|
||||
# check for invalid values in UTF-16
|
||||
return 0 if $_ == 0xffff or $_ == 0xfffe or ($_ >= 0xfdd0 and $_ <= 0xfdef);
|
||||
} elsif ($surrogate) {
|
||||
return 0 if $hiBits != 0xdc00;
|
||||
$surrogate = 0;
|
||||
} else {
|
||||
return 0 if $hiBits == 0xdc00;
|
||||
$surrogate = 1 if $hiBits == 0xd800;
|
||||
}
|
||||
}
|
||||
return 1 if not defined $surrogate;
|
||||
return 2 unless $surrogate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Decompose string with specified encoding into an array of integer code points
|
||||
# Inputs: 0) ExifTool object ref (or undef), 1) string, 2) character set name,
|
||||
# 3) optional byte order ('II','MM','Unknown' or undef to use ExifTool ordering)
|
||||
# Returns: Reference to array of Unicode values
|
||||
# Notes: Accepts any type of character set
|
||||
# - byte order only used for fixed-width 2-byte and 4-byte character sets
|
||||
# - byte order mark observed and then removed with UCS2 and UCS4
|
||||
# - no warnings are issued if ExifTool object is not provided
|
||||
# - sets ExifTool WrongByteOrder flag if byte order is Unknown and current order is wrong
|
||||
sub Decompose($$$;$)
|
||||
{
|
||||
local $_;
|
||||
my ($et, $val, $charset) = @_; # ($byteOrder assigned later if required)
|
||||
my $type = $csType{$charset};
|
||||
my (@uni, $conv);
|
||||
|
||||
if ($type & 0x001) {
|
||||
$conv = LoadCharset($charset);
|
||||
unless ($conv) {
|
||||
# (shouldn't happen)
|
||||
$et->Warn("Invalid character set $charset") if $et;
|
||||
return \@uni; # error!
|
||||
}
|
||||
} elsif ($type == 0x100) {
|
||||
# convert ASCII and UTF8 (treat ASCII as UTF8)
|
||||
if ($] < 5.006001) {
|
||||
# do it ourself
|
||||
@uni = Image::ExifTool::UnpackUTF8($val);
|
||||
} else {
|
||||
# handle warnings from malformed UTF-8
|
||||
undef $Image::ExifTool::evalWarning;
|
||||
local $SIG{'__WARN__'} = \&Image::ExifTool::SetWarning;
|
||||
# (somehow the meaning of "U0" was reversed in Perl 5.10.0!)
|
||||
@uni = unpack($] < 5.010000 ? 'U0U*' : 'C0U*', $val);
|
||||
# issue warning if we had errors
|
||||
if ($Image::ExifTool::evalWarning and $et and not $$et{WarnBadUTF8}) {
|
||||
$et->Warn('Malformed UTF-8 character(s)');
|
||||
$$et{WarnBadUTF8} = 1;
|
||||
}
|
||||
}
|
||||
return \@uni; # all done!
|
||||
}
|
||||
if ($type & 0x100) { # 1-byte fixed-width characters
|
||||
@uni = unpack('C*', $val);
|
||||
foreach (@uni) {
|
||||
$_ = $$conv{$_} if defined $$conv{$_};
|
||||
}
|
||||
} elsif ($type & 0x600) { # 2-byte or 4-byte fixed-width characters
|
||||
my $unknown;
|
||||
my $byteOrder = $_[3];
|
||||
if (not $byteOrder) {
|
||||
$byteOrder = GetByteOrder();
|
||||
} elsif ($byteOrder eq 'Unknown') {
|
||||
$byteOrder = GetByteOrder();
|
||||
$unknown = 1;
|
||||
}
|
||||
my $fmt = $byteOrder eq 'MM' ? 'n*' : 'v*';
|
||||
if ($type & 0x400) { # 4-byte
|
||||
$fmt = uc $fmt; # unpack as 'N*' or 'V*'
|
||||
# honour BOM if it exists
|
||||
$val =~ s/^(\0\0\xfe\xff|\xff\xfe\0\0)// and $fmt = $1 eq "\0\0\xfe\xff" ? 'N*' : 'V*';
|
||||
undef $unknown; # (byte order logic applies to 2-byte only)
|
||||
} elsif ($val =~ s/^(\xfe\xff|\xff\xfe)//) {
|
||||
$fmt = $1 eq "\xfe\xff" ? 'n*' : 'v*';
|
||||
undef $unknown;
|
||||
}
|
||||
# convert from UCS2 or UCS4
|
||||
@uni = unpack($fmt, $val);
|
||||
|
||||
if (not $conv) {
|
||||
# no translation necessary
|
||||
if ($unknown) {
|
||||
# check the byte order
|
||||
my (%bh, %bl);
|
||||
my ($zh, $zl) = (0, 0);
|
||||
foreach (@uni) {
|
||||
$bh{$_ >> 8} = 1;
|
||||
$bl{$_ & 0xff} = 1;
|
||||
++$zh unless $_ & 0xff00;
|
||||
++$zl unless $_ & 0x00ff;
|
||||
}
|
||||
# count the number of unique values in the hi and lo bytes
|
||||
my ($bh, $bl) = (scalar(keys %bh), scalar(keys %bl));
|
||||
# the byte with the greater number of unique values should be
|
||||
# the low-order byte, otherwise the byte which is zero more
|
||||
# often is likely the high-order byte
|
||||
if ($bh > $bl or ($bh == $bl and $zl > $zh)) {
|
||||
# we guessed wrong, so decode using the other byte order
|
||||
$fmt =~ tr/nvNV/vnVN/;
|
||||
@uni = unpack($fmt, $val);
|
||||
$$et{WrongByteOrder} = 1;
|
||||
}
|
||||
}
|
||||
# handle surrogate pairs of UTF-16
|
||||
if ($charset eq 'UTF16') {
|
||||
my $i;
|
||||
for ($i=0; $i<$#uni; ++$i) {
|
||||
next unless ($uni[$i] & 0xfc00) == 0xd800 and
|
||||
($uni[$i+1] & 0xfc00) == 0xdc00;
|
||||
my $cp = 0x10000 + (($uni[$i] & 0x3ff) << 10) + ($uni[$i+1] & 0x3ff);
|
||||
splice(@uni, $i, 2, $cp);
|
||||
}
|
||||
}
|
||||
} elsif ($unknown) {
|
||||
# count encoding errors as we do the translation
|
||||
my $e1 = 0;
|
||||
foreach (@uni) {
|
||||
defined $$conv{$_} and $_ = $$conv{$_}, next;
|
||||
++$e1;
|
||||
}
|
||||
# try the other byte order if we had any errors
|
||||
if ($e1) {
|
||||
$fmt = $byteOrder eq 'MM' ? 'v*' : 'n*'; #(reversed)
|
||||
my @try = unpack($fmt, $val);
|
||||
my $e2 = 0;
|
||||
foreach (@try) {
|
||||
defined $$conv{$_} and $_ = $$conv{$_}, next;
|
||||
++$e2;
|
||||
}
|
||||
# use this byte order if there are fewer errors
|
||||
if ($e2 < $e1) {
|
||||
$$et{WrongByteOrder} = 1;
|
||||
return \@try;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# translate any characters found in the lookup
|
||||
foreach (@uni) {
|
||||
$_ = $$conv{$_} if defined $$conv{$_};
|
||||
}
|
||||
}
|
||||
} else { # variable-width characters
|
||||
# unpack into bytes
|
||||
my @bytes = unpack('C*', $val);
|
||||
while (@bytes) {
|
||||
my $ch = shift @bytes;
|
||||
my $cv = $$conv{$ch};
|
||||
# pass straight through if no translation
|
||||
$cv or push(@uni, $ch), next;
|
||||
# byte translates into single Unicode character
|
||||
ref $cv or push(@uni, $cv), next;
|
||||
# byte maps into multiple Unicode characters
|
||||
ref $cv eq 'ARRAY' and push(@uni, @$cv), next;
|
||||
# handle 2-byte character codes
|
||||
$ch = shift @bytes;
|
||||
if (defined $ch) {
|
||||
if ($$cv{$ch}) {
|
||||
$cv = $$cv{$ch};
|
||||
ref $cv or push(@uni, $cv), next;
|
||||
push @uni, @$cv; # multiple Unicode characters
|
||||
} else {
|
||||
push @uni, ord('?'); # encoding error
|
||||
unshift @bytes, $ch;
|
||||
}
|
||||
} else {
|
||||
push @uni, ord('?'); # encoding error
|
||||
}
|
||||
}
|
||||
}
|
||||
return \@uni;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Convert array of code point integers into a string with specified encoding
|
||||
# Inputs: 0) ExifTool ref (or undef), 1) unicode character array ref,
|
||||
# 2) character set (note: not all types are supported)
|
||||
# 3) byte order ('MM' or 'II', multi-byte sets only, defaults to current byte order)
|
||||
# Returns: converted string (truncated at null character if it exists), empty on error
|
||||
# Notes: converts elements of input character array to new code points
|
||||
# - ExifTool ref may be undef provided $charset is defined
|
||||
sub Recompose($$;$$)
|
||||
{
|
||||
local $_;
|
||||
my ($et, $uni, $charset) = @_; # ($byteOrder assigned later if required)
|
||||
my ($outVal, $conv, $inv);
|
||||
$charset or $charset = $$et{OPTIONS}{Charset};
|
||||
my $csType = $csType{$charset};
|
||||
if ($csType == 0x100) { # UTF8 (also treat ASCII as UTF8)
|
||||
if ($] >= 5.006001) {
|
||||
# let Perl do it
|
||||
$outVal = pack('C0U*', @$uni);
|
||||
} else {
|
||||
# do it ourself
|
||||
$outVal = Image::ExifTool::PackUTF8(@$uni);
|
||||
}
|
||||
$outVal =~ s/\0.*//s; # truncate at null terminator
|
||||
return $outVal;
|
||||
}
|
||||
# get references to forward and inverse lookup tables
|
||||
if ($csType & 0x801) {
|
||||
$conv = LoadCharset($charset);
|
||||
unless ($conv) {
|
||||
$et->Warn("Missing charset $charset") if $et;
|
||||
return '';
|
||||
}
|
||||
$inv = $unicode2byte{$charset};
|
||||
# generate inverse lookup if necessary
|
||||
unless ($inv) {
|
||||
if (not $csType or $csType & 0x802) {
|
||||
$et->Warn("Invalid destination charset $charset") if $et;
|
||||
return '';
|
||||
}
|
||||
# prepare table to convert from Unicode to 1-byte characters
|
||||
my ($char, %inv);
|
||||
foreach $char (keys %$conv) {
|
||||
$inv{$$conv{$char}} = $char;
|
||||
}
|
||||
$inv = $unicode2byte{$charset} = \%inv;
|
||||
}
|
||||
}
|
||||
if ($csType & 0x100) { # 1-byte fixed-width
|
||||
# convert to specified character set
|
||||
foreach (@$uni) {
|
||||
next if $_ < 0x80;
|
||||
$$inv{$_} and $_ = $$inv{$_}, next;
|
||||
# our tables omit 1-byte characters with the same values as Unicode,
|
||||
# so pass them straight through after making sure there isn't a
|
||||
# different character with this byte value
|
||||
next if $_ < 0x100 and not $$conv{$_};
|
||||
$_ = ord('?'); # set invalid characters to '?'
|
||||
if ($et and not $$et{EncodingError}) {
|
||||
$et->Warn("Some character(s) could not be encoded in $charset");
|
||||
$$et{EncodingError} = 1;
|
||||
}
|
||||
}
|
||||
# repack as an 8-bit string and truncate at null
|
||||
$outVal = pack('C*', @$uni);
|
||||
$outVal =~ s/\0.*//s;
|
||||
} else { # 2-byte and 4-byte fixed-width
|
||||
# convert if required
|
||||
if ($inv) {
|
||||
$$inv{$_} and $_ = $$inv{$_} foreach @$uni;
|
||||
}
|
||||
# generate surrogate pairs of UTF-16
|
||||
if ($charset eq 'UTF16') {
|
||||
my $i;
|
||||
for ($i=0; $i<@$uni; ++$i) {
|
||||
next unless $$uni[$i] >= 0x10000 and $$uni[$i] < 0x10ffff;
|
||||
my $t = $$uni[$i] - 0x10000;
|
||||
my $w1 = 0xd800 + (($t >> 10) & 0x3ff);
|
||||
my $w2 = 0xdc00 + ($t & 0x3ff);
|
||||
splice(@$uni, $i, 1, $w1, $w2);
|
||||
++$i; # skip surrogate pair
|
||||
}
|
||||
}
|
||||
# pack as 2- or 4-byte integer in specified byte order
|
||||
my $byteOrder = $_[3] || GetByteOrder();
|
||||
my $fmt = $byteOrder eq 'MM' ? 'n*' : 'v*';
|
||||
$fmt = uc($fmt) if $csType & 0x400;
|
||||
$outVal = pack($fmt, @$uni);
|
||||
}
|
||||
return $outVal;
|
||||
}
|
||||
|
||||
1; # end
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Image::ExifTool::Charset - ExifTool character encoding routines
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
This module is required by Image::ExifTool.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module contains routines used by ExifTool to translate special
|
||||
character sets. Currently, the following character sets are supported:
|
||||
|
||||
UTF8, UTF16, UCS2, UCS4, Arabic, Baltic, Cyrillic, Greek, Hebrew, JIS,
|
||||
Latin, Latin2, DOSLatinUS, DOSLatin1, MacArabic, MacChineseCN,
|
||||
MacChineseTW, MacCroatian, MacCyrillic, MacGreek, MacHebrew, MacIceland,
|
||||
MacJapanese, MacKorean, MacLatin2, MacRSymbol, MacRoman, MacRomanian,
|
||||
MacThai, MacTurkish, PDFDoc, RSymbol, ShiftJIS, Symbol, Thai, Turkish,
|
||||
Vietnam
|
||||
|
||||
However, only some of these character sets are available to the user via
|
||||
ExifTool options -- the multi-byte character sets are used only internally
|
||||
when decoding certain types of information.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca)
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Image::ExifTool(3pm)|Image::ExifTool>
|
||||
|
||||
=cut
|
||||
@@ -1,39 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Arabic.pm
|
||||
#
|
||||
# Description: cp1256 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1256.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Arabic = (
|
||||
0x80 => 0x20ac, 0x81 => 0x067e, 0x82 => 0x201a, 0x83 => 0x0192,
|
||||
0x84 => 0x201e, 0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021,
|
||||
0x88 => 0x02c6, 0x89 => 0x2030, 0x8a => 0x0679, 0x8b => 0x2039,
|
||||
0x8c => 0x0152, 0x8d => 0x0686, 0x8e => 0x0698, 0x8f => 0x0688,
|
||||
0x90 => 0x06af, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c,
|
||||
0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
|
||||
0x98 => 0x06a9, 0x99 => 0x2122, 0x9a => 0x0691, 0x9b => 0x203a,
|
||||
0x9c => 0x0153, 0x9d => 0x200c, 0x9e => 0x200d, 0x9f => 0x06ba,
|
||||
0xa1 => 0x060c, 0xaa => 0x06be, 0xba => 0x061b, 0xbf => 0x061f,
|
||||
0xc0 => 0x06c1, 0xc1 => 0x0621, 0xc2 => 0x0622, 0xc3 => 0x0623,
|
||||
0xc4 => 0x0624, 0xc5 => 0x0625, 0xc6 => 0x0626, 0xc7 => 0x0627,
|
||||
0xc8 => 0x0628, 0xc9 => 0x0629, 0xca => 0x062a, 0xcb => 0x062b,
|
||||
0xcc => 0x062c, 0xcd => 0x062d, 0xce => 0x062e, 0xcf => 0x062f,
|
||||
0xd0 => 0x0630, 0xd1 => 0x0631, 0xd2 => 0x0632, 0xd3 => 0x0633,
|
||||
0xd4 => 0x0634, 0xd5 => 0x0635, 0xd6 => 0x0636, 0xd8 => 0x0637,
|
||||
0xd9 => 0x0638, 0xda => 0x0639, 0xdb => 0x063a, 0xdc => 0x0640,
|
||||
0xdd => 0x0641, 0xde => 0x0642, 0xdf => 0x0643, 0xe1 => 0x0644,
|
||||
0xe3 => 0x0645, 0xe4 => 0x0646, 0xe5 => 0x0647, 0xe6 => 0x0648,
|
||||
0xec => 0x0649, 0xed => 0x064a, 0xf0 => 0x064b, 0xf1 => 0x064c,
|
||||
0xf2 => 0x064d, 0xf3 => 0x064e, 0xf5 => 0x064f, 0xf6 => 0x0650,
|
||||
0xf8 => 0x0651, 0xfa => 0x0652, 0xfd => 0x200e, 0xfe => 0x200f,
|
||||
0xff => 0x06d2,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,35 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Baltic.pm
|
||||
#
|
||||
# Description: cp1257 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1257.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Baltic = (
|
||||
0x80 => 0x20ac, 0x82 => 0x201a, 0x84 => 0x201e, 0x85 => 0x2026,
|
||||
0x86 => 0x2020, 0x87 => 0x2021, 0x89 => 0x2030, 0x8b => 0x2039, 0x8d => 0xa8,
|
||||
0x8e => 0x02c7, 0x8f => 0xb8, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c,
|
||||
0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
|
||||
0x99 => 0x2122, 0x9b => 0x203a, 0x9d => 0xaf, 0x9e => 0x02db, 0xa8 => 0xd8,
|
||||
0xaa => 0x0156, 0xaf => 0xc6, 0xb8 => 0xf8, 0xba => 0x0157, 0xbf => 0xe6,
|
||||
0xc0 => 0x0104, 0xc1 => 0x012e, 0xc2 => 0x0100, 0xc3 => 0x0106,
|
||||
0xc6 => 0x0118, 0xc7 => 0x0112, 0xc8 => 0x010c, 0xca => 0x0179,
|
||||
0xcb => 0x0116, 0xcc => 0x0122, 0xcd => 0x0136, 0xce => 0x012a,
|
||||
0xcf => 0x013b, 0xd0 => 0x0160, 0xd1 => 0x0143, 0xd2 => 0x0145,
|
||||
0xd4 => 0x014c, 0xd8 => 0x0172, 0xd9 => 0x0141, 0xda => 0x015a,
|
||||
0xdb => 0x016a, 0xdd => 0x017b, 0xde => 0x017d, 0xe0 => 0x0105,
|
||||
0xe1 => 0x012f, 0xe2 => 0x0101, 0xe3 => 0x0107, 0xe6 => 0x0119,
|
||||
0xe7 => 0x0113, 0xe8 => 0x010d, 0xea => 0x017a, 0xeb => 0x0117,
|
||||
0xec => 0x0123, 0xed => 0x0137, 0xee => 0x012b, 0xef => 0x013c,
|
||||
0xf0 => 0x0161, 0xf1 => 0x0144, 0xf2 => 0x0146, 0xf4 => 0x014d,
|
||||
0xf8 => 0x0173, 0xf9 => 0x0142, 0xfa => 0x015b, 0xfb => 0x016b,
|
||||
0xfd => 0x017c, 0xfe => 0x017e, 0xff => 0x02d9,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,45 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Cyrillic.pm
|
||||
#
|
||||
# Description: cp1251 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Cyrillic = (
|
||||
0x80 => 0x0402, 0x81 => 0x0403, 0x82 => 0x201a, 0x83 => 0x0453,
|
||||
0x84 => 0x201e, 0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021,
|
||||
0x88 => 0x20ac, 0x89 => 0x2030, 0x8a => 0x0409, 0x8b => 0x2039,
|
||||
0x8c => 0x040a, 0x8d => 0x040c, 0x8e => 0x040b, 0x8f => 0x040f,
|
||||
0x90 => 0x0452, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c,
|
||||
0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
|
||||
0x99 => 0x2122, 0x9a => 0x0459, 0x9b => 0x203a, 0x9c => 0x045a,
|
||||
0x9d => 0x045c, 0x9e => 0x045b, 0x9f => 0x045f, 0xa1 => 0x040e,
|
||||
0xa2 => 0x045e, 0xa3 => 0x0408, 0xa5 => 0x0490, 0xa8 => 0x0401,
|
||||
0xaa => 0x0404, 0xaf => 0x0407, 0xb2 => 0x0406, 0xb3 => 0x0456,
|
||||
0xb4 => 0x0491, 0xb8 => 0x0451, 0xb9 => 0x2116, 0xba => 0x0454,
|
||||
0xbc => 0x0458, 0xbd => 0x0405, 0xbe => 0x0455, 0xbf => 0x0457,
|
||||
0xc0 => 0x0410, 0xc1 => 0x0411, 0xc2 => 0x0412, 0xc3 => 0x0413,
|
||||
0xc4 => 0x0414, 0xc5 => 0x0415, 0xc6 => 0x0416, 0xc7 => 0x0417,
|
||||
0xc8 => 0x0418, 0xc9 => 0x0419, 0xca => 0x041a, 0xcb => 0x041b,
|
||||
0xcc => 0x041c, 0xcd => 0x041d, 0xce => 0x041e, 0xcf => 0x041f,
|
||||
0xd0 => 0x0420, 0xd1 => 0x0421, 0xd2 => 0x0422, 0xd3 => 0x0423,
|
||||
0xd4 => 0x0424, 0xd5 => 0x0425, 0xd6 => 0x0426, 0xd7 => 0x0427,
|
||||
0xd8 => 0x0428, 0xd9 => 0x0429, 0xda => 0x042a, 0xdb => 0x042b,
|
||||
0xdc => 0x042c, 0xdd => 0x042d, 0xde => 0x042e, 0xdf => 0x042f,
|
||||
0xe0 => 0x0430, 0xe1 => 0x0431, 0xe2 => 0x0432, 0xe3 => 0x0433,
|
||||
0xe4 => 0x0434, 0xe5 => 0x0435, 0xe6 => 0x0436, 0xe7 => 0x0437,
|
||||
0xe8 => 0x0438, 0xe9 => 0x0439, 0xea => 0x043a, 0xeb => 0x043b,
|
||||
0xec => 0x043c, 0xed => 0x043d, 0xee => 0x043e, 0xef => 0x043f,
|
||||
0xf0 => 0x0440, 0xf1 => 0x0441, 0xf2 => 0x0442, 0xf3 => 0x0443,
|
||||
0xf4 => 0x0444, 0xf5 => 0x0445, 0xf6 => 0x0446, 0xf7 => 0x0447,
|
||||
0xf8 => 0x0448, 0xf9 => 0x0449, 0xfa => 0x044a, 0xfb => 0x044b,
|
||||
0xfc => 0x044c, 0xfd => 0x044d, 0xfe => 0x044e, 0xff => 0x044f,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,49 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: DOSLatin1.pm
|
||||
#
|
||||
# Description: cp850 to Unicode
|
||||
#
|
||||
# Revisions: 2017/10/31- P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP850.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::DOSLatin1 = (
|
||||
0x80 => 0x00c7, 0x81 => 0x00fc, 0x82 => 0x00e9, 0x83 => 0x00e2,
|
||||
0x84 => 0x00e4, 0x85 => 0x00e0, 0x86 => 0x00e5, 0x87 => 0x00e7,
|
||||
0x88 => 0x00ea, 0x89 => 0x00eb, 0x8a => 0x00e8, 0x8b => 0x00ef,
|
||||
0x8c => 0x00ee, 0x8d => 0x00ec, 0x8e => 0x00c4, 0x8f => 0x00c5,
|
||||
0x90 => 0x00c9, 0x91 => 0x00e6, 0x92 => 0x00c6, 0x93 => 0x00f4,
|
||||
0x94 => 0x00f6, 0x95 => 0x00f2, 0x96 => 0x00fb, 0x97 => 0x00f9,
|
||||
0x98 => 0x00ff, 0x99 => 0x00d6, 0x9a => 0x00dc, 0x9b => 0x00f8,
|
||||
0x9c => 0x00a3, 0x9d => 0x00d8, 0x9e => 0x00d7, 0x9f => 0x0192,
|
||||
0xa0 => 0x00e1, 0xa1 => 0x00ed, 0xa2 => 0x00f3, 0xa3 => 0x00fa,
|
||||
0xa4 => 0x00f1, 0xa5 => 0x00d1, 0xa6 => 0x00aa, 0xa7 => 0x00ba,
|
||||
0xa8 => 0x00bf, 0xa9 => 0x00ae, 0xaa => 0x00ac, 0xab => 0x00bd,
|
||||
0xac => 0x00bc, 0xad => 0x00a1, 0xae => 0x00ab, 0xaf => 0x00bb,
|
||||
0xb0 => 0x2591, 0xb1 => 0x2592, 0xb2 => 0x2593, 0xb3 => 0x2502,
|
||||
0xb4 => 0x2524, 0xb5 => 0x00c1, 0xb6 => 0x00c2, 0xb7 => 0x00c0,
|
||||
0xb8 => 0x00a9, 0xb9 => 0x2563, 0xba => 0x2551, 0xbb => 0x2557,
|
||||
0xbc => 0x255d, 0xbd => 0x00a2, 0xbe => 0x00a5, 0xbf => 0x2510,
|
||||
0xc0 => 0x2514, 0xc1 => 0x2534, 0xc2 => 0x252c, 0xc3 => 0x251c,
|
||||
0xc4 => 0x2500, 0xc5 => 0x253c, 0xc6 => 0x00e3, 0xc7 => 0x00c3,
|
||||
0xc8 => 0x255a, 0xc9 => 0x2554, 0xca => 0x2569, 0xcb => 0x2566,
|
||||
0xcc => 0x2560, 0xcd => 0x2550, 0xce => 0x256c, 0xcf => 0x00a4,
|
||||
0xd0 => 0x00f0, 0xd1 => 0x00d0, 0xd2 => 0x00ca, 0xd3 => 0x00cb,
|
||||
0xd4 => 0x00c8, 0xd5 => 0x0131, 0xd6 => 0x00cd, 0xd7 => 0x00ce,
|
||||
0xd8 => 0x00cf, 0xd9 => 0x2518, 0xda => 0x250c, 0xdb => 0x2588,
|
||||
0xdc => 0x2584, 0xdd => 0x00a6, 0xde => 0x00cc, 0xdf => 0x2580,
|
||||
0xe0 => 0x00d3, 0xe1 => 0x00df, 0xe2 => 0x00d4, 0xe3 => 0x00d2,
|
||||
0xe4 => 0x00f5, 0xe5 => 0x00d5, 0xe6 => 0x00b5, 0xe7 => 0x00fe,
|
||||
0xe8 => 0x00de, 0xe9 => 0x00da, 0xea => 0x00db, 0xeb => 0x00d9,
|
||||
0xec => 0x00fd, 0xed => 0x00dd, 0xee => 0x00af, 0xef => 0x00b4,
|
||||
0xf0 => 0x00ad, 0xf1 => 0x00b1, 0xf2 => 0x2017, 0xf3 => 0x00be,
|
||||
0xf4 => 0x00b6, 0xf5 => 0x00a7, 0xf6 => 0x00f7, 0xf7 => 0x00b8,
|
||||
0xf8 => 0x00b0, 0xf9 => 0x00a8, 0xfa => 0x00b7, 0xfb => 0x00b9,
|
||||
0xfc => 0x00b3, 0xfd => 0x00b2, 0xfe => 0x25a0, 0xff => 0x00a0,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,49 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: DOSLatinUS.pm
|
||||
#
|
||||
# Description: cp437 to Unicode
|
||||
#
|
||||
# Revisions: 2017/10/31- P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::DOSLatinUS = (
|
||||
0x80 => 0x00c7, 0x81 => 0x00fc, 0x82 => 0x00e9, 0x83 => 0x00e2,
|
||||
0x84 => 0x00e4, 0x85 => 0x00e0, 0x86 => 0x00e5, 0x87 => 0x00e7,
|
||||
0x88 => 0x00ea, 0x89 => 0x00eb, 0x8a => 0x00e8, 0x8b => 0x00ef,
|
||||
0x8c => 0x00ee, 0x8d => 0x00ec, 0x8e => 0x00c4, 0x8f => 0x00c5,
|
||||
0x90 => 0x00c9, 0x91 => 0x00e6, 0x92 => 0x00c6, 0x93 => 0x00f4,
|
||||
0x94 => 0x00f6, 0x95 => 0x00f2, 0x96 => 0x00fb, 0x97 => 0x00f9,
|
||||
0x98 => 0x00ff, 0x99 => 0x00d6, 0x9a => 0x00dc, 0x9b => 0x00a2,
|
||||
0x9c => 0x00a3, 0x9d => 0x00a5, 0x9e => 0x20a7, 0x9f => 0x0192,
|
||||
0xa0 => 0x00e1, 0xa1 => 0x00ed, 0xa2 => 0x00f3, 0xa3 => 0x00fa,
|
||||
0xa4 => 0x00f1, 0xa5 => 0x00d1, 0xa6 => 0x00aa, 0xa7 => 0x00ba,
|
||||
0xa8 => 0x00bf, 0xa9 => 0x2310, 0xaa => 0x00ac, 0xab => 0x00bd,
|
||||
0xac => 0x00bc, 0xad => 0x00a1, 0xae => 0x00ab, 0xaf => 0x00bb,
|
||||
0xb0 => 0x2591, 0xb1 => 0x2592, 0xb2 => 0x2593, 0xb3 => 0x2502,
|
||||
0xb4 => 0x2524, 0xb5 => 0x2561, 0xb6 => 0x2562, 0xb7 => 0x2556,
|
||||
0xb8 => 0x2555, 0xb9 => 0x2563, 0xba => 0x2551, 0xbb => 0x2557,
|
||||
0xbc => 0x255d, 0xbd => 0x255c, 0xbe => 0x255b, 0xbf => 0x2510,
|
||||
0xc0 => 0x2514, 0xc1 => 0x2534, 0xc2 => 0x252c, 0xc3 => 0x251c,
|
||||
0xc4 => 0x2500, 0xc5 => 0x253c, 0xc6 => 0x255e, 0xc7 => 0x255f,
|
||||
0xc8 => 0x255a, 0xc9 => 0x2554, 0xca => 0x2569, 0xcb => 0x2566,
|
||||
0xcc => 0x2560, 0xcd => 0x2550, 0xce => 0x256c, 0xcf => 0x2567,
|
||||
0xd0 => 0x2568, 0xd1 => 0x2564, 0xd2 => 0x2565, 0xd3 => 0x2559,
|
||||
0xd4 => 0x2558, 0xd5 => 0x2552, 0xd6 => 0x2553, 0xd7 => 0x256b,
|
||||
0xd8 => 0x256a, 0xd9 => 0x2518, 0xda => 0x250c, 0xdb => 0x2588,
|
||||
0xdc => 0x2584, 0xdd => 0x258c, 0xde => 0x2590, 0xdf => 0x2580,
|
||||
0xe0 => 0x03b1, 0xe1 => 0x00df, 0xe2 => 0x0393, 0xe3 => 0x03c0,
|
||||
0xe4 => 0x03a3, 0xe5 => 0x03c3, 0xe6 => 0x00b5, 0xe7 => 0x03c4,
|
||||
0xe8 => 0x03a6, 0xe9 => 0x0398, 0xea => 0x03a9, 0xeb => 0x03b4,
|
||||
0xec => 0x221e, 0xed => 0x03c6, 0xee => 0x03b5, 0xef => 0x2229,
|
||||
0xf0 => 0x2261, 0xf1 => 0x00b1, 0xf2 => 0x2265, 0xf3 => 0x2264,
|
||||
0xf4 => 0x2320, 0xf5 => 0x2321, 0xf6 => 0x00f7, 0xf7 => 0x2248,
|
||||
0xf8 => 0x00b0, 0xf9 => 0x2219, 0xfa => 0x00b7, 0xfb => 0x221a,
|
||||
0xfc => 0x207f, 0xfd => 0x00b2, 0xfe => 0x25a0, 0xff => 0x00a0,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,40 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Greek.pm
|
||||
#
|
||||
# Description: cp1253 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1253.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Greek = (
|
||||
0x80 => 0x20ac, 0x82 => 0x201a, 0x83 => 0x0192, 0x84 => 0x201e,
|
||||
0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021, 0x89 => 0x2030,
|
||||
0x8b => 0x2039, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c,
|
||||
0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
|
||||
0x99 => 0x2122, 0x9b => 0x203a, 0xa1 => 0x0385, 0xa2 => 0x0386,
|
||||
0xaf => 0x2015, 0xb4 => 0x0384, 0xb8 => 0x0388, 0xb9 => 0x0389,
|
||||
0xba => 0x038a, 0xbc => 0x038c, 0xbe => 0x038e, 0xbf => 0x038f,
|
||||
0xc0 => 0x0390, 0xc1 => 0x0391, 0xc2 => 0x0392, 0xc3 => 0x0393,
|
||||
0xc4 => 0x0394, 0xc5 => 0x0395, 0xc6 => 0x0396, 0xc7 => 0x0397,
|
||||
0xc8 => 0x0398, 0xc9 => 0x0399, 0xca => 0x039a, 0xcb => 0x039b,
|
||||
0xcc => 0x039c, 0xcd => 0x039d, 0xce => 0x039e, 0xcf => 0x039f,
|
||||
0xd0 => 0x03a0, 0xd1 => 0x03a1, 0xd3 => 0x03a3, 0xd4 => 0x03a4,
|
||||
0xd5 => 0x03a5, 0xd6 => 0x03a6, 0xd7 => 0x03a7, 0xd8 => 0x03a8,
|
||||
0xd9 => 0x03a9, 0xda => 0x03aa, 0xdb => 0x03ab, 0xdc => 0x03ac,
|
||||
0xdd => 0x03ad, 0xde => 0x03ae, 0xdf => 0x03af, 0xe0 => 0x03b0,
|
||||
0xe1 => 0x03b1, 0xe2 => 0x03b2, 0xe3 => 0x03b3, 0xe4 => 0x03b4,
|
||||
0xe5 => 0x03b5, 0xe6 => 0x03b6, 0xe7 => 0x03b7, 0xe8 => 0x03b8,
|
||||
0xe9 => 0x03b9, 0xea => 0x03ba, 0xeb => 0x03bb, 0xec => 0x03bc,
|
||||
0xed => 0x03bd, 0xee => 0x03be, 0xef => 0x03bf, 0xf0 => 0x03c0,
|
||||
0xf1 => 0x03c1, 0xf2 => 0x03c2, 0xf3 => 0x03c3, 0xf4 => 0x03c4,
|
||||
0xf5 => 0x03c5, 0xf6 => 0x03c6, 0xf7 => 0x03c7, 0xf8 => 0x03c8,
|
||||
0xf9 => 0x03c9, 0xfa => 0x03ca, 0xfb => 0x03cb, 0xfc => 0x03cc,
|
||||
0xfd => 0x03cd, 0xfe => 0x03ce,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,36 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Hebrew.pm
|
||||
#
|
||||
# Description: cp1255 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1255.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Hebrew = (
|
||||
0x80 => 0x20ac, 0x82 => 0x201a, 0x83 => 0x0192, 0x84 => 0x201e,
|
||||
0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021, 0x88 => 0x02c6,
|
||||
0x89 => 0x2030, 0x8b => 0x2039, 0x91 => 0x2018, 0x92 => 0x2019,
|
||||
0x93 => 0x201c, 0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013,
|
||||
0x97 => 0x2014, 0x98 => 0x02dc, 0x99 => 0x2122, 0x9b => 0x203a,
|
||||
0xa4 => 0x20aa, 0xaa => 0xd7, 0xba => 0xf7, 0xc0 => 0x05b0, 0xc1 => 0x05b1,
|
||||
0xc2 => 0x05b2, 0xc3 => 0x05b3, 0xc4 => 0x05b4, 0xc5 => 0x05b5,
|
||||
0xc6 => 0x05b6, 0xc7 => 0x05b7, 0xc8 => 0x05b8, 0xc9 => 0x05b9,
|
||||
0xcb => 0x05bb, 0xcc => 0x05bc, 0xcd => 0x05bd, 0xce => 0x05be,
|
||||
0xcf => 0x05bf, 0xd0 => 0x05c0, 0xd1 => 0x05c1, 0xd2 => 0x05c2,
|
||||
0xd3 => 0x05c3, 0xd4 => 0x05f0, 0xd5 => 0x05f1, 0xd6 => 0x05f2,
|
||||
0xd7 => 0x05f3, 0xd8 => 0x05f4, 0xe0 => 0x05d0, 0xe1 => 0x05d1,
|
||||
0xe2 => 0x05d2, 0xe3 => 0x05d3, 0xe4 => 0x05d4, 0xe5 => 0x05d5,
|
||||
0xe6 => 0x05d6, 0xe7 => 0x05d7, 0xe8 => 0x05d8, 0xe9 => 0x05d9,
|
||||
0xea => 0x05da, 0xeb => 0x05db, 0xec => 0x05dc, 0xed => 0x05dd,
|
||||
0xee => 0x05de, 0xef => 0x05df, 0xf0 => 0x05e0, 0xf1 => 0x05e1,
|
||||
0xf2 => 0x05e2, 0xf3 => 0x05e3, 0xf4 => 0x05e4, 0xf5 => 0x05e5,
|
||||
0xf6 => 0x05e6, 0xf7 => 0x05e7, 0xf8 => 0x05e8, 0xf9 => 0x05e9,
|
||||
0xfa => 0x05ea, 0xfd => 0x200e, 0xfe => 0x200f,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,24 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Latin.pm
|
||||
#
|
||||
# Description: cp1252 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Latin = (
|
||||
0x80 => 0x20ac, 0x82 => 0x201a, 0x83 => 0x0192, 0x84 => 0x201e,
|
||||
0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021, 0x88 => 0x02c6,
|
||||
0x89 => 0x2030, 0x8a => 0x0160, 0x8b => 0x2039, 0x8c => 0x0152,
|
||||
0x8e => 0x017d, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c,
|
||||
0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
|
||||
0x98 => 0x02dc, 0x99 => 0x2122, 0x9a => 0x0161, 0x9b => 0x203a,
|
||||
0x9c => 0x0153, 0x9e => 0x017e, 0x9f => 0x0178,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,36 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Latin2.pm
|
||||
#
|
||||
# Description: cp1250 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1250.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Latin2 = (
|
||||
0x80 => 0x20ac, 0x82 => 0x201a, 0x84 => 0x201e, 0x85 => 0x2026,
|
||||
0x86 => 0x2020, 0x87 => 0x2021, 0x89 => 0x2030, 0x8a => 0x0160,
|
||||
0x8b => 0x2039, 0x8c => 0x015a, 0x8d => 0x0164, 0x8e => 0x017d,
|
||||
0x8f => 0x0179, 0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c,
|
||||
0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014,
|
||||
0x99 => 0x2122, 0x9a => 0x0161, 0x9b => 0x203a, 0x9c => 0x015b,
|
||||
0x9d => 0x0165, 0x9e => 0x017e, 0x9f => 0x017a, 0xa1 => 0x02c7,
|
||||
0xa2 => 0x02d8, 0xa3 => 0x0141, 0xa5 => 0x0104, 0xaa => 0x015e,
|
||||
0xaf => 0x017b, 0xb2 => 0x02db, 0xb3 => 0x0142, 0xb9 => 0x0105,
|
||||
0xba => 0x015f, 0xbc => 0x013d, 0xbd => 0x02dd, 0xbe => 0x013e,
|
||||
0xbf => 0x017c, 0xc0 => 0x0154, 0xc3 => 0x0102, 0xc5 => 0x0139,
|
||||
0xc6 => 0x0106, 0xc8 => 0x010c, 0xca => 0x0118, 0xcc => 0x011a,
|
||||
0xcf => 0x010e, 0xd0 => 0x0110, 0xd1 => 0x0143, 0xd2 => 0x0147,
|
||||
0xd5 => 0x0150, 0xd8 => 0x0158, 0xd9 => 0x016e, 0xdb => 0x0170,
|
||||
0xde => 0x0162, 0xe0 => 0x0155, 0xe3 => 0x0103, 0xe5 => 0x013a,
|
||||
0xe6 => 0x0107, 0xe8 => 0x010d, 0xea => 0x0119, 0xec => 0x011b,
|
||||
0xef => 0x010f, 0xf0 => 0x0111, 0xf1 => 0x0144, 0xf2 => 0x0148,
|
||||
0xf5 => 0x0151, 0xf8 => 0x0159, 0xf9 => 0x016f, 0xfb => 0x0171,
|
||||
0xfe => 0x0163, 0xff => 0x02d9,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,47 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacArabic.pm
|
||||
#
|
||||
# Description: Mac Arabic to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ARABIC.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
# and directional characters are ignored
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacArabic = (
|
||||
0x80 => 0xc4, 0x81 => 0xa0, 0x82 => 0xc7, 0x83 => 0xc9, 0x84 => 0xd1,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0x06ba, 0x8c => 0xab, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed, 0x93 => 0x2026,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3, 0x98 => 0xbb,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf7, 0x9c => 0xfa, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x20, 0xa1 => 0x21, 0xa2 => 0x22,
|
||||
0xa3 => 0x23, 0xa4 => 0x24, 0xa5 => 0x066a, 0xa6 => 0x26, 0xa7 => 0x27,
|
||||
0xa8 => 0x28, 0xa9 => 0x29, 0xaa => 0x2a, 0xab => 0x2b, 0xac => 0x060c,
|
||||
0xad => 0x2d, 0xae => 0x2e, 0xaf => 0x2f, 0xb0 => 0x0660, 0xb1 => 0x0661,
|
||||
0xb2 => 0x0662, 0xb3 => 0x0663, 0xb4 => 0x0664, 0xb5 => 0x0665,
|
||||
0xb6 => 0x0666, 0xb7 => 0x0667, 0xb8 => 0x0668, 0xb9 => 0x0669, 0xba => 0x3a,
|
||||
0xbb => 0x061b, 0xbc => 0x3c, 0xbd => 0x3d, 0xbe => 0x3e, 0xbf => 0x061f,
|
||||
0xc0 => 0x274a, 0xc1 => 0x0621, 0xc2 => 0x0622, 0xc3 => 0x0623,
|
||||
0xc4 => 0x0624, 0xc5 => 0x0625, 0xc6 => 0x0626, 0xc7 => 0x0627,
|
||||
0xc8 => 0x0628, 0xc9 => 0x0629, 0xca => 0x062a, 0xcb => 0x062b,
|
||||
0xcc => 0x062c, 0xcd => 0x062d, 0xce => 0x062e, 0xcf => 0x062f,
|
||||
0xd0 => 0x0630, 0xd1 => 0x0631, 0xd2 => 0x0632, 0xd3 => 0x0633,
|
||||
0xd4 => 0x0634, 0xd5 => 0x0635, 0xd6 => 0x0636, 0xd7 => 0x0637,
|
||||
0xd8 => 0x0638, 0xd9 => 0x0639, 0xda => 0x063a, 0xdb => 0x5b, 0xdc => 0x5c,
|
||||
0xdd => 0x5d, 0xde => 0x5e, 0xdf => 0x5f, 0xe0 => 0x0640, 0xe1 => 0x0641,
|
||||
0xe2 => 0x0642, 0xe3 => 0x0643, 0xe4 => 0x0644, 0xe5 => 0x0645,
|
||||
0xe6 => 0x0646, 0xe7 => 0x0647, 0xe8 => 0x0648, 0xe9 => 0x0649,
|
||||
0xea => 0x064a, 0xeb => 0x064b, 0xec => 0x064c, 0xed => 0x064d,
|
||||
0xee => 0x064e, 0xef => 0x064f, 0xf0 => 0x0650, 0xf1 => 0x0651,
|
||||
0xf2 => 0x0652, 0xf3 => 0x067e, 0xf4 => 0x0679, 0xf5 => 0x0686,
|
||||
0xf6 => 0x06d5, 0xf7 => 0x06a4, 0xf8 => 0x06af, 0xf9 => 0x0688,
|
||||
0xfa => 0x0691, 0xfb => 0x7b, 0xfc => 0x7c, 0xfd => 0x7d, 0xfe => 0x0698,
|
||||
0xff => 0x06d2,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,43 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacCroatian.pm
|
||||
#
|
||||
# Description: Mac Croatian to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/CROATIAN.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacCroatian = (
|
||||
0x80 => 0xc4, 0x81 => 0xc5, 0x82 => 0xc7, 0x83 => 0xc9, 0x84 => 0xd1,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0xe3, 0x8c => 0xe5, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed, 0x93 => 0xec,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3, 0x98 => 0xf2,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x2020, 0xa1 => 0xb0, 0xa4 => 0xa7,
|
||||
0xa5 => 0x2022, 0xa6 => 0xb6, 0xa7 => 0xdf, 0xa8 => 0xae, 0xa9 => 0x0160,
|
||||
0xaa => 0x2122, 0xab => 0xb4, 0xac => 0xa8, 0xad => 0x2260, 0xae => 0x017d,
|
||||
0xaf => 0xd8, 0xb0 => 0x221e, 0xb2 => 0x2264, 0xb3 => 0x2265, 0xb4 => 0x2206,
|
||||
0xb6 => 0x2202, 0xb7 => 0x2211, 0xb8 => 0x220f, 0xb9 => 0x0161,
|
||||
0xba => 0x222b, 0xbb => 0xaa, 0xbc => 0xba, 0xbd => 0x03a9, 0xbe => 0x017e,
|
||||
0xbf => 0xf8, 0xc0 => 0xbf, 0xc1 => 0xa1, 0xc2 => 0xac, 0xc3 => 0x221a,
|
||||
0xc4 => 0x0192, 0xc5 => 0x2248, 0xc6 => 0x0106, 0xc7 => 0xab, 0xc8 => 0x010c,
|
||||
0xc9 => 0x2026, 0xca => 0xa0, 0xcb => 0xc0, 0xcc => 0xc3, 0xcd => 0xd5,
|
||||
0xce => 0x0152, 0xcf => 0x0153, 0xd0 => 0x0110, 0xd1 => 0x2014,
|
||||
0xd2 => 0x201c, 0xd3 => 0x201d, 0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7,
|
||||
0xd7 => 0x25ca, 0xd8 => 0xf8ff, 0xd9 => 0xa9, 0xda => 0x2044, 0xdb => 0x20ac,
|
||||
0xdc => 0x2039, 0xdd => 0x203a, 0xde => 0xc6, 0xdf => 0xbb, 0xe0 => 0x2013,
|
||||
0xe1 => 0xb7, 0xe2 => 0x201a, 0xe3 => 0x201e, 0xe4 => 0x2030, 0xe5 => 0xc2,
|
||||
0xe6 => 0x0107, 0xe7 => 0xc1, 0xe8 => 0x010d, 0xe9 => 0xc8, 0xea => 0xcd,
|
||||
0xeb => 0xce, 0xec => 0xcf, 0xed => 0xcc, 0xee => 0xd3, 0xef => 0xd4,
|
||||
0xf0 => 0x0111, 0xf1 => 0xd2, 0xf2 => 0xda, 0xf3 => 0xdb, 0xf4 => 0xd9,
|
||||
0xf5 => 0x0131, 0xf6 => 0x02c6, 0xf7 => 0x02dc, 0xf8 => 0xaf, 0xf9 => 0x03c0,
|
||||
0xfa => 0xcb, 0xfb => 0x02da, 0xfc => 0xb8, 0xfd => 0xca, 0xfe => 0xe6,
|
||||
0xff => 0x02c7,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,47 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacCyrillic.pm
|
||||
#
|
||||
# Description: Mac Cyrillic to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/CYRILLIC.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacCyrillic = (
|
||||
0x80 => 0x0410, 0x81 => 0x0411, 0x82 => 0x0412, 0x83 => 0x0413,
|
||||
0x84 => 0x0414, 0x85 => 0x0415, 0x86 => 0x0416, 0x87 => 0x0417,
|
||||
0x88 => 0x0418, 0x89 => 0x0419, 0x8a => 0x041a, 0x8b => 0x041b,
|
||||
0x8c => 0x041c, 0x8d => 0x041d, 0x8e => 0x041e, 0x8f => 0x041f,
|
||||
0x90 => 0x0420, 0x91 => 0x0421, 0x92 => 0x0422, 0x93 => 0x0423,
|
||||
0x94 => 0x0424, 0x95 => 0x0425, 0x96 => 0x0426, 0x97 => 0x0427,
|
||||
0x98 => 0x0428, 0x99 => 0x0429, 0x9a => 0x042a, 0x9b => 0x042b,
|
||||
0x9c => 0x042c, 0x9d => 0x042d, 0x9e => 0x042e, 0x9f => 0x042f,
|
||||
0xa0 => 0x2020, 0xa1 => 0xb0, 0xa2 => 0x0490, 0xa4 => 0xa7, 0xa5 => 0x2022,
|
||||
0xa6 => 0xb6, 0xa7 => 0x0406, 0xa8 => 0xae, 0xaa => 0x2122, 0xab => 0x0402,
|
||||
0xac => 0x0452, 0xad => 0x2260, 0xae => 0x0403, 0xaf => 0x0453,
|
||||
0xb0 => 0x221e, 0xb2 => 0x2264, 0xb3 => 0x2265, 0xb4 => 0x0456,
|
||||
0xb6 => 0x0491, 0xb7 => 0x0408, 0xb8 => 0x0404, 0xb9 => 0x0454,
|
||||
0xba => 0x0407, 0xbb => 0x0457, 0xbc => 0x0409, 0xbd => 0x0459,
|
||||
0xbe => 0x040a, 0xbf => 0x045a, 0xc0 => 0x0458, 0xc1 => 0x0405, 0xc2 => 0xac,
|
||||
0xc3 => 0x221a, 0xc4 => 0x0192, 0xc5 => 0x2248, 0xc6 => 0x2206, 0xc7 => 0xab,
|
||||
0xc8 => 0xbb, 0xc9 => 0x2026, 0xca => 0xa0, 0xcb => 0x040b, 0xcc => 0x045b,
|
||||
0xcd => 0x040c, 0xce => 0x045c, 0xcf => 0x0455, 0xd0 => 0x2013,
|
||||
0xd1 => 0x2014, 0xd2 => 0x201c, 0xd3 => 0x201d, 0xd4 => 0x2018,
|
||||
0xd5 => 0x2019, 0xd6 => 0xf7, 0xd7 => 0x201e, 0xd8 => 0x040e, 0xd9 => 0x045e,
|
||||
0xda => 0x040f, 0xdb => 0x045f, 0xdc => 0x2116, 0xdd => 0x0401,
|
||||
0xde => 0x0451, 0xdf => 0x044f, 0xe0 => 0x0430, 0xe1 => 0x0431,
|
||||
0xe2 => 0x0432, 0xe3 => 0x0433, 0xe4 => 0x0434, 0xe5 => 0x0435,
|
||||
0xe6 => 0x0436, 0xe7 => 0x0437, 0xe8 => 0x0438, 0xe9 => 0x0439,
|
||||
0xea => 0x043a, 0xeb => 0x043b, 0xec => 0x043c, 0xed => 0x043d,
|
||||
0xee => 0x043e, 0xef => 0x043f, 0xf0 => 0x0440, 0xf1 => 0x0441,
|
||||
0xf2 => 0x0442, 0xf3 => 0x0443, 0xf4 => 0x0444, 0xf5 => 0x0445,
|
||||
0xf6 => 0x0446, 0xf7 => 0x0447, 0xf8 => 0x0448, 0xf9 => 0x0449,
|
||||
0xfa => 0x044a, 0xfb => 0x044b, 0xfc => 0x044c, 0xfd => 0x044d,
|
||||
0xfe => 0x044e, 0xff => 0x20ac,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,45 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacGreek.pm
|
||||
#
|
||||
# Description: Mac Greek to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/GREEK.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacGreek = (
|
||||
0x80 => 0xc4, 0x81 => 0xb9, 0x82 => 0xb2, 0x83 => 0xc9, 0x84 => 0xb3,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0x0385, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0x0384, 0x8c => 0xa8, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xa3, 0x93 => 0x2122,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0x2022, 0x97 => 0xbd, 0x98 => 0x2030,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xa6, 0x9c => 0x20ac, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x2020, 0xa1 => 0x0393, 0xa2 => 0x0394,
|
||||
0xa3 => 0x0398, 0xa4 => 0x039b, 0xa5 => 0x039e, 0xa6 => 0x03a0, 0xa7 => 0xdf,
|
||||
0xa8 => 0xae, 0xaa => 0x03a3, 0xab => 0x03aa, 0xac => 0xa7, 0xad => 0x2260,
|
||||
0xae => 0xb0, 0xaf => 0xb7, 0xb0 => 0x0391, 0xb2 => 0x2264, 0xb3 => 0x2265,
|
||||
0xb4 => 0xa5, 0xb5 => 0x0392, 0xb6 => 0x0395, 0xb7 => 0x0396, 0xb8 => 0x0397,
|
||||
0xb9 => 0x0399, 0xba => 0x039a, 0xbb => 0x039c, 0xbc => 0x03a6,
|
||||
0xbd => 0x03ab, 0xbe => 0x03a8, 0xbf => 0x03a9, 0xc0 => 0x03ac,
|
||||
0xc1 => 0x039d, 0xc2 => 0xac, 0xc3 => 0x039f, 0xc4 => 0x03a1, 0xc5 => 0x2248,
|
||||
0xc6 => 0x03a4, 0xc7 => 0xab, 0xc8 => 0xbb, 0xc9 => 0x2026, 0xca => 0xa0,
|
||||
0xcb => 0x03a5, 0xcc => 0x03a7, 0xcd => 0x0386, 0xce => 0x0388,
|
||||
0xcf => 0x0153, 0xd0 => 0x2013, 0xd1 => 0x2015, 0xd2 => 0x201c,
|
||||
0xd3 => 0x201d, 0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7, 0xd7 => 0x0389,
|
||||
0xd8 => 0x038a, 0xd9 => 0x038c, 0xda => 0x038e, 0xdb => 0x03ad,
|
||||
0xdc => 0x03ae, 0xdd => 0x03af, 0xde => 0x03cc, 0xdf => 0x038f,
|
||||
0xe0 => 0x03cd, 0xe1 => 0x03b1, 0xe2 => 0x03b2, 0xe3 => 0x03c8,
|
||||
0xe4 => 0x03b4, 0xe5 => 0x03b5, 0xe6 => 0x03c6, 0xe7 => 0x03b3,
|
||||
0xe8 => 0x03b7, 0xe9 => 0x03b9, 0xea => 0x03be, 0xeb => 0x03ba,
|
||||
0xec => 0x03bb, 0xed => 0x03bc, 0xee => 0x03bd, 0xef => 0x03bf,
|
||||
0xf0 => 0x03c0, 0xf1 => 0x03ce, 0xf2 => 0x03c1, 0xf3 => 0x03c3,
|
||||
0xf4 => 0x03c4, 0xf5 => 0x03b8, 0xf6 => 0x03c9, 0xf7 => 0x03c2,
|
||||
0xf8 => 0x03c7, 0xf9 => 0x03c5, 0xfa => 0x03b6, 0xfb => 0x03ca,
|
||||
0xfc => 0x03cb, 0xfd => 0x0390, 0xfe => 0x03b0, 0xff => 0xad,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,47 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacHebrew.pm
|
||||
#
|
||||
# Description: Mac Hebrew to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/HEBREW.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
# and directional characters are ignored
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacHebrew = (
|
||||
0x80 => 0xc4, 0x81 => [0x05f2,0x05b7], 0x82 => 0xc7, 0x83 => 0xc9,
|
||||
0x84 => 0xd1, 0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0,
|
||||
0x89 => 0xe2, 0x8a => 0xe4, 0x8b => 0xe3, 0x8c => 0xe5, 0x8d => 0xe7,
|
||||
0x8e => 0xe9, 0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed,
|
||||
0x93 => 0xec, 0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3,
|
||||
0x98 => 0xf2, 0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa,
|
||||
0x9d => 0xf9, 0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x20, 0xa1 => 0x21,
|
||||
0xa2 => 0x22, 0xa3 => 0x23, 0xa4 => 0x24, 0xa5 => 0x25, 0xa6 => 0x20aa,
|
||||
0xa7 => 0x27, 0xa8 => 0x29, 0xa9 => 0x28, 0xaa => 0x2a, 0xab => 0x2b,
|
||||
0xac => 0x2c, 0xad => 0x2d, 0xae => 0x2e, 0xaf => 0x2f, 0xb0 => 0x30,
|
||||
0xb1 => 0x31, 0xb2 => 0x32, 0xb3 => 0x33, 0xb4 => 0x34, 0xb5 => 0x35,
|
||||
0xb6 => 0x36, 0xb7 => 0x37, 0xb8 => 0x38, 0xb9 => 0x39, 0xba => 0x3a,
|
||||
0xbb => 0x3b, 0xbc => 0x3c, 0xbd => 0x3d, 0xbe => 0x3e, 0xbf => 0x3f,
|
||||
0xc0 => [0xf86a,0x05dc,0x05b9], 0xc1 => 0x201e, 0xc2 => 0xf89b,
|
||||
0xc3 => 0xf89c, 0xc4 => 0xf89d, 0xc5 => 0xf89e, 0xc6 => 0x05bc,
|
||||
0xc7 => 0xfb4b, 0xc8 => 0xfb35, 0xc9 => 0x2026, 0xca => 0xa0, 0xcb => 0x05b8,
|
||||
0xcc => 0x05b7, 0xcd => 0x05b5, 0xce => 0x05b6, 0xcf => 0x05b4,
|
||||
0xd0 => 0x2013, 0xd1 => 0x2014, 0xd2 => 0x201c, 0xd3 => 0x201d,
|
||||
0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xfb2a, 0xd7 => 0xfb2b,
|
||||
0xd8 => 0x05bf, 0xd9 => 0x05b0, 0xda => 0x05b2, 0xdb => 0x05b1,
|
||||
0xdc => 0x05bb, 0xdd => 0x05b9, 0xde => [0x05b8,0xf87f], 0xdf => 0x05b3,
|
||||
0xe0 => 0x05d0, 0xe1 => 0x05d1, 0xe2 => 0x05d2, 0xe3 => 0x05d3,
|
||||
0xe4 => 0x05d4, 0xe5 => 0x05d5, 0xe6 => 0x05d6, 0xe7 => 0x05d7,
|
||||
0xe8 => 0x05d8, 0xe9 => 0x05d9, 0xea => 0x05da, 0xeb => 0x05db,
|
||||
0xec => 0x05dc, 0xed => 0x05dd, 0xee => 0x05de, 0xef => 0x05df,
|
||||
0xf0 => 0x05e0, 0xf1 => 0x05e1, 0xf2 => 0x05e2, 0xf3 => 0x05e3,
|
||||
0xf4 => 0x05e4, 0xf5 => 0x05e5, 0xf6 => 0x05e6, 0xf7 => 0x05e7,
|
||||
0xf8 => 0x05e8, 0xf9 => 0x05e9, 0xfa => 0x05ea, 0xfb => 0x7d, 0xfc => 0x5d,
|
||||
0xfd => 0x7b, 0xfe => 0x5b, 0xff => 0x7c,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,42 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacIceland.pm
|
||||
#
|
||||
# Description: Mac Icelandic to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ICELAND.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacIceland = (
|
||||
0x80 => 0xc4, 0x81 => 0xc5, 0x82 => 0xc7, 0x83 => 0xc9, 0x84 => 0xd1,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0xe3, 0x8c => 0xe5, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed, 0x93 => 0xec,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3, 0x98 => 0xf2,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0xdd, 0xa1 => 0xb0, 0xa4 => 0xa7,
|
||||
0xa5 => 0x2022, 0xa6 => 0xb6, 0xa7 => 0xdf, 0xa8 => 0xae, 0xaa => 0x2122,
|
||||
0xab => 0xb4, 0xac => 0xa8, 0xad => 0x2260, 0xae => 0xc6, 0xaf => 0xd8,
|
||||
0xb0 => 0x221e, 0xb2 => 0x2264, 0xb3 => 0x2265, 0xb4 => 0xa5, 0xb6 => 0x2202,
|
||||
0xb7 => 0x2211, 0xb8 => 0x220f, 0xb9 => 0x03c0, 0xba => 0x222b, 0xbb => 0xaa,
|
||||
0xbc => 0xba, 0xbd => 0x03a9, 0xbe => 0xe6, 0xbf => 0xf8, 0xc0 => 0xbf,
|
||||
0xc1 => 0xa1, 0xc2 => 0xac, 0xc3 => 0x221a, 0xc4 => 0x0192, 0xc5 => 0x2248,
|
||||
0xc6 => 0x2206, 0xc7 => 0xab, 0xc8 => 0xbb, 0xc9 => 0x2026, 0xca => 0xa0,
|
||||
0xcb => 0xc0, 0xcc => 0xc3, 0xcd => 0xd5, 0xce => 0x0152, 0xcf => 0x0153,
|
||||
0xd0 => 0x2013, 0xd1 => 0x2014, 0xd2 => 0x201c, 0xd3 => 0x201d,
|
||||
0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7, 0xd7 => 0x25ca, 0xd8 => 0xff,
|
||||
0xd9 => 0x0178, 0xda => 0x2044, 0xdb => 0x20ac, 0xdc => 0xd0, 0xdd => 0xf0,
|
||||
0xdf => 0xfe, 0xe0 => 0xfd, 0xe1 => 0xb7, 0xe2 => 0x201a, 0xe3 => 0x201e,
|
||||
0xe4 => 0x2030, 0xe5 => 0xc2, 0xe6 => 0xca, 0xe7 => 0xc1, 0xe8 => 0xcb,
|
||||
0xe9 => 0xc8, 0xea => 0xcd, 0xeb => 0xce, 0xec => 0xcf, 0xed => 0xcc,
|
||||
0xee => 0xd3, 0xef => 0xd4, 0xf0 => 0xf8ff, 0xf1 => 0xd2, 0xf2 => 0xda,
|
||||
0xf3 => 0xdb, 0xf4 => 0xd9, 0xf5 => 0x0131, 0xf6 => 0x02c6, 0xf7 => 0x02dc,
|
||||
0xf8 => 0xaf, 0xf9 => 0x02d8, 0xfa => 0x02d9, 0xfb => 0x02da, 0xfc => 0xb8,
|
||||
0xfd => 0x02dd, 0xfe => 0x02db, 0xff => 0x02c7,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,44 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacLatin2.pm
|
||||
#
|
||||
# Description: Mac Central European to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/CENTEURO.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacLatin2 = (
|
||||
0x80 => 0xc4, 0x81 => 0x0100, 0x82 => 0x0101, 0x83 => 0xc9, 0x84 => 0x0104,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0x0105, 0x89 => 0x010c,
|
||||
0x8a => 0xe4, 0x8b => 0x010d, 0x8c => 0x0106, 0x8d => 0x0107, 0x8e => 0xe9,
|
||||
0x8f => 0x0179, 0x90 => 0x017a, 0x91 => 0x010e, 0x92 => 0xed, 0x93 => 0x010f,
|
||||
0x94 => 0x0112, 0x95 => 0x0113, 0x96 => 0x0116, 0x97 => 0xf3, 0x98 => 0x0117,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa, 0x9d => 0x011a,
|
||||
0x9e => 0x011b, 0x9f => 0xfc, 0xa0 => 0x2020, 0xa1 => 0xb0, 0xa2 => 0x0118,
|
||||
0xa4 => 0xa7, 0xa5 => 0x2022, 0xa6 => 0xb6, 0xa7 => 0xdf, 0xa8 => 0xae,
|
||||
0xaa => 0x2122, 0xab => 0x0119, 0xac => 0xa8, 0xad => 0x2260, 0xae => 0x0123,
|
||||
0xaf => 0x012e, 0xb0 => 0x012f, 0xb1 => 0x012a, 0xb2 => 0x2264,
|
||||
0xb3 => 0x2265, 0xb4 => 0x012b, 0xb5 => 0x0136, 0xb6 => 0x2202,
|
||||
0xb7 => 0x2211, 0xb8 => 0x0142, 0xb9 => 0x013b, 0xba => 0x013c,
|
||||
0xbb => 0x013d, 0xbc => 0x013e, 0xbd => 0x0139, 0xbe => 0x013a,
|
||||
0xbf => 0x0145, 0xc0 => 0x0146, 0xc1 => 0x0143, 0xc2 => 0xac, 0xc3 => 0x221a,
|
||||
0xc4 => 0x0144, 0xc5 => 0x0147, 0xc6 => 0x2206, 0xc7 => 0xab, 0xc8 => 0xbb,
|
||||
0xc9 => 0x2026, 0xca => 0xa0, 0xcb => 0x0148, 0xcc => 0x0150, 0xcd => 0xd5,
|
||||
0xce => 0x0151, 0xcf => 0x014c, 0xd0 => 0x2013, 0xd1 => 0x2014,
|
||||
0xd2 => 0x201c, 0xd3 => 0x201d, 0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7,
|
||||
0xd7 => 0x25ca, 0xd8 => 0x014d, 0xd9 => 0x0154, 0xda => 0x0155,
|
||||
0xdb => 0x0158, 0xdc => 0x2039, 0xdd => 0x203a, 0xde => 0x0159,
|
||||
0xdf => 0x0156, 0xe0 => 0x0157, 0xe1 => 0x0160, 0xe2 => 0x201a,
|
||||
0xe3 => 0x201e, 0xe4 => 0x0161, 0xe5 => 0x015a, 0xe6 => 0x015b, 0xe7 => 0xc1,
|
||||
0xe8 => 0x0164, 0xe9 => 0x0165, 0xea => 0xcd, 0xeb => 0x017d, 0xec => 0x017e,
|
||||
0xed => 0x016a, 0xee => 0xd3, 0xef => 0xd4, 0xf0 => 0x016b, 0xf1 => 0x016e,
|
||||
0xf2 => 0xda, 0xf3 => 0x016f, 0xf4 => 0x0170, 0xf5 => 0x0171, 0xf6 => 0x0172,
|
||||
0xf7 => 0x0173, 0xf8 => 0xdd, 0xf9 => 0xfd, 0xfa => 0x0137, 0xfb => 0x017b,
|
||||
0xfc => 0x0141, 0xfd => 0x017c, 0xfe => 0x0122, 0xff => 0x02c7,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,42 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacRoman.pm
|
||||
#
|
||||
# Description: Mac Roman to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacRoman = (
|
||||
0x80 => 0xc4, 0x81 => 0xc5, 0x82 => 0xc7, 0x83 => 0xc9, 0x84 => 0xd1,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0xe3, 0x8c => 0xe5, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed, 0x93 => 0xec,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3, 0x98 => 0xf2,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x2020, 0xa1 => 0xb0, 0xa4 => 0xa7,
|
||||
0xa5 => 0x2022, 0xa6 => 0xb6, 0xa7 => 0xdf, 0xa8 => 0xae, 0xaa => 0x2122,
|
||||
0xab => 0xb4, 0xac => 0xa8, 0xad => 0x2260, 0xae => 0xc6, 0xaf => 0xd8,
|
||||
0xb0 => 0x221e, 0xb2 => 0x2264, 0xb3 => 0x2265, 0xb4 => 0xa5, 0xb6 => 0x2202,
|
||||
0xb7 => 0x2211, 0xb8 => 0x220f, 0xb9 => 0x03c0, 0xba => 0x222b, 0xbb => 0xaa,
|
||||
0xbc => 0xba, 0xbd => 0x03a9, 0xbe => 0xe6, 0xbf => 0xf8, 0xc0 => 0xbf,
|
||||
0xc1 => 0xa1, 0xc2 => 0xac, 0xc3 => 0x221a, 0xc4 => 0x0192, 0xc5 => 0x2248,
|
||||
0xc6 => 0x2206, 0xc7 => 0xab, 0xc8 => 0xbb, 0xc9 => 0x2026, 0xca => 0xa0,
|
||||
0xcb => 0xc0, 0xcc => 0xc3, 0xcd => 0xd5, 0xce => 0x0152, 0xcf => 0x0153,
|
||||
0xd0 => 0x2013, 0xd1 => 0x2014, 0xd2 => 0x201c, 0xd3 => 0x201d,
|
||||
0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7, 0xd7 => 0x25ca, 0xd8 => 0xff,
|
||||
0xd9 => 0x0178, 0xda => 0x2044, 0xdb => 0x20ac, 0xdc => 0x2039,
|
||||
0xdd => 0x203a, 0xde => 0xfb01, 0xdf => 0xfb02, 0xe0 => 0x2021, 0xe1 => 0xb7,
|
||||
0xe2 => 0x201a, 0xe3 => 0x201e, 0xe4 => 0x2030, 0xe5 => 0xc2, 0xe6 => 0xca,
|
||||
0xe7 => 0xc1, 0xe8 => 0xcb, 0xe9 => 0xc8, 0xea => 0xcd, 0xeb => 0xce,
|
||||
0xec => 0xcf, 0xed => 0xcc, 0xee => 0xd3, 0xef => 0xd4, 0xf0 => 0xf8ff,
|
||||
0xf1 => 0xd2, 0xf2 => 0xda, 0xf3 => 0xdb, 0xf4 => 0xd9, 0xf5 => 0x0131,
|
||||
0xf6 => 0x02c6, 0xf7 => 0x02dc, 0xf8 => 0xaf, 0xf9 => 0x02d8, 0xfa => 0x02d9,
|
||||
0xfb => 0x02da, 0xfc => 0xb8, 0xfd => 0x02dd, 0xfe => 0x02db, 0xff => 0x02c7,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,42 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacRomanian.pm
|
||||
#
|
||||
# Description: Mac Romanian to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMANIAN.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacRomanian = (
|
||||
0x80 => 0xc4, 0x81 => 0xc5, 0x82 => 0xc7, 0x83 => 0xc9, 0x84 => 0xd1,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0xe3, 0x8c => 0xe5, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed, 0x93 => 0xec,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3, 0x98 => 0xf2,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x2020, 0xa1 => 0xb0, 0xa4 => 0xa7,
|
||||
0xa5 => 0x2022, 0xa6 => 0xb6, 0xa7 => 0xdf, 0xa8 => 0xae, 0xaa => 0x2122,
|
||||
0xab => 0xb4, 0xac => 0xa8, 0xad => 0x2260, 0xae => 0x0102, 0xaf => 0x0218,
|
||||
0xb0 => 0x221e, 0xb2 => 0x2264, 0xb3 => 0x2265, 0xb4 => 0xa5, 0xb6 => 0x2202,
|
||||
0xb7 => 0x2211, 0xb8 => 0x220f, 0xb9 => 0x03c0, 0xba => 0x222b, 0xbb => 0xaa,
|
||||
0xbc => 0xba, 0xbd => 0x03a9, 0xbe => 0x0103, 0xbf => 0x0219, 0xc0 => 0xbf,
|
||||
0xc1 => 0xa1, 0xc2 => 0xac, 0xc3 => 0x221a, 0xc4 => 0x0192, 0xc5 => 0x2248,
|
||||
0xc6 => 0x2206, 0xc7 => 0xab, 0xc8 => 0xbb, 0xc9 => 0x2026, 0xca => 0xa0,
|
||||
0xcb => 0xc0, 0xcc => 0xc3, 0xcd => 0xd5, 0xce => 0x0152, 0xcf => 0x0153,
|
||||
0xd0 => 0x2013, 0xd1 => 0x2014, 0xd2 => 0x201c, 0xd3 => 0x201d,
|
||||
0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7, 0xd7 => 0x25ca, 0xd8 => 0xff,
|
||||
0xd9 => 0x0178, 0xda => 0x2044, 0xdb => 0x20ac, 0xdc => 0x2039,
|
||||
0xdd => 0x203a, 0xde => 0x021a, 0xdf => 0x021b, 0xe0 => 0x2021, 0xe1 => 0xb7,
|
||||
0xe2 => 0x201a, 0xe3 => 0x201e, 0xe4 => 0x2030, 0xe5 => 0xc2, 0xe6 => 0xca,
|
||||
0xe7 => 0xc1, 0xe8 => 0xcb, 0xe9 => 0xc8, 0xea => 0xcd, 0xeb => 0xce,
|
||||
0xec => 0xcf, 0xed => 0xcc, 0xee => 0xd3, 0xef => 0xd4, 0xf0 => 0xf8ff,
|
||||
0xf1 => 0xd2, 0xf2 => 0xda, 0xf3 => 0xdb, 0xf4 => 0xd9, 0xf5 => 0x0131,
|
||||
0xf6 => 0x02c6, 0xf7 => 0x02dc, 0xf8 => 0xaf, 0xf9 => 0x02d8, 0xfa => 0x02d9,
|
||||
0xfb => 0x02da, 0xfc => 0xb8, 0xfd => 0x02dd, 0xfe => 0x02db, 0xff => 0x02c7,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,49 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacThai.pm
|
||||
#
|
||||
# Description: Mac Thai to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/THAI.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacThai = (
|
||||
0x80 => 0xab, 0x81 => 0xbb, 0x82 => 0x2026, 0x83 => [0x0e48,0xf875],
|
||||
0x84 => [0x0e49,0xf875], 0x85 => [0x0e4a,0xf875], 0x86 => [0x0e4b,0xf875],
|
||||
0x87 => [0x0e4c,0xf875], 0x88 => [0x0e48,0xf873], 0x89 => [0x0e49,0xf873],
|
||||
0x8a => [0x0e4a,0xf873], 0x8b => [0x0e4b,0xf873], 0x8c => [0x0e4c,0xf873],
|
||||
0x8d => 0x201c, 0x8e => 0x201d, 0x8f => [0x0e4d,0xf874], 0x91 => 0x2022,
|
||||
0x92 => [0x0e31,0xf874], 0x93 => [0x0e47,0xf874], 0x94 => [0x0e34,0xf874],
|
||||
0x95 => [0x0e35,0xf874], 0x96 => [0x0e36,0xf874], 0x97 => [0x0e37,0xf874],
|
||||
0x98 => [0x0e48,0xf874], 0x99 => [0x0e49,0xf874], 0x9a => [0x0e4a,0xf874],
|
||||
0x9b => [0x0e4b,0xf874], 0x9c => [0x0e4c,0xf874], 0x9d => 0x2018,
|
||||
0x9e => 0x2019, 0xa1 => 0x0e01, 0xa2 => 0x0e02, 0xa3 => 0x0e03,
|
||||
0xa4 => 0x0e04, 0xa5 => 0x0e05, 0xa6 => 0x0e06, 0xa7 => 0x0e07,
|
||||
0xa8 => 0x0e08, 0xa9 => 0x0e09, 0xaa => 0x0e0a, 0xab => 0x0e0b,
|
||||
0xac => 0x0e0c, 0xad => 0x0e0d, 0xae => 0x0e0e, 0xaf => 0x0e0f,
|
||||
0xb0 => 0x0e10, 0xb1 => 0x0e11, 0xb2 => 0x0e12, 0xb3 => 0x0e13,
|
||||
0xb4 => 0x0e14, 0xb5 => 0x0e15, 0xb6 => 0x0e16, 0xb7 => 0x0e17,
|
||||
0xb8 => 0x0e18, 0xb9 => 0x0e19, 0xba => 0x0e1a, 0xbb => 0x0e1b,
|
||||
0xbc => 0x0e1c, 0xbd => 0x0e1d, 0xbe => 0x0e1e, 0xbf => 0x0e1f,
|
||||
0xc0 => 0x0e20, 0xc1 => 0x0e21, 0xc2 => 0x0e22, 0xc3 => 0x0e23,
|
||||
0xc4 => 0x0e24, 0xc5 => 0x0e25, 0xc6 => 0x0e26, 0xc7 => 0x0e27,
|
||||
0xc8 => 0x0e28, 0xc9 => 0x0e29, 0xca => 0x0e2a, 0xcb => 0x0e2b,
|
||||
0xcc => 0x0e2c, 0xcd => 0x0e2d, 0xce => 0x0e2e, 0xcf => 0x0e2f,
|
||||
0xd0 => 0x0e30, 0xd1 => 0x0e31, 0xd2 => 0x0e32, 0xd3 => 0x0e33,
|
||||
0xd4 => 0x0e34, 0xd5 => 0x0e35, 0xd6 => 0x0e36, 0xd7 => 0x0e37,
|
||||
0xd8 => 0x0e38, 0xd9 => 0x0e39, 0xda => 0x0e3a, 0xdb => 0x2060,
|
||||
0xdc => 0x200b, 0xdd => 0x2013, 0xde => 0x2014, 0xdf => 0x0e3f,
|
||||
0xe0 => 0x0e40, 0xe1 => 0x0e41, 0xe2 => 0x0e42, 0xe3 => 0x0e43,
|
||||
0xe4 => 0x0e44, 0xe5 => 0x0e45, 0xe6 => 0x0e46, 0xe7 => 0x0e47,
|
||||
0xe8 => 0x0e48, 0xe9 => 0x0e49, 0xea => 0x0e4a, 0xeb => 0x0e4b,
|
||||
0xec => 0x0e4c, 0xed => 0x0e4d, 0xee => 0x2122, 0xef => 0x0e4f,
|
||||
0xf0 => 0x0e50, 0xf1 => 0x0e51, 0xf2 => 0x0e52, 0xf3 => 0x0e53,
|
||||
0xf4 => 0x0e54, 0xf5 => 0x0e55, 0xf6 => 0x0e56, 0xf7 => 0x0e57,
|
||||
0xf8 => 0x0e58, 0xf9 => 0x0e59, 0xfa => 0xae, 0xfb => 0xa9,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,42 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: MacTurkish.pm
|
||||
#
|
||||
# Description: Mac Turkish to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/TURKISH.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::MacTurkish = (
|
||||
0x80 => 0xc4, 0x81 => 0xc5, 0x82 => 0xc7, 0x83 => 0xc9, 0x84 => 0xd1,
|
||||
0x85 => 0xd6, 0x86 => 0xdc, 0x87 => 0xe1, 0x88 => 0xe0, 0x89 => 0xe2,
|
||||
0x8a => 0xe4, 0x8b => 0xe3, 0x8c => 0xe5, 0x8d => 0xe7, 0x8e => 0xe9,
|
||||
0x8f => 0xe8, 0x90 => 0xea, 0x91 => 0xeb, 0x92 => 0xed, 0x93 => 0xec,
|
||||
0x94 => 0xee, 0x95 => 0xef, 0x96 => 0xf1, 0x97 => 0xf3, 0x98 => 0xf2,
|
||||
0x99 => 0xf4, 0x9a => 0xf6, 0x9b => 0xf5, 0x9c => 0xfa, 0x9d => 0xf9,
|
||||
0x9e => 0xfb, 0x9f => 0xfc, 0xa0 => 0x2020, 0xa1 => 0xb0, 0xa4 => 0xa7,
|
||||
0xa5 => 0x2022, 0xa6 => 0xb6, 0xa7 => 0xdf, 0xa8 => 0xae, 0xaa => 0x2122,
|
||||
0xab => 0xb4, 0xac => 0xa8, 0xad => 0x2260, 0xae => 0xc6, 0xaf => 0xd8,
|
||||
0xb0 => 0x221e, 0xb2 => 0x2264, 0xb3 => 0x2265, 0xb4 => 0xa5, 0xb6 => 0x2202,
|
||||
0xb7 => 0x2211, 0xb8 => 0x220f, 0xb9 => 0x03c0, 0xba => 0x222b, 0xbb => 0xaa,
|
||||
0xbc => 0xba, 0xbd => 0x03a9, 0xbe => 0xe6, 0xbf => 0xf8, 0xc0 => 0xbf,
|
||||
0xc1 => 0xa1, 0xc2 => 0xac, 0xc3 => 0x221a, 0xc4 => 0x0192, 0xc5 => 0x2248,
|
||||
0xc6 => 0x2206, 0xc7 => 0xab, 0xc8 => 0xbb, 0xc9 => 0x2026, 0xca => 0xa0,
|
||||
0xcb => 0xc0, 0xcc => 0xc3, 0xcd => 0xd5, 0xce => 0x0152, 0xcf => 0x0153,
|
||||
0xd0 => 0x2013, 0xd1 => 0x2014, 0xd2 => 0x201c, 0xd3 => 0x201d,
|
||||
0xd4 => 0x2018, 0xd5 => 0x2019, 0xd6 => 0xf7, 0xd7 => 0x25ca, 0xd8 => 0xff,
|
||||
0xd9 => 0x0178, 0xda => 0x011e, 0xdb => 0x011f, 0xdc => 0x0130,
|
||||
0xdd => 0x0131, 0xde => 0x015e, 0xdf => 0x015f, 0xe0 => 0x2021, 0xe1 => 0xb7,
|
||||
0xe2 => 0x201a, 0xe3 => 0x201e, 0xe4 => 0x2030, 0xe5 => 0xc2, 0xe6 => 0xca,
|
||||
0xe7 => 0xc1, 0xe8 => 0xcb, 0xe9 => 0xc8, 0xea => 0xcd, 0xeb => 0xce,
|
||||
0xec => 0xcf, 0xed => 0xcc, 0xee => 0xd3, 0xef => 0xd4, 0xf0 => 0xf8ff,
|
||||
0xf1 => 0xd2, 0xf2 => 0xda, 0xf3 => 0xdb, 0xf4 => 0xd9, 0xf5 => 0xf8a0,
|
||||
0xf6 => 0x02c6, 0xf7 => 0x02dc, 0xf8 => 0xaf, 0xf9 => 0x02d8, 0xfa => 0x02d9,
|
||||
0xfb => 0x02da, 0xfc => 0xb8, 0xfd => 0x02dd, 0xfe => 0x02db, 0xff => 0x02c7,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,28 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: PDFDoc.pm
|
||||
#
|
||||
# Description: PDFDocEncoding to Unicode
|
||||
#
|
||||
# Revisions: 2010/10/16 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://www.adobe.com/devnet/pdf/pdf_reference.html
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
# This set re-maps characters with codepoints less than 0x80
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::PDFDoc = (
|
||||
0x18 => 0x02d8, 0x82 => 0x2021, 0x8c => 0x201e, 0x96 => 0x0152,
|
||||
0x19 => 0x02c7, 0x83 => 0x2026, 0x8d => 0x201c, 0x97 => 0x0160,
|
||||
0x1a => 0x02c6, 0x84 => 0x2014, 0x8e => 0x201d, 0x98 => 0x0178,
|
||||
0x1b => 0x02d9, 0x85 => 0x2013, 0x8f => 0x2018, 0x99 => 0x017d,
|
||||
0x1c => 0x02dd, 0x86 => 0x0192, 0x90 => 0x2019, 0x9a => 0x0131,
|
||||
0x1d => 0x02db, 0x87 => 0x2044, 0x91 => 0x201a, 0x9b => 0x0142,
|
||||
0x1e => 0x02da, 0x88 => 0x2039, 0x92 => 0x2122, 0x9c => 0x0153,
|
||||
0x1f => 0x02dc, 0x89 => 0x203a, 0x93 => 0xfb01, 0x9d => 0x0161,
|
||||
0x80 => 0x2022, 0x8a => 0x2212, 0x94 => 0xfb02, 0x9e => 0x017e,
|
||||
0x81 => 0x2020, 0x8b => 0x2030, 0x95 => 0x0141, 0xa0 => 0x20ac,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,54 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Symbol.pm
|
||||
#
|
||||
# Description: Symbol to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://blogs.msdn.com/michkap/archive/2005/11/08/490495.aspx
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode.
|
||||
# This set re-maps characters with codepoints less than 0x80
|
||||
# (Although all bytes >= 0x20 should be mapped according to the
|
||||
# reference, I didn't map chars below 0x80 because I have some
|
||||
# samples where these are regular ASCII characters, even though
|
||||
# I think the encoding is probably incorrect for these samples)
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Symbol = (
|
||||
0x80 => 0xf080, 0x81 => 0xf081, 0x82 => 0xf082, 0x83 => 0xf083,
|
||||
0x84 => 0xf084, 0x85 => 0xf085, 0x86 => 0xf086, 0x87 => 0xf087,
|
||||
0x88 => 0xf088, 0x89 => 0xf089, 0x8a => 0xf08a, 0x8b => 0xf08b,
|
||||
0x8c => 0xf08c, 0x8d => 0xf08d, 0x8e => 0xf08e, 0x8f => 0xf08f,
|
||||
0x90 => 0xf090, 0x91 => 0xf091, 0x92 => 0xf092, 0x93 => 0xf093,
|
||||
0x94 => 0xf094, 0x95 => 0xf095, 0x96 => 0xf096, 0x97 => 0xf097,
|
||||
0x98 => 0xf098, 0x99 => 0xf099, 0x9a => 0xf09a, 0x9b => 0xf09b,
|
||||
0x9c => 0xf09c, 0x9d => 0xf09d, 0x9e => 0xf09e, 0x9f => 0xf09f,
|
||||
0xa0 => 0xf0a0, 0xa1 => 0xf0a1, 0xa2 => 0xf0a2, 0xa3 => 0xf0a3,
|
||||
0xa4 => 0xf0a4, 0xa5 => 0xf0a5, 0xa6 => 0xf0a6, 0xa7 => 0xf0a7,
|
||||
0xa8 => 0xf0a8, 0xa9 => 0xf0a9, 0xaa => 0xf0aa, 0xab => 0xf0ab,
|
||||
0xac => 0xf0ac, 0xad => 0xf0ad, 0xae => 0xf0ae, 0xaf => 0xf0af,
|
||||
0xb0 => 0xf0b0, 0xb1 => 0xf0b1, 0xb2 => 0xf0b2, 0xb3 => 0xf0b3,
|
||||
0xb4 => 0xf0b4, 0xb5 => 0xf0b5, 0xb6 => 0xf0b6, 0xb7 => 0xf0b7,
|
||||
0xb8 => 0xf0b8, 0xb9 => 0xf0b9, 0xba => 0xf0ba, 0xbb => 0xf0bb,
|
||||
0xbc => 0xf0bc, 0xbd => 0xf0bd, 0xbe => 0xf0be, 0xbf => 0xf0bf,
|
||||
0xc0 => 0xf0c0, 0xc1 => 0xf0c1, 0xc2 => 0xf0c2, 0xc3 => 0xf0c3,
|
||||
0xc4 => 0xf0c4, 0xc5 => 0xf0c5, 0xc6 => 0xf0c6, 0xc7 => 0xf0c7,
|
||||
0xc8 => 0xf0c8, 0xc9 => 0xf0c9, 0xca => 0xf0ca, 0xcb => 0xf0cb,
|
||||
0xcc => 0xf0cc, 0xcd => 0xf0cd, 0xce => 0xf0ce, 0xcf => 0xf0cf,
|
||||
0xd0 => 0xf0d0, 0xd1 => 0xf0d1, 0xd2 => 0xf0d2, 0xd3 => 0xf0d3,
|
||||
0xd4 => 0xf0d4, 0xd5 => 0xf0d5, 0xd6 => 0xf0d6, 0xd7 => 0xf0d7,
|
||||
0xd8 => 0xf0d8, 0xd9 => 0xf0d9, 0xda => 0xf0da, 0xdb => 0xf0db,
|
||||
0xdc => 0xf0dc, 0xdd => 0xf0dd, 0xde => 0xf0de, 0xdf => 0xf0df,
|
||||
0xe0 => 0xf0e0, 0xe1 => 0xf0e1, 0xe2 => 0xf0e2, 0xe3 => 0xf0e3,
|
||||
0xe4 => 0xf0e4, 0xe5 => 0xf0e5, 0xe6 => 0xf0e6, 0xe7 => 0xf0e7,
|
||||
0xe8 => 0xf0e8, 0xe9 => 0xf0e9, 0xea => 0xf0ea, 0xeb => 0xf0eb,
|
||||
0xec => 0xf0ec, 0xed => 0xf0ed, 0xee => 0xf0ee, 0xef => 0xf0ef,
|
||||
0xf0 => 0xf0f0, 0xf1 => 0xf0f1, 0xf2 => 0xf0f2, 0xf3 => 0xf0f3,
|
||||
0xf4 => 0xf0f4, 0xf5 => 0xf0f5, 0xf6 => 0xf0f6, 0xf7 => 0xf0f7,
|
||||
0xf8 => 0xf0f8, 0xf9 => 0xf0f9, 0xfa => 0xf0fa, 0xfb => 0xf0fb,
|
||||
0xfc => 0xf0fc, 0xfd => 0xf0fd, 0xfe => 0xf0fe, 0xff => 0xf0ff,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,41 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Thai.pm
|
||||
#
|
||||
# Description: cp874 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP874.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Thai = (
|
||||
0x80 => 0x20ac, 0x85 => 0x2026, 0x91 => 0x2018, 0x92 => 0x2019,
|
||||
0x93 => 0x201c, 0x94 => 0x201d, 0x95 => 0x2022, 0x96 => 0x2013,
|
||||
0x97 => 0x2014, 0xa1 => 0x0e01, 0xa2 => 0x0e02, 0xa3 => 0x0e03,
|
||||
0xa4 => 0x0e04, 0xa5 => 0x0e05, 0xa6 => 0x0e06, 0xa7 => 0x0e07,
|
||||
0xa8 => 0x0e08, 0xa9 => 0x0e09, 0xaa => 0x0e0a, 0xab => 0x0e0b,
|
||||
0xac => 0x0e0c, 0xad => 0x0e0d, 0xae => 0x0e0e, 0xaf => 0x0e0f,
|
||||
0xb0 => 0x0e10, 0xb1 => 0x0e11, 0xb2 => 0x0e12, 0xb3 => 0x0e13,
|
||||
0xb4 => 0x0e14, 0xb5 => 0x0e15, 0xb6 => 0x0e16, 0xb7 => 0x0e17,
|
||||
0xb8 => 0x0e18, 0xb9 => 0x0e19, 0xba => 0x0e1a, 0xbb => 0x0e1b,
|
||||
0xbc => 0x0e1c, 0xbd => 0x0e1d, 0xbe => 0x0e1e, 0xbf => 0x0e1f,
|
||||
0xc0 => 0x0e20, 0xc1 => 0x0e21, 0xc2 => 0x0e22, 0xc3 => 0x0e23,
|
||||
0xc4 => 0x0e24, 0xc5 => 0x0e25, 0xc6 => 0x0e26, 0xc7 => 0x0e27,
|
||||
0xc8 => 0x0e28, 0xc9 => 0x0e29, 0xca => 0x0e2a, 0xcb => 0x0e2b,
|
||||
0xcc => 0x0e2c, 0xcd => 0x0e2d, 0xce => 0x0e2e, 0xcf => 0x0e2f,
|
||||
0xd0 => 0x0e30, 0xd1 => 0x0e31, 0xd2 => 0x0e32, 0xd3 => 0x0e33,
|
||||
0xd4 => 0x0e34, 0xd5 => 0x0e35, 0xd6 => 0x0e36, 0xd7 => 0x0e37,
|
||||
0xd8 => 0x0e38, 0xd9 => 0x0e39, 0xda => 0x0e3a, 0xdf => 0x0e3f,
|
||||
0xe0 => 0x0e40, 0xe1 => 0x0e41, 0xe2 => 0x0e42, 0xe3 => 0x0e43,
|
||||
0xe4 => 0x0e44, 0xe5 => 0x0e45, 0xe6 => 0x0e46, 0xe7 => 0x0e47,
|
||||
0xe8 => 0x0e48, 0xe9 => 0x0e49, 0xea => 0x0e4a, 0xeb => 0x0e4b,
|
||||
0xec => 0x0e4c, 0xed => 0x0e4d, 0xee => 0x0e4e, 0xef => 0x0e4f,
|
||||
0xf0 => 0x0e50, 0xf1 => 0x0e51, 0xf2 => 0x0e52, 0xf3 => 0x0e53,
|
||||
0xf4 => 0x0e54, 0xf5 => 0x0e55, 0xf6 => 0x0e56, 0xf7 => 0x0e57,
|
||||
0xf8 => 0x0e58, 0xf9 => 0x0e59, 0xfa => 0x0e5a, 0xfb => 0x0e5b,
|
||||
);
|
||||
|
||||
1; # end
|
||||
@@ -1,25 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# File: Turkish.pm
|
||||
#
|
||||
# Description: cp1254 to Unicode
|
||||
#
|
||||
# Revisions: 2010/01/20 - P. Harvey created
|
||||
#
|
||||
# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1254.TXT
|
||||
#
|
||||
# Notes: The table omits 1-byte characters with the same values as Unicode
|
||||
#------------------------------------------------------------------------------
|
||||
use strict;
|
||||
|
||||
%Image::ExifTool::Charset::Turkish = (
|
||||
0x80 => 0x20ac, 0x82 => 0x201a, 0x83 => 0x0192, 0x84 => 0x201e,
|
||||
0x85 => 0x2026, 0x86 => 0x2020, 0x87 => 0x2021, 0x88 => 0x02c6,
|
||||
0x89 => 0x2030, 0x8a => 0x0160, 0x8b => 0x2039, 0x8c => 0x0152,
|
||||
0x91 => 0x2018, 0x92 => 0x2019, 0x93 => 0x201c, 0x94 => 0x201d,
|
||||
0x95 => 0x2022, 0x96 => 0x2013, 0x97 => 0x2014, 0x98 => 0x02dc,
|
||||
0x99 => 0x2122, 0x9a => 0x0161, 0x9b => 0x203a, 0x9c => 0x0153,
|
||||
0x9f => 0x0178, 0xd0 => 0x011e, 0xdd => 0x0130, 0xde => 0x015e,
|
||||
0xf0 => 0x011f, 0xfd => 0x0131, 0xfe => 0x015f,
|
||||
);
|
||||
|
||||
1; # end
|
||||