#!/usr/bin/perl
# 
# partially used EXIF DATA READING soubroutine from EXIF Data Extractor Copyright (c) 2001-2004 by Andrew Gregory
###############################################################################


use locale;
use Time::Local;
$sourcePath = '.'; # value by default
$fileTypes = '(.jpg)';     # value by default
$version = "0.0.1";
$silent = 0;

sub DirLoop             # parametr $_[0] is DirName
{
  opendir (CURRENT_DIR, $_[0])  
    or die "Cant open $_[0]:  $!";
  print "Open dir $_[0] \n"  if($silent == 0);
  
  # directory loop
  foreach $File (readdir CURRENT_DIR)  
  {
#    print "$_[0]/$File\n";

    if (-f "$_[0]/$File" && $File=~m/$fileTypes/i)
    { # one of files
   print "  read $_[0]/$File \n"  if($silent == 0);
   %exif = &exif_get_data("$_[0]/$File");
#   print $exif{'DateTimeOriginal'};
   $date = $exif{'DateTimeOriginal'}; #2006:09:23 21:58:31
#   print $date;

# print "\n $YYYY $MM $mm $File $file_date";# \n$yyyy & $ss\n";

   &set_data if($date != 0);
   print "\n";

    }
    elsif (-d "$_[0]/$File" && $File=~m/\w+/ )
    { # subdirectory
      &DirLoop("$_[0]/$File");
    }
  }
  closedir(CURRENT_DIR);
}

sub set_data{

 ($YYYY, $MM, $DD, $hh, $mm, $ss) = ($date  =~ /(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)/); 
 $file_date1 = timelocal($ss, $mm, $hh, $DD, $MM-1, $YYYY-1900);
 utime($file_date1,$file_date1,"$_[0]/$File");

}


###################################################################################

sub exif_get_credits {
  "EXIF Data Extractor v1.5\n" .
  "Copyright (c) 2001-2004\n" .
  "by Andrew Gregory\n" .
  "http://www.scss.com.au/family/andrew/camera/exif/";
}

sub exif_get_data {
  local($filename) = @_;
  local(%exif); # Returned EXIF data
  local(@ifdq); # IFD queue (file offsets)
  local($buf);
  local($tag, $type, $len, $offset); # EXIF field data
  local($cnt, $num);
  local($base);
  local($flratio, $flmin); # focal length - ratio and minimum
  local($sizex, $sizey);
  local(*JPG);
  local($unpack_short, $unpack_long);
  
  $unpack_short = 'n';
  $unpack_long = 'N';

  open(JPG, $filename);
  read(JPG, $buf, 2);
  ($tag) = unpack('n1', $buf);
  if ($tag == 0xFFD8) {
    my ($blockid, $blocklen, $blockstart);
    do {
      # got start of image - read blocks
      read(JPG, $buf, 4);
      ($blockid, $blocklen) = unpack('n2', $buf);
      $blockid  = 0 unless ($blockid );
      $blocklen = 0 unless ($blocklen);
      if ($blockid > 0 && $blocklen > 0) {
        $blockstart = tell JPG;
        if ($blockid == 0xFFE0) {
          # APP0
        } elsif ($blockid == 0xFFE1) {
          # APP1
          read(JPG, $buf, 6);
          my ($exif, $pad) = unpack('a4n1', $buf);
          read(JPG, $buf, 2);
          my ($bo) = unpack('n1', $buf);
          if ($exif eq 'Exif') {
            if ($bo == 0x4949) {
              $unpack_short = 'v';
              $unpack_long = 'V';
            }
            read(JPG, $buf, 2);
            ($magic) = unpack(&exif_get_unpack_string('n1'), $buf);
            if ($magic == 0x002A) {
              $base = (tell JPG) - 4;
              read(JPG, $buf, 4);
              push @ifdq, unpack(&exif_get_unpack_string('N1'), $buf);
            }
          }
        } elsif ($blockid == 0xFFFE) {
          # COMMENT
          read(JPG, $buf, $blocklen - 2);
          $exif{'jpeg.Comment'} = $buf;
        }
        if ($blocklen >= 2) {
          seek(JPG, $blocklen - ((tell JPG) - $blockstart + 2), 1); # skip block
        }
      }
    } while ($blocklen >= 2);
  }

  while (@ifdq) {
    $offset = pop @ifdq;
    seek(JPG, $base + $offset, 0);
    read(JPG, $buf, 2);
    ($num) = unpack(&exif_get_unpack_string('n1'), $buf);
    for ($cnt = 0; $cnt < $num; $cnt++) {
      read(JPG, $buf, 12);
      ($tag, $type, $len, $offset) = unpack(&exif_get_unpack_string('n1n1N1N1'), $buf);
      push @ifdq, $offset if ($tag == 0x8769); # Exif IFD
      if ($exif{'Make'}) {
        if ($exif{'Make'} eq 'CASIO') {
          # currently, only Casio MakerNotes are understood
          push @ifdq, $offset if ($tag == 0x927C); # MakerNote IFD
        }
      }
      &exif_process_tag($tag, $type, $len, $offset);
    }
    read(JPG, $buf, 4);
    ($offset) = unpack(&exif_get_unpack_string('N1'), $buf);
    push @ifdq, $offset if ($offset != 0);
  }

  close JPG;
  %exif;
}

sub exif_process_tag {
  local($tag, $type, $len, $offset) = @_;
  local(%tmp, $v, $short, $handled);
  
#  print "tag=$tag\n"; # <-- for debugging

  $handled = 0;
  
  $short = int($offset / 0x10000); # short data stored in offset field

  if ($tag == 0x9000) {
    $exif{'ExifVersion'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA000) {
    $exif{'FlashPixVersion'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA001) {
    %tmp = (1, 'sRGB',
            0xFFFF, 'Uncalibrated');
    $exif{'ColorSpace'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0xA002) {
    $exif{'PixelXDimension'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA003) {
    $exif{'PixelYDimension'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA005) {
    #$exif{'*InteroperabilityIFD'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x9003) {
    $exif{'DateTimeOriginal'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x9004) {
    $exif{'DateTimeDigitized'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x9101) {
    #$exif{'*ComponentsConfiguration'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x9102) {
    $exif{'CompressedBitsPerPixel'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x8827) {
    $exif{'ISOSpeedRating'} = $short;
    $handled = 1;
  }
  if ($tag == 0x8822) {
    %tmp = (2, 'Programmed AE',
            3, 'Aperture Priority',
            4, 'Shutter Priority',
            7, 'Portrait',
            8, 'Landscape');
    $exif{'AE'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x9207) {
    push @names, 'Light Metering';
    %tmp = (2, 'Center',
            3, 'Spot',
            5, 'Multi');
    $exif{'Light Metering'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x8298) {
    $exif{'Copyright'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x829A) {
    $v = &exif_get_tag_value($type, $len, $offset);
    if ($v < 1) {
      $v = int(1.0 / $v + 0.5);
      $v = "1/$v";
    } else {
      $v = int($v * 100.0);
      $v = int($v / 100.0) . '.' . ($v % 100);
    }
    $exif{'Shutter Speed'} = $v . 'sec';
    $handled = 1;
  }
  if ($tag == 0x829D) {
    $exif{'Aperture Stop'} = 'F' . &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x9201) {
    $v = &exif_get_tag_value($type, $len, $offset); # APEX value
    if ($v <= 0.0) {
      $v = int(2.0 ** -$v * 100.0);
      $v = int($v / 100.0) . '.' . ($v % 100);
    } else {
      $v = '1/' . int(2.0 ** $v + 0.5);
    }
    $exif{'Shutter Speed'} = $v . 'sec';
    $handled = 1;
  }
  if ($tag == 0x9202) {
    $v = &exif_get_tag_value($type, $len, $offset); # APEX value
    $v = 2.0 ** ($v / 2.0) * 10.0;
    $v = int($v / 10.0) . '.' . ($v % 10);
    $exif{'Aperture Stop'} = "F$v";
    $handled = 1;
  }
  if ($tag == 0x9203) {
    $v = &exif_get_tag_value($type, $len, $offset); # APEX value
    $v = int(2.0 ** $v * 100.0);
    $v = int($v / 100.0) . '.' . ($v % 100);
    $exif{'Brightness'} = $v . 'foot-lambert';
    $handled = 1;
  }
  if ($tag == 0x9204) {
    $exif{'Exposure comp.'} = sprintf('%1.2fEV', &exif_get_tag_value($type, $len, $offset) );
    $handled = 1;
  }
  if ($tag == 0x9205) {
    $exif{'MaxApertureValue'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA20E) {
    $exif{'FocalPlaneXResolution'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA20F) {
    $exif{'FocalPlaneYResolution'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0xA210) {
    %tmp = (2, 'in',
            3, 'cm');
    $exif{'FocalPlaneResolutionUnit'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0xA217) {
    %tmp = (1, 'Not defined',
            2, 'One-chip color area sensor',
            3, 'Two-chip color area sensor',
            4, 'Three-chip color area sensor',
            5, 'Color sequential area sensor',
            7, 'Trilinear sensor',
            8, 'Color sequential linear sensor');
    $exif{'SensingMethod'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0131) {
    $exif{'Software'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x0132) {
    $exif{'Date'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x0110) {
    $exif{'Model'} = &exif_get_tag_value($type, $len, $offset);
    $_ = $exif{'Model'};
    if (/3000/) {
      $flratio = 33 / 7;
      $flmin = 7.13;
    }
    if (/2000/) {
      $flratio = 36 / 6.5;
      $flmin = 6.6;
    }
    if (/8000/) {
      $flratio = 40 / 6.18;
      $flmin = 6.18;
    }
    $handled = 1;
  }
  if ($tag == 0x010F) {
    $exif{'Make'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x010E) {
    $exif{'Description'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x0103) {
    %tmp = (1, 'Uncompressed',
            6, 'JPEG');
    $exif{'Compression'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0112) {
    %tmp = (1, 'Normal',
            2, 'Flipped left-right',
            3, 'Flipped top-bottom',
            4, 'Rotated 180deg',
            5, 'Rotated anticlockwise 90deg, flipped top-bottom',
            6, 'Rotated anticlockwise 90deg',
            7, 'Rotated clockwise 90deg, flipped top-bottom',
            8, 'Rotated clockwise 90deg');
    $exif{'Orientation'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x011A) {
    $exif{'XResolution'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x011B) {
    $exif{'YResolution'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x0128) {
    %tmp = (2, 'in',
            3, 'cm');
    $exif{'XYResolutionUnit'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0201) {
    #$exif{'*JpegInterchangeFormat'} = $offset;
    $handled = 1;
  }
  if ($tag == 0x0202) {
    #$exif{'*JpegInterchangeFormatLength'} = $offset;
    $handled = 1;
  }
  if ($tag == 0x0213) {
    %tmp = (1, 'Centered',
            2, 'Co-sited');
    $exif{'YCbCrPositioning'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x9286) {
    $exif{'Comment'} = &exif_get_tag_value($type, $len, $offset);
    $handled = 1;
  }
  if ($tag == 0x9209) {
    %tmp = (0, 'Did not fire',
            1, 'Fired');
    $exif{'Flash'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x920A) {
    $v = &exif_get_tag_value($type, $len, $offset);
    $exif{'Focal Length'} = $v . 'mm';
    if ($flratio) {
      $exif{'Focal Length (equiv)'} = sprintf('%3.2f', $v * $flratio) . 'mm';
    }
    $exif{'Zoom'} = sprintf('%1.2f', $v / $flmin) if ($flmin != 0);
    $handled = 1;
  }
  if ($tag == 0xA002 || $tag == 0xA003) {
    $sizex = $offset if ($tag == 0xA002);
    $sizey = $offset if ($tag == 0xA003);
    if ($sizex && $sizey) {
      $exif{'Resolution'} = $sizex . 'x' . $sizey;
    }
    $handled = 1;
  }
  
  # Casio MakerNote tags:
  if ($tag == 0x0001) {
    %tmp = ( 1, 'Single Shutter',
             7, 'Panorama',
            10, 'Night Scene',
            15, 'Portrait',
            16, 'Landscape');
    $exif{'Recording Mode'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0002) {
    %tmp = (1, 'Economy',
            2, 'Normal',
            3, 'Fine');
    $exif{'Quality'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0003) {
    %tmp = (2, 'Macro',
            3, 'Auto Focus',
            4, 'Manual Focus',
            5, 'Infinity');
    $exif{'Focusing Mode'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0004) {
    %tmp = (1, 'Auto',
            2, 'On',
            4, 'Off',
            5, 'Red Eye Reduction');
    $exif{'Flash Mode'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0005) {
    %tmp = (11, 'Weak',
            13, 'Normal',
            15, 'Strong');
    $exif{'Flash Intensity'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0006) {
    #$exif{'Object Distance'} = sprintf('%2.3fm', $short);
  }
  if ($tag == 0x0007) {
    %tmp = (  1, 'Auto',
              2, 'Tungsten',
              3, 'Daylight',
              4, 'Fluorescent',
              5, 'Shade',
            129, 'Manual');
    $exif{'White Balance'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x000A) {
    %tmp = (1, 'Off',
            2, 'x2');
    $exif{'Digital Zoom'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x000B) {
    %tmp = (0, 'Normal',
            1, 'Soft',
            2, 'Hard');
    $exif{'Sharpness'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x000C) {
    %tmp = (0, 'Normal',
            1, 'Low',
            2, 'High');
    $exif{'Contrast'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x000D) {
    %tmp = (0, 'Normal',
            1, 'Low',
            2, 'High');
    $exif{'Saturation'} = $tmp{$short};
    $handled = 1;
  }
  if ($tag == 0x0014) {
    %tmp = ( 64, 'Normal',
             80, 'Normal',
            100, 'High',
            125, '+1.0',
            250, '+2.0',
            244, '+3.0');
    $exif{'Sensitivity'} = $tmp{$short};
    $handled = 1;
  }
#  print 'Tag ' . sprintf('%X', $tag) . " not handled\n" unless ($handled); # <-- for debugging
}

sub exif_get_tag_value {
  my ($type, $len, $offset) = @_;
  my ($buf);
  if ($type == 3) {
    $buf = int($offset / 0x10000); # short data stored in offset field
  } elsif ($type == 4) {
    $buf = $offset; # long data stored as offset
  } else {
    my ($old, $n1, $n2);
    $old = tell(JPG);
    seek(JPG, $base + $offset, 0);
    if ($type == 2) {
      # string
      read(JPG, $buf, $len);
      ($buf) = unpack("a$len", $buf);
      $buf =~ s/\0.*//g; # strip terminating null and following characters
    }
    if ($type == 7) {
      # undefined
      read(JPG, $buf, $len);
      ($buf) = unpack("a$len", $buf);
      # check ID code
      if (substr($buf, 0, 8) eq "ASCII\0\0\0") {
        $buf = substr($buf, 8);
      } else {
        $buf = '';
      }
    }
    if ($type == 5 || $type == 10) {
      # rational
      read(JPG, $buf, 8);
      ($n1, $n2) = unpack(&exif_get_unpack_string('N2'), $buf);
      $buf = $n1 / $n2;
    }
    seek(JPG, $old, 0);
  }
  $buf;
}

sub exif_get_unpack_string {
  my($str) = @_;
  my($ret, $i, $ch);
  for ($i = 0; $i < length $str; $i++) {
    $ch = substr $str, $i, 1;
    if ($ch eq 'n') {
      $ret .= $unpack_short;
    } elsif ($ch eq 'N') {
      $ret .= $unpack_long;
    } else {
      $ret .= $ch;
    }
  }
  $ret;
}

1;

print "FILE DATE EXIF-RENAMER $version \n---------------------\n(c) 2006 Y.Bilozor e-mail:aslav(na)inbox.ru \n\n";
&DirLoop($sourcePath);

