diff options
Diffstat (limited to 'iphone/bin/Mac')
-rwxr-xr-x | iphone/bin/Mac/Finder/AliasRecord.pm | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/iphone/bin/Mac/Finder/AliasRecord.pm b/iphone/bin/Mac/Finder/AliasRecord.pm new file mode 100755 index 0000000..06f68f6 --- /dev/null +++ b/iphone/bin/Mac/Finder/AliasRecord.pm @@ -0,0 +1,169 @@ +package Mac::Finder::AliasRecord; + +# Generate(/Parse) a Mac "alias record" binary string/file. +# +# Currently just enough is implemented to satisfy immediate requirements +# (ie, write backgroundImageAlias to .DS_Store for DMG) +# +# based on these documents: +# http://www.geocities.com/xhelmboyx/quicktime/formats/alias-layout.txt +# http://sebastien.kirche.free.fr/python_stuff/MacOS-aliases.txt +# +# FIXME interface is very poor... + +use warnings; +use strict; +use DateTime; +use File::Spec; +use File::Spec::Mac; +use Encode qw(encode); +require Exporter; + +our $VERSION = '0.1'; +our @ISA = qw(Exporter); + +my %FSEncodings = ( + MacFS => ['RW', ''], + MFS => ['RW', ''], + HFS => ['BD', ''], + 'HFS+' => ['H+', ''], + + AudioCD => ['', 'JH'], + ISO9660 => ['', 'AG'], + FAT => ['', 'IS'], + Joliet => ['', 'Jo'], + 'ISO9660+Joliet' => ['', 'Jo'], +); + +my %DiskEncodings = ( + HD => 0, + FixedHD => 0, + Network => 1, + NetworkDisk => 1, + Floppy => 4, + Floppy1440 => 4, + Other => 5, + OtherDisk => 5, +); + +my %RecordEncodings = ( + parentDir => 0x00, + absolutePath => 0x02, + unicodeFile => 0x0e, + unicodeVolume => 0x0f, + volumePath => 0x12, +); + +sub new { + my $class = shift || __PACKAGE__; + my $self = { + aliasCreator => '', + aliasVersion => 2, + aliasType => 'file', + volume => '', + volumeCreated => 0, + volumeFS => 'HFS', + volumeDisk => undef, + volumeAttrs => 0, + directoryID => 0, + file => '', + fileID => 0, + fileCreated => 0, + fileType => '', + fileCreator => '', + nlvlFrom => -1, + nlvlTo => -1, + records => { }, + @_ + }; + if(exists($self->{path})) { + my $path = $self->{path}; + my ($vol, $dir, $file) = File::Spec::Mac->splitpath($path); + $vol =~ s/:$//; + my @dir = File::Spec::Mac->splitdir($dir); + while(@dir && !$dir[0]) { + shift(@dir); + } + while(@dir && !$dir[-1]) { + pop(@dir); + } + $self->{volume} ||= $vol; + $self->{records}{unicodeVolume} ||= + pack('na*', length($vol), encode('utf-16be', $vol)); + + $self->{file} ||= $file; + $self->{records}{parentDir} ||= $dir[-1] + if(@dir); + $self->{records}{absolutePath} ||= $path; + $self->{records}{volumePath} ||= File::Spec->catfile('', @dir, $file); + $self->{records}{unicodeFile} ||= + pack('na*', length($file), encode('utf-16be', $file)); + } + return(bless($self, ref($class) || $class)); +} + +sub toFSTime { + my $val = shift; + if(ref($val) && $val->isa("DateTime")) { + $val = $val->epoch - DateTime->new(year => 1904)->epoch(); + } + return($val); +} + +sub write { + my ($self, $out) = @_; + + my $aliasType = $self->{aliasType}; + $aliasType = (($aliasType =~ /^d(ir(ectory)?)?$/i && 1) || + ($aliasType !~ /^f(ile)?$/ && $aliasType) || 0); + + my $volumeCreated = toFSTime($self->{volumeCreated}); + my $volumeFS = $self->{volumeFS}; + if(ref($volumeFS) ne 'ARRAY') { + $volumeFS = $FSEncodings{$volumeFS} || ['', '']; + } + + my $volumeDisk = $self->{volumeDisk}; + if(!defined($volumeDisk)) { + if($volumeFS->[0] eq 'H+') { + $volumeDisk = 'Floppy'; + } + elsif($volumeFS->[0]) { + $volumeDisk = 'HD'; + } + else { + $volumeDisk = 'Other'; + } + } + $volumeDisk = (exists($DiskEncodings{$volumeDisk}) + ? $DiskEncodings{$volumeDisk} + : $volumeDisk); + + my $fileCreated = toFSTime($self->{fileCreated}); + + my $buf = + pack('nn (C/a @28)Na2n N(C/a @64)NNa4a4 n!n!Na2 x10 (n!n/ax!2)*', + $self->{aliasVersion}, $aliasType, + $self->{volume}, $volumeCreated, $volumeFS->[0], $volumeDisk, + $self->{directoryID}, $self->{file}, $self->{fileID}, $fileCreated, + $self->{fileType}, $self->{fileCreator}, $self->{nlvlFrom}, + $self->{nlvlTo}, $self->{volumeAttrs}, $volumeFS->[1], + map(((exists($RecordEncodings{$_}) ? $RecordEncodings{$_} : $_) + => $self->{records}{$_}), + keys(%{$self->{records}})), + (-1, '')); + $buf = pack('a4n', $self->{aliasCreator}, length($buf) + 6) . $buf; + + if(!$out) { + return($buf); + } + elsif(ref($out) eq 'GLOB') { + print $out $buf; + } + else { + open(my $outfh, '>', $out) || die; + print $outfh $buf; + } +} + +1; |