Image-ExifTool

 view release on metacpan or  search on metacpan

lib/Image/ExifTool/Writer.pl  view on Meta::CPAN

        # renaming didn't work, so copy the file instead
        unless ($self->Open(\*EXIFTOOL_SFN_IN, $file)) {
            $self->Error("Error opening '${file}'");
            return -1;
        }
        unless ($self->Open(\*EXIFTOOL_SFN_OUT, $newName, '>')) {
            close EXIFTOOL_SFN_IN;
            $self->Error("Error creating '${newName}'");
            return -1;
        }
        binmode EXIFTOOL_SFN_IN;
        binmode EXIFTOOL_SFN_OUT;
        my ($buff, $err);
        while (read EXIFTOOL_SFN_IN, $buff, 65536) {
            print EXIFTOOL_SFN_OUT $buff or $err = 1;
        }
        close EXIFTOOL_SFN_OUT or $err = 1;
        close EXIFTOOL_SFN_IN;
        if ($err) {
            $self->Unlink($newName);    # erase bad output file
            $self->Error("Error writing '${newName}'");
            return -1;
        }
        # preserve modification time
        my ($aTime, $mTime, $cTime) = $self->GetFileTime($file);
        $self->SetFileTime($newName, $aTime, $mTime, $cTime);
        # remove the original file
        $self->Unlink($file) or $self->Warn('Error removing old file');
    }
    $$self{NewName} = $newName; # remember new file name
    ++$$self{CHANGED};
    $self->VerboseValue('+ FileName', $newName);
    return 1;
}

#------------------------------------------------------------------------------
# Set file permissions, group/user id and various MDItem tags from new tag values
# Inputs: 0) ExifTool ref, 1) file name or glob (must be a name for MDItem tags)
# Returns: 1=something was set OK, 0=didn't try, -1=error (and warning set)
# Notes: There may be errors even if 1 is returned
sub SetSystemTags($$)
{
    my ($self, $file) = @_;
    my $result = 0;

    my $perm = $self->GetNewValue('FilePermissions');
    if (defined $perm) {
        if (eval { chmod($perm & 07777, $file) }) {
            $self->VerboseValue('+ FilePermissions', $perm);
            $result = 1;
        } else {
            $self->Warn('Error setting FilePermissions');
            $result = -1;
        }
    }
    my $uid = $self->GetNewValue('FileUserID');
    my $gid = $self->GetNewValue('FileGroupID');
    if (defined $uid or defined $gid) {
        defined $uid or $uid = -1;
        defined $gid or $gid = -1;
        if (eval { chown($uid, $gid, $file) }) {
            $self->VerboseValue('+ FileUserID', $uid) if $uid >= 0;
            $self->VerboseValue('+ FileGroupID', $gid) if $gid >= 0;
            $result = 1;
        } else {
            $self->Warn('Error setting FileGroup/UserID');
            $result = -1 unless $result;
        }
    }
    my $tag;
    foreach $tag (@writableMacOSTags) {
        my $nvHash;
        my $val = $self->GetNewValue($tag, \$nvHash);
        next unless $nvHash;
        if ($^O eq 'darwin') {
            ref $file and $self->Warn('Setting MDItem tags requires a file name'), last;
            require Image::ExifTool::MacOS;
            my $res = Image::ExifTool::MacOS::SetMacOSTags($self, $file, \@writableMacOSTags);
            $result = $res if $res == 1 or not $result;
            last;
        } elsif ($tag ne 'FileCreateDate') {
            $self->Warn('Can only set MDItem tags on MacOS');
            last;
        }
    }
    # delete Windows Zone.Identifier if specified
    my $zhash = $self->GetNewValueHash($Image::ExifTool::Extra{ZoneIdentifier});
    if ($zhash) {
        my $res = -1;
        if ($^O ne 'MSWin32') {
            $self->Warn('ZoneIdentifer is a Windows-only tag');
        } elsif (ref $file) {
            $self->Warn('Writing ZoneIdentifer requires a file name');
        } elsif (defined $self->GetNewValue('ZoneIdentifier', \$zhash)) {
            $self->Warn('ZoneIndentifier may only be deleted');
        } elsif (not eval { require Win32API::File }) {
            $self->Warn('Install Win32API::File to write ZoneIdentifier');
        } else {
            my ($wattr, $wide);
            my $zfile = "${file}:Zone.Identifier";
            if ($self->EncodeFileName($zfile)) {
                $wide = 1;
                $wattr = eval { Win32API::File::GetFileAttributesW($zfile) };
            } else {
                $wattr = eval { Win32API::File::GetFileAttributes($zfile) };
            }
            if ($wattr == Win32API::File::INVALID_FILE_ATTRIBUTES()) {
                $res = 0; # file doesn't exist, nothing to do
            } elsif ($wattr & Win32API::File::FILE_ATTRIBUTE_READONLY()) {
                $self->Warn('Zone.Identifier stream is read-only');
            } else {
                if ($wide) {
                    $res = 1 if eval { Win32API::File::DeleteFileW($zfile) };
                } else {
                    $res = 1 if eval { Win32API::File::DeleteFile($zfile) };
                }
                if ($res > 0) {
                    $self->VPrint(0, "  Deleting Zone.Identifier stream\n");
                } else {
                    $self->Warn('Error deleting Zone.Identifier stream');
                }

lib/Image/ExifTool/Writer.pl  view on Meta::CPAN

            return 1 if $$tagInfo{Writable};
        }
    }
    return 0;
}

#------------------------------------------------------------------------------
# Check to see if these are the same file
# Inputs: 0) ExifTool ref, 1) first file name, 2) second file name
# Returns: true if file names reference the same file
sub IsSameFile($$$)
{
    my ($self, $file, $file2) = @_;
    return 0 unless lc $file eq lc $file2;  # (only looking for differences in case)
    my ($isSame, $interrupted);
    my $tmp1 = "${file}_ExifTool_tmp_$$";
    my $tmp2 = "${file2}_ExifTool_tmp_$$";
    {
        local *TMP1;
        local $SIG{INT} = sub { $interrupted = 1 };
        if ($self->Open(\*TMP1, $tmp1, '>')) {
            close TMP1;
            $isSame = 1 if $self->Exists($tmp2);
            $self->Unlink($tmp1);
        }
    }
    if ($interrupted and $SIG{INT}) {
        no strict 'refs';
        &{$SIG{INT}}();
    }
    return $isSame;
}

#------------------------------------------------------------------------------
# Is this a raw file type?
# Inputs: 0) ExifTool ref
# Returns: true if FileType is a type of RAW image
sub IsRawType($)
{
    my $self = shift;
    return $rawType{$$self{FileType}};
}

#------------------------------------------------------------------------------
# Copy file attributes from one file to another
# Inputs: 0) ExifTool ref, 1) source file name, 2) destination file name
# Notes: eventually add support for extended attributes?
sub CopyFileAttrs($$$)
{
    my ($self, $src, $dst) = @_;
    my ($mode, $uid, $gid) = (stat($src))[2, 4, 5];
    # copy file attributes unless we already set them
    if (defined $mode and not defined $self->GetNewValue('FilePermissions')) {
        eval { chmod($mode & 07777, $dst) };
    }
    my $newUid = $self->GetNewValue('FileUserID');
    my $newGid = $self->GetNewValue('FileGroupID');
    if (defined $uid and defined $gid and (not defined $newUid or not defined $newGid)) {
        defined $newGid and $gid = $newGid;
        defined $newUid and $uid = $newUid;
        eval { chown($uid, $gid, $dst) };
    }
}

#------------------------------------------------------------------------------
# Get new file path name
# Inputs: 0) existing name (may contain directory),
#         1) new file name, new directory, or new path (dir+name)
# Returns: new file path name
sub GetNewFileName($$)
{
    my ($oldName, $newName) = @_;
    my ($dir, $name) = ($oldName =~ m{(.*/)(.*)});
    ($dir, $name) = ('', $oldName) unless defined $dir;
    if ($newName =~ m{/$}) {
        $newName = "$newName$name"; # change dir only
    } elsif ($newName !~ m{/}) {
        $newName = "$dir$newName";  # change name only if newname doesn't specify dir
    }                               # else change dir and name
    return $newName;
}

#------------------------------------------------------------------------------
# Get next available tag key
# Inputs: 0) hash reference (keys are tag keys), 1) tag name
# Returns: next available tag key
sub NextFreeTagKey($$)
{
    my ($info, $tag) = @_;
    return $tag unless exists $$info{$tag};
    my $i;
    for ($i=1; ; ++$i) {
        my $key = "$tag ($i)";
        return $key unless exists $$info{$key};
    }
}

#------------------------------------------------------------------------------
# Reverse hash lookup
# Inputs: 0) value, 1) hash reference
# Returns: Hash key or undef if not found (plus flag for multiple matches in list context)
sub ReverseLookup($$)
{
    my ($val, $conv) = @_;
    return undef unless defined $val;
    my $multi;
    if ($val =~ /^Unknown\s*\((.*)\)$/i) {
        $val = $1;    # was unknown
        if ($val =~ /^0x([\da-fA-F]+)$/) {
            # disable "Hexadecimal number > 0xffffffff non-portable" warning
            local $SIG{'__WARN__'} = sub { };
            $val = hex($val);   # convert hex value
        }
    } else {
        my $qval = $val;
        $qval =~ s/\s+$//;      # remove trailing whitespace
        $qval = quotemeta $qval;
        my @patterns = (
            "^$qval\$",         # exact match
            "^(?i)$qval\$",     # case-insensitive
            "^(?i)$qval",       # beginning of string



( run in 2.192 seconds using v1.01-cache-2.11-cpan-71847e10f99 )