diff --git a/mongo-cleanup.sh b/mongo-cleanup.sh new file mode 100755 index 0000000..41379bb --- /dev/null +++ b/mongo-cleanup.sh @@ -0,0 +1,5 @@ +#!/bin/bash +sudo rm /var/lib/mongodb/mongod.lock +sudo -u mongodb mongod -f /etc/mongodb.conf --repair +sudo start mongodb +sudo status mongodb diff --git a/plutil.pl b/plutil.pl new file mode 100755 index 0000000..9095de0 --- /dev/null +++ b/plutil.pl @@ -0,0 +1,1077 @@ +# plutil.pl 1.6 - implementation of binary/UTF-8 (text) XML conversion of plist files +# does not (yet) support OS X plutil command line syntax + +# 1.0 - first public release +# 1.1 - added support for date Type 3; fixed real Type 2 +# 1.2 - fixed handling of empty arrays +# 1.3 - fixed handling of large strings and empty keys +# 1.4 - write utf8 in XML, convert as necessary on read +# 1.5 - read/write 8 byte integers and negative integers; handle special XML chars in dictionary keys +# - now requires Math::BigInt +# 1.6 - read/write data fields (type 4); also handles funny filenames better +# - now requires MIME::Base64 +# 1.7 - correct binary to XML conversion + +# Copyright 2007-2008 Starlight Computer Wizardry + +use strict; + +use Encode qw(decode encode); +use Fcntl qw(:seek); +use Time::Local 'timegm_nocheck'; +use POSIX (); +use Math::BigInt; +use MIME::Base64; + +my $VERSION = "v1.5"; + + sub nice_string { + join("", + map { $_ > 255 ? # if wide character... + sprintf("\\x{%04X}", $_) : # \x{...} + chr($_) =~ /[[:cntrl:]]/ ? # else if control character ... + sprintf("\\x%02X", $_) : # \x.. + quotemeta(chr($_)) # else quoted or as themselves + } unpack("U*", $_[0])); # unpack Unicode characters + } + + +my @Offsets; +my ($OffsetSize, $ObjRefSize, $NumObjects, $TopObject, $OffsetTableOffset); +my $OVal; + +my ($InX, %Strings); +my $SNum = 0; +my $SLen = 0; # string lens +my $ILen = 0; # int lens +my $MLen = 0; # Misc lens +my $OLen = 0; # object lens + +sub GetToken { + $InX =~ s/^\s+//; # skip whitespace + +# print "from ",substr($InX, 1, 20)," => "; + + if ($InX =~ s/<([^>]+)>//) { +# print "Token: $1\n"; + return $1; + } + else { + die "Can't find token at " . substr($InX, 0, 80); + } +} + +sub GetNonToken { + my ($t) = @_; + + if ($InX =~ s{([^<]*)}{}) { + return $1; + } + else { + die "can't find end of <$t> at " . substr($InX, 0, 80); + } +} + +sub PushToken { + my ($t) = @_; + $InX = "<$t>" . $InX; +} + +sub ReadXinteger { + my $s = +GetNonToken("integer"); + + my $il = 1; + $il += 1 if ($s > 255); + $il += 2 if ($s > 65535); + $il += 4 if ($s > Math::BigInt->new("4294967295")); + $il += 7 if ($s < 0); + $ILen += $il+1; +# print "ILen (int $s) += ", $il+1, "\n"; + + ++$NumObjects; + + return ["integer", $s]; +} + +sub ReadXreal { + my $s = +GetNonToken("real"); + + $MLen += 9; +# print "MLen (real $s) += 9\n"; + + ++$NumObjects; + + return ["real", +$s]; +} + +sub ReadXdate { + my $s = +GetNonToken("date"); + + $MLen += 9; +# print "MLen (date $s) += 9\n"; + + ++$NumObjects; + + return ["date", +$s]; +} + +sub CountIntSize { + my ($num) = @_; + + my $ans = 0; + + $ans += 2 if $num > 14; + $ans += 1 if $num > 255; + $ans += 2 if $num > 65535; + + return $ans; +} + +sub CountX { + my ($s) = @_; + if (not defined $Strings{$s}) { + ++$NumObjects; + $Strings{$s} = ++$SNum; +# print "SLen ('$s' ",length($s),") += ",length($s)+1 + CountIntSize(length($s)),"\n"; + $SLen += length($s)+1; + $ILen += CountIntSize(length($s)); + } +} + + +sub ReadXdata { + my $s = +GetNonToken("data"); + + + ++$NumObjects; + + my $buf = decode_base64($s); + $MLen += length($buf)+1; + print "MLen (data ",unpack("H*",$buf),") += ",length($buf)+1,"\n"; + $ILen += CountIntSize(length($buf)); + print "ILen (data(",length($buf),")) += ", CountIntSize(length($buf)),"\n"; + +# print "buf=",unpack("H*",$buf),"\n"; + + return ["data", $buf]; +} + +sub UnfixXMLString { + my ($s) = @_; + + $s =~ s/<//g; + $s =~ s/&/&/g; + + return $s; +} + +sub ReadXstring { + my $s = UnfixXMLString(GetNonToken("string")); + + CountX($s); + return ["string", $s]; +} + +sub ReadXustring { + my $s = GetNonToken("ustring"); + + $s = pack "U0C*", unpack "C*", $s; + + if (not defined $Strings{$s}) { + ++$NumObjects; + $Strings{$s} = ++$SNum; +# print "SLen ('",nice_string($s),"' ",length($s)*2,") += ",length($s)*2+1 + CountIntSize(length($s)),"\n"; + $SLen += length($s)*2+1; + $ILen += CountIntSize(length($s)); + } + +# now treat as utf8 so binary output will work + + return ["ustring", $s]; +} + +sub ReadXarray { + my @array; + + my $j = 0; + + while (1) { + my $t = GetToken(); + last if ($t eq "/array"); + PushToken($t); + my $v = ReadXObject(); + ++$j; + push @array,$v; + ++$OLen; # count each array member + } + + ++$NumObjects; + ++$MLen; # count array type byte + $ILen += CountIntSize(scalar @array); + + return ["array", \@array]; +} + +sub ReadXdict { + my %dict; + + my $t = GetToken(); + while ($t eq "key") { + my $k = UnfixXMLString(GetNonToken("key")); + CountX($k); + my $v = ReadXObject(); + $dict{$k} = $v; + $t = GetToken(); + $OLen += 2; + } + die "Missing /dict at $t" if ($t ne "/dict"); + + ++$NumObjects; + ++$MLen; # count dict type byte + $ILen += CountIntSize(scalar keys %dict); + return ["dict", \%dict]; +} + +sub ReadXtrue_ { + ++$NumObjects; + $MLen += 1; # type + return ["true", 1]; +} + +sub ReadXfalse_ { + ++$NumObjects; + $MLen += 1; # type + return ["false", 0]; +} + +sub ReadXObject { + my $t = GetToken(); + $t =~ s{/$}{_}; +# print "ReadX$t()\n"; + my $ans = eval "ReadX" . $t . "()"; + die "$@ in ReadXObject" if $@; + + return $ans; +} + +#my ($OffsetSize, $ObjRefSize, $NumObjects, $TopObject, $OffsetTableOffset); +#my @Offsets; +my @VObjects; +my $ObjNum = 0; +my %WStrings; + +sub MakeInt { + my ($anInt) = @_; + my $ans = ""; + + if ($anInt > 65535) { # 4 byte int + $ans = "\x12" . pack("N", $anInt); + } + elsif ($anInt > 255) { # 2 byte int + $ans = "\x11" . pack("n", $anInt); + } + else { + $ans = "\x10" . pack("C", $anInt); + } + + return $ans; +} + +sub MakeAType { + my ($typ, $len) = @_; + my $ans = ""; +# print "MakeAType($typ,$len)\n"; + + my $optint = ""; + + if ($len < 15) { + $typ .= sprintf("%x", $len); + } + else { + $typ .= "f"; + $optint = MakeInt($len); + } +# print "typ=$typ\n"; + $ans = pack("H*", $typ) . $optint; + + return $ans; +} + +sub WriteBtrue { + my $oVal = $OVal; + my $objNum = $ObjNum++; + my $t = "\x09"; + $VObjects[$objNum] = $t; + +# print "#$objNum -> true\n"; + return $objNum; +} + +sub WriteBfalse { + my $oVal = $OVal; + my $objNum = $ObjNum++; + my $t = "\x08"; + $VObjects[$objNum] = $t; + +# print "#$objNum -> false\n"; + return $objNum; +} + +sub WriteBinteger { + my $oVal = $OVal; + my $objNum = $ObjNum++; + my $il = 0; + if ($oVal > 255) { + ++$il; + } + if ($oVal > 65535) { + ++$il; + } + if ($oVal > Math::BigInt->new("4294967295")) { + ++$il; + } + $il = 3 if ($oVal < 0); + + my $t = MakeAType("1", $il); + my $buf; + if ($il < 3) { + $buf = pack((($il == 0) ? "C" : (($il == 1) ? "n" : "N" )), $oVal); + } + else { + if ($oVal < 0) { + $oVal += Math::BigInt->new(2)->bpow(64); + } + my $hw = Math::BigInt->new($oVal); + $hw->brsft(32); + my $lw = Math::BigInt->new($oVal); + $lw->band(Math::BigInt->new("4294967295")); + $buf = pack("N", $hw) . pack("N", $lw); + } + $VObjects[$objNum] = $t . $buf; +# print "($il) VObjects[$objNum] = ",unpack("H*", $VObjects[$objNum])," : "; + +# print "#$objNum -> $oVal\n"; + return $objNum; +} + +sub WriteBreal { + my $oVal = $OVal; + my $objNum = $ObjNum++; + + my $t = MakeAType("2", 3); + $VObjects[$objNum] = $t . reverse(pack("d", $oVal)); + +# print "#$objNum -> $oVal\n"; + return $objNum; +} + +sub WriteBdate { + my $oVal = $OVal; + my $objNum = $ObjNum++; + + my ($year,$mon,$mday,$hour,$min,$sec) = unpack "A4xA2xA2xA2xA2xA*",$oVal; + $sec =~ s/Z$//; + my ($fsec,$isec) = POSIX::modf($sec); +# print "Write date $year-$mon-${mday}T$hour:$min:${sec}Z\n"; + $oVal = timegm_nocheck($isec,$min,$hour,$mday,$mon-1,$year-1900)-978307200 + $fsec; + + my $t = MakeAType("3", 3); + $VObjects[$objNum] = $t . reverse(pack("d", $oVal)); + +# print "#$objNum -> $oVal\n"; + return $objNum; +} + +sub WriteBdata { + my $oVal = $OVal; + my $objNum = $ObjNum++; + + my $t = MakeAType("4", length($oVal)); +# print "data(",length($oVal),")\n"; + $VObjects[$objNum] = $t . $oVal; + +# print "#$objNum -> ",unpack("H*",$oVal),"\n"; + return $objNum; +} + +sub WriteBstring { + my $oVal = $OVal; + my $objNum; + + if (not defined $WStrings{$oVal}) { + $objNum = $ObjNum++; + $WStrings{$oVal} = $objNum; + my $t = MakeAType("5", length($oVal)); + $VObjects[$objNum] = $t . $oVal; +# print "#$objNum -> $oVal\n"; + } + else { + $objNum = $WStrings{$oVal}; + } + + return $objNum; +} + +sub WriteBustring { + my $oVal = $OVal; + my $objNum; + + if (not defined $WStrings{$oVal}) { + $objNum = $ObjNum++; + $WStrings{$oVal} = $objNum; + my $t = MakeAType("6", length($oVal)); + $VObjects[$objNum] = $t . pack("C*", unpack("U*", encode("UTF-16BE", $oVal))); +# print "#$objNum -> ", nice_string($oVal), "\n"; + } + else { + $objNum = $WStrings{$oVal}; + } + + return $objNum; +} + +sub WriteBarray { + my $oVal = $OVal; + my $objNum = $ObjNum++; + my $t = MakeAType("a", scalar @$oVal); + + for (my $j = 0; $j < @$oVal; ++$j) { + my $vref = WriteB($oVal->[$j]); +# print "[$j] = $vref\n"; + $t .= PackIn($ObjRefSize, $vref); + } + + $VObjects[$objNum] = $t; +# print "#$objNum = [", unpack("H*", $t), "]\n"; + return $objNum; +} + +sub WriteBdict { + my $oVal = $OVal; + my $objNum = $ObjNum++; + my $t = MakeAType("d", scalar keys %$oVal); + + foreach my $k (sort keys %$oVal) { + my $kref = WriteB(["string", $k]); + $t .= PackIn($ObjRefSize, $kref); + } + + foreach my $k (sort keys %$oVal) { + my $vref = WriteB($oVal->{$k}); + $t .= PackIn($ObjRefSize, $vref); + } + + $VObjects[$objNum] = $t; +# print "#$objNum = {", unpack("H*", $t), "}\n"; + return $objNum; +} + +sub WriteB { + my ($obj) = @_; + my $oType = $obj->[0]; + $OVal = $obj->[1]; + + my $ans; + if ($oType ne "") { + $ans = eval "WriteB" . $oType . "()"; + die "$@ in WriteB" if $@; + } + else { + die "$oType == ''"; + } + + return $ans; +} + +sub TryName { + my ($oldname,$fromtype, $totype, $tryext) = @_; + + + if ($oldname =~ /\.$fromtype\.$tryext$/) { + print "Found .$fromtype.$tryext\n"; + $oldname =~ s/\.$fromtype\.$tryext$/.$totype.$tryext/; + } + elsif ($oldname =~ /\.$tryext$/) { + print "Found .$tryext\n"; + $oldname =~ s/\.$tryext$/.$totype.$tryext/; + } + + print "TryName: $oldname\n"; + + return $oldname; +} + +sub NewName { + my ($oldname, $fromtype, $totype) = @_; + print "Old: $oldname, from: $fromtype, to: $totype\n"; + my $newname = TryName($oldname, $fromtype, $totype, "plist"); + + $newname = TryName($newname, $fromtype, $totype, "strings"); + $newname .= ".$totype" if $newname !~ /$totype/; + + return $newname; +} + +sub NumBytesNeeded { + my ($num) = @_; + + my $ans = 0; + + while ($num >= 1) { + ++$ans; + $num /= 256; + } + + return $ans; +} + +sub PackIn { + my ($bytes, $num) = @_; + + my $fmt = ["C", "n", "N", "N"]->[$bytes-1]; + + if ($bytes == 3) { + my $ans = substr(pack($fmt, $num), -3); +# print "PackIn($bytes, $num) = ", unpack("H*", $ans),"\n"; + return $ans; + } + else { + return pack($fmt, $num); + } +} + +sub ConvertXMLToBinary { + my ($filename) = @ARGV; + my $newname = NewName($filename, "text", "binary"); + + print "XMLToBinary:\n"; + + open(INF, "<", $filename) or die "can't open $filename for conversion"; # removed :utf8 + readline INF; # skip XML line + readline INF; # skip DTD line + my $verline = readline INF; + chomp $verline; + warn "Unknown plist version $verline" if $verline ne ""; + + $InX = do { local $/; undef $/; }; + +# brute force remove unicode flag +# $InX = pack "C*", unpack "U0C*", $InX; + + $NumObjects = 0; + my $top = ReadXObject(); + + print "NumObjects = $NumObjects\n"; + $ObjRefSize = NumBytesNeeded($NumObjects); + print "ObjRefSize = $ObjRefSize\n"; + + print "String Lengths = $SLen\n"; + print "Int Lengths = $ILen\n"; + print "Misc Lengths = $MLen\n"; + print "$OLen obj refs = ", $OLen * $ObjRefSize, "\n"; + my $fileSize = $SLen + $ILen + $MLen + $OLen * $ObjRefSize + 40; + print "Object FileSize = $fileSize\n"; + $OffsetSize = NumBytesNeeded($fileSize); + print "OffsetSize = $OffsetSize\n"; + print "Total Filesize = ",$fileSize + $NumObjects * $OffsetSize,"\n"; + $OffsetTableOffset = $fileSize - 32; + print "OffsetTableOffset = $OffsetTableOffset\n\n"; + print "Unique strings = ", scalar keys %Strings,"\n"; + + $TopObject = 0; + + close(INF); + + open(OUTF, ">$newname") or die "can't open $newname for output"; + binmode(OUTF); + +# output magic header + print OUTF "bplist00"; + + WriteB($top); + + my $objOffset = 8; + my @offsets; + + for (my $j = 0; $j < @VObjects; ++$j) { + print OUTF $VObjects[$j]; + $offsets[$j] = $objOffset; + $objOffset += length($VObjects[$j]); + } + + for (my $j = 0; $j < @offsets; ++$j) { + print OUTF PackIn($OffsetSize, $offsets[$j]); + } + + print OUTF pack("x6CC", $OffsetSize, $ObjRefSize); + print OUTF pack("x4N", $NumObjects); + print OUTF pack("x4N", $TopObject); + print OUTF pack("x4N", $OffsetTableOffset); + + close(OUTF); +} + +my %RStrings; + +sub ReadBType0 { + my ($objLen) = @_; + my $ans; + + if ($objLen == 0) { + $ans = ["null", 0]; + } + elsif ($objLen == 8) { + $ans = ["false", 0]; + } + elsif ($objLen == 9) { + $ans = ["true", 1]; + } + elsif ($objLen == 15) { + $ans = ["fill", 15]; + } + + ++$MLen; + +# print $ans->[0],"\n"; + return $ans; +} + +sub ReadBType1 { # int + my ($objLen) = @_; + die "Integer > 8 bytes = $objLen" if ($objLen > 3); + + my $byteLen = 1 << $objLen; + + my ($buf, $val); + read(INF, $buf, $byteLen); + if ($objLen == 0) { + $val = unpack("C", $buf); + } + elsif ($objLen == 1) { + $val = unpack("n", $buf); + } + elsif ($objLen == 2) { + $val = unpack("N", $buf); + } + elsif ($objLen == 3) { +# print "buf=",unpack("H*",$buf),"\n"; + my ($hw,$lw) = unpack("NN", $buf); + $val = Math::BigInt->new($hw)->blsft(32)->bior($lw); + if ($val->bcmp(Math::BigInt->new(2)->bpow(63)) > 0) { + $val -= Math::BigInt->new(2)->bpow(64); + } +# print "8 byte val: hw; $hw, lw: $lw, val: $val\n"; +# $val = unpack("Q", $buf); +# print "8 byte val (Q): $val\n"; + } + $ILen += $byteLen+1; + +# print "$val\n"; + return ["int", $val]; +} + +sub ReadBType2 { # real + my ($objLen) = @_; + die "Real > 8 bytes" if ($objLen > 3); + + my $byteLen = 1 << $objLen; + + my ($buf, $val); + read(INF, $buf, $byteLen); + if ($objLen == 0) { # 1 byte float = error? + die "1 byte real found"; + } + elsif ($objLen == 1) { # 2 byte float??? + die "2 byte real found"; + } + elsif ($objLen == 2) { + $val = unpack("f", reverse $buf); + } + elsif ($objLen == 3) { + $val = unpack("d", reverse $buf); + } + + $MLen += 9; + +# print "$val\n"; + return ["real", $val]; +} + +sub ReadBType3 { # date + my ($objLen) = @_; + die "Date > 8 bytes" if ($objLen > 3); + + my $byteLen = 1 << $objLen; + + my ($buf, $val); + read(INF, $buf, $byteLen); + if ($objLen == 0) { # 1 byte NSDate = error? + die "1 byte NSDate found"; + } + elsif ($objLen == 1) { # 2 byte NSDate??? + die "2 byte NSDate found"; + } + elsif ($objLen == 2) { + $val = unpack("f", reverse $buf); + } + elsif ($objLen == 3) { + $val = unpack("d", reverse $buf); + } + + $MLen += 9; + +# print "$val\n"; + return ["date", $val]; +} + +sub ReadBType4 { # binary data + my ($byteLen) = @_; + + my $buf; + read(INF, $buf, $byteLen); + + $MLen += $byteLen+1; + +# print "buf($byteLen)=",unpack("H*",$buf),"\n"; + return ["data", $buf]; +} + + +sub ReadBType5 { # byte (utf8?) string + my ($objLen) = @_; + + my $buf; + read(INF, $buf, $objLen); + + if (not defined $RStrings{$buf}) { + $SLen += $objLen+1; +# print "SLen ($buf) = ",$objLen+1,"\n"; + $RStrings{$buf} = 1; + } + else { + $ILen -= CountIntSize($objLen); + } + + $buf = pack "U0C*", unpack "C*", $buf; # mark as Unicode + +# print "$buf\n"; + return ["string", $buf]; +} + +sub ReadBType6 { # unicode string + my ($objLen) = @_; + + my $buf; + read(INF, $buf, 2*$objLen); + + if (not defined $RStrings{$buf}) { + $SLen += 2*$objLen+1; + $RStrings{$buf} = 1; + } + else { + $ILen -= CountIntSize($objLen); + } + +# print nice_string(decode("UTF-16BE", $buf)); + return ["ustring", decode("UTF-16BE", $buf)]; +} + +sub ReadBTypea { # array + my ($objLen) = @_; + + my @array; + + # read objrefs + my $buf; + read(INF, $buf, $objLen * $ObjRefSize); + my @objs = unpack(($ObjRefSize == 1 ? "C*" : "n*"), $buf); + + for (my $j = 0; $j < $objLen; ++$j) { + my $obj = ReadBObjectAt($objs[$j]); + $array[$j] = $obj; + } + + ++$MLen; + +# print "array\n"; + return ["array", \@array]; +} + +sub ReadBTyped { # dictionary + my ($objLen) = @_; + my %dict; + +# print "dict\n"; + + # read keys + my $buf; + read(INF, $buf, $objLen * $ObjRefSize); + my @keys = unpack(($ObjRefSize == 1 ? "C*" : "n*"), $buf); + + # read objrefs + read(INF, $buf, $objLen * $ObjRefSize); + my @objs = unpack(($ObjRefSize == 1 ? "C*" : "n*"), $buf); + + for (my $j = 0; $j < $objLen; ++$j) { +# print "\t= "; + my $key = ReadBObjectAt($keys[$j])->[1]; +# print " -> "; + my $obj = ReadBObjectAt($objs[$j]); + $dict{$key} = $obj; + } + + ++$MLen; + +# print "\n"; + return ["dict", \%dict]; +} + +sub ReadBObject { + # get object type/size + my $buf; + if (read(INF, $buf, 1) != 1) { + die "Didn't read type byte: $!"; + } + my $objLen = unpack("C*", $buf) & 0xF; + $buf = unpack("H*", $buf); + my $objType = substr($buf, 0, 1); + if ($objType ne "0" && $objLen == 15) { + $objLen = ReadBObject()->[1]; + } + +# print "ReadBType $objType ( $objLen )\n"; + my $ans = eval "ReadBType" . $objType . "($objLen)"; + die "$@ in ReadBObject" if $@; + + return $ans; +} + +sub ReadBObjectAt { + my ($objNum) = @_; + +# print "#$objNum @(", $Offsets[$objNum],")= "; + seek(INF, $Offsets[$objNum], SEEK_SET); + return ReadBObject(); +} + +my ($Indent); + +sub FixXMLString { + my ($in) = @_; + + $in =~ s/&/&/g; + $in =~ s//>/g; + + return $in; +} + +sub WriteXMLstring { + my $oVal = $OVal; + print OUTF "\t" x $Indent,"",FixXMLString($oVal),"\n"; +} + +sub WriteXMLtrue { + print OUTF "\t" x $Indent,"\n"; +} + +sub WriteXMLfalse { + print OUTF "\t" x $Indent,"\n"; +} + +sub WriteXMLint { + my $oVal = $OVal; + print OUTF "\t" x $Indent,"$oVal\n"; +} + +sub WriteXMLreal { + my $oVal = $OVal; + print OUTF "\t" x $Indent,""; + my $ans = sprintf "%.25f", $oVal; + $ans =~ s/0+$//; + print OUTF "$ans\n"; +} + +sub WriteXMLdate { # note: CFDate is a double = # seconds since 1/1/2001 0:0:0 GMT +# Windows Perl epoch 1/1/1970 0:0:0 UTC so difference is 978307200 + my $oVal = $OVal; + + print "date $oVal\n"; + + my ($fsec,$iVal) = POSIX::modf($oVal); + + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(978307200+$iVal); + print OUTF "\t" x $Indent,""; + printf OUTF "%04d-%02d-%02dT%02d:%02d:%.6fZ", $year+1900,$mon+1,$mday,$hour,$min,$sec+$fsec; + print OUTF "\n"; +} + +sub WriteXMLdata { + my $oVal = $OVal; + print "oVal=",unpack("H*",$oVal),"\n"; + my $ind = "\t" x $Indent; + + print OUTF "$ind\n"; + my $buf = encode_base64($oVal,""); + print "buf=\n$buf\n"; +# limit lines to 76 chars, counting tabs as 8 chars + my $len = 76 - 8 * $Indent; + my @lines = unpack("(a$len)*",$buf); + foreach (@lines) { + print OUTF $ind,$_,"\n"; + } + print OUTF $ind, "\n"; +} + +sub WriteXMLustring { + my $oVal = $OVal; + $oVal =~ s/&/&/g; + $oVal =~ s//>/g; + print OUTF "\t" x $Indent,"$oVal\n"; +} + +sub WriteXMLarray { + my $oVal = $OVal; + print OUTF "\t" x $Indent,"\n"; + + ++$Indent; + foreach my $v (@$oVal) { + WriteXML($v); + } + --$Indent; + + print OUTF "\t" x $Indent,"\n"; +} + +sub WriteXMLdict { + my $oVal = $OVal; + + print OUTF "\t" x $Indent,"\n"; + + ++$Indent; + foreach my $k (sort keys %$oVal) { + print OUTF "\t" x $Indent,"",FixXMLString($k),"\n"; + WriteXML($oVal->{$k}); + } + --$Indent; + + print OUTF "\t" x $Indent,"\n"; +} + +sub WriteXML { + my ($obj) = @_; + + my $oType; + ($oType, $OVal) = @$obj; + + if ($oType ne "") { + eval "WriteXML" . $oType . "()"; + die "$@ in WriteXML" if $@; + } + else { + die "$oType is null!"; + } +} + +sub WriteTopXML { + $Indent = 0; + WriteXML(@_); +} + +sub ConvertBinaryToXML { + my ($filename) = @_; + my $newname = NewName($filename, "binary", "text"); + + print "BinaryToXML:\n"; + open(INF, $filename) or die "can't open $filename for conversion"; + binmode(INF); + open(OUTF, ">:utf8", "$newname") or die "can't open $newname for output"; + +# get trailer + seek(INF, -32, SEEK_END); + my $buf; + read(INF, $buf, 32); + ($OffsetSize, $ObjRefSize, $NumObjects, $TopObject, $OffsetTableOffset) = unpack "x6CC(x4N)3", $buf; + + print "Offsets are $OffsetSize bytes\n"; + print "Object Refs are $ObjRefSize bytes\n"; + print "There are $NumObjects objects in the file\n"; + print "The top object is at $TopObject\n"; + print "The Offset Table is at offset $OffsetTableOffset\n\n"; + +# get the offset table + seek(INF, $OffsetTableOffset, SEEK_SET); + my $rawOffsetTable; + my $readSize = read(INF, $rawOffsetTable, $NumObjects * $OffsetSize); + if ($readSize != $NumObjects * $OffsetSize) { + die "rawOffsetTable read $readSize expected ",$NumObjects * $OffsetSize; + } + + @Offsets = unpack(["","C*","n*","(H6)*","N*"]->[$OffsetSize], $rawOffsetTable); + if ($OffsetSize == 3) { + @Offsets = map { hex($_) } @Offsets; + } + + $ILen = 0; + $MLen = 0; + $SLen = 0; + + my $top = ReadBObjectAt($TopObject); + + print "Int Lengths = $ILen\n"; + print "Misc Lengths = $MLen\n"; + print "String Lengths = $SLen\n"; + print "Unique Strings = ",scalar keys %RStrings,"\n"; + +# write the XML header + print OUTF "\n"; + print OUTF "\n"; + print OUTF "\n"; + +# dump out the top object + WriteTopXML($top); + +# write the XML trailer + print OUTF "\n"; + + close(OUTF); + close(INF); +} + +sub Convert { + + print "plutil.pl $VERSION\n\n"; + + my ($filename) = @ARGV; + + if (-s $filename < 8) { + die "$filename is too short for a plist file"; + } + + # convert binary or text? + + open(INF, $filename) or die "can't open $filename"; + + my $magic; + read(INF, $magic, 8); + close(INF); + + if (substr($magic, 0, 6) eq "bplist") { # convert binary plist to XML + if (not ($magic =~ /00$/)) { + warn "Binary plist unknown version: " . substr($magic, -2); + } + ConvertBinaryToXML($filename); + } + else { # convert XML to binary plist + ConvertXMLToBinary($filename); + } +} + +if ((@ARGV > 0) && (-e $ARGV[0])) { + Convert($ARGV[0]); +} +else { + print "usage: plutil file[.text|.binary][.plist|.strings|.*]\n"; +} diff --git a/resty b/resty new file mode 100755 index 0000000..231155f --- /dev/null +++ b/resty @@ -0,0 +1,150 @@ +# +# resty - A tiny command line REST interface for bash and zsh. +# +# Fork me on github: +# http://github.com/micha/resty +# +# Author: +# Micha Niskin +# Copyright 2009, no rights reserved. +# + +export _resty_host="" +export _resty_path="" +export _resty_nohistory="" + +function resty() { + local confdir datadir host cookies method h2t editor domain _path opt dat res ret out err verbose raw i j d tmpf args2 wantdata vimedit quote query maybe_query + local -a curlopt + local -a curlopt2 + + if [ -n "$XDG_CONFIG_HOME" ]; then + confdir="$XDG_CONFIG_HOME/resty" + datadir="$XDG_DATA_HOME/resty" + else + confdir="$HOME/.resty" + datadir="$confdir" + fi + mkdir -p "$confdir" + host="$datadir/host" + cookies="$datadir/c" + method="$1"; [[ $# > 0 ]] && shift + h2t=$((exec 2>&-; (which lynx >/dev/null && echo lynx -stdin -dump) \ + || which html2text || which cat) |tail -n 1) + editor=$((exec 2>&-; which "$EDITOR" || which vim || echo "vi") |tail -n 1) + + [ "${method#P}" != "$method" ] || [ "$method" = "TRACE" ] && wantdata="yes" + + [ -d "$cookies" ] || (mkdir -p "$cookies"; echo "http://localhost*" > "$host") + [ -n "$1" ] && [ "${1#/}" != "$1" ] \ + && _path="$1" && [[ $# > 0 ]] && shift + [ "$1" = "${1#-}" ] && dat="$1" && [[ $# > 0 ]] && shift + + j=1 + for i in "$@"; do + [ -n "$maybe_query" -a -z "$query" ] && query="?$i" && continue + ([ "$i" = "--verbose" ] || echo "$i" | grep '^-[a-zA-Z]*v[a-zA-Z]*$' >/dev/null) \ + && verbose="yes" && continue + [ "$i" = "-V" ] && vimedit="yes" && continue + [ "$i" = "-Z" ] && raw="yes" && continue + [ "$i" = "-W" ] && continue + [ "$i" = "-Q" ] && quote="yes" && continue + [ "$i" = "-q" ] && maybe_query="yes" && continue + curlopt[j]="$i" && j=$((j + 1)) + done + + [ -z "$quote" ] && _path=$(echo "$_path"|sed 's/%/%25/g;s/\[/%5B/g;s/\]/%5D/g;s/|/%7C/g;s/\$/%24/g;s/&/%26/g;s/+/%2B/g;s/,/%2C/g;s/:/%3A/g;s/;/%3B/g;s/=/%3D/g;s/?/%3F/g;s/@/%40/g;s/ /%20/g;s/#/%23/g;s/{/%7B/g;s/}/%7D/g;s/\\/%5C/g;s/\^/%5E/g;s/~/%7E/g;s/`/%60/g') + + [ "$method" = "HEAD" ] || [ "$method" = "OPTIONS" ] && raw="yes" + [ -z "$_resty_host" ] && _resty_host=$(cat "$host" 2>/dev/null) + [ "$method" = "-v" ] && echo "$_resty_host $_resty_opts" && return + [ -z "$method" ] && echo "$_resty_host" && return + [ -n "$_path" ] && _resty_path=$_path + domain=$(echo -n "$_resty_host" \ + |perl -ane '/^https?:\/\/([^\/\*]+)/; print $1') + _path="${_resty_host//\*/$_resty_path}" + + case "$method" in + HEAD|OPTIONS|GET|DELETE|POST|PUT|TRACE) + eval "curlopt2=(${_resty_opts[*]})" + dat=$( ( [ "$wantdata" = "yes" ] \ + && ( ( [ -n "$dat" ] && echo "$dat") \ + || ([ ! -t 0 ] && echo "@-") ) ) || echo) + if [ "$wantdata" = "yes" ] && [ "$vimedit" = "yes" ]; then + tmpf=$(mktemp /tmp/resty.XXXXXX) + [ -t 0 ] || cat > $tmpf + (exec < /dev/tty; "$editor" $tmpf) + dat=$(cat $tmpf) + rm -f $tmpf + fi + [ -n "$dat" ] && [ "$dat" != "@-" ] && [[ $# > 0 ]] && shift + [ "$1" = "-Z" ] && raw="yes" && [[ $# > 0 ]] && shift + [ -n "$dat" ] && opt="--data-binary" + [ "$method" = "HEAD" ] && opt="-I" && raw="yes" + eval "args2=( $(cat "$confdir/$domain" 2>/dev/null |sed 's/^ *//' |grep ^$method |cut -b $((${#method}+2))-) )" + res=$((((curl -sLv $opt "$dat" -X $method \ + -b "$cookies/$domain" -c "$cookies/$domain" \ + "${args2[@]}" "${curlopt2[@]}" "${curlopt[@]}" "$_path$query" \ + |sed 's/^/OUT /' && echo) 3>&2 2>&1 1>&3) \ + |sed 's/^/ERR /' && echo) 2>&1) + out=$(echo "$res" |sed '/^OUT /s/^....//p; d') + err=$(echo "$res" |sed '/^ERR /s/^....//p; d') + ret=$(echo "$err" |sed \ + '/^.*HTTP\/1\.[01] [0-9][0-9][0-9]/s/.*\([0-9]\)[0-9][0-9].*/\1/p; d' \ + | tail -n1) + [ -n "$err" -a -n "$verbose" ] && echo "$err" 1>&2 + echo "$err" | grep -i '^< \s*Content-Type: *text/html' >/dev/null \ + && [ -z "$raw" ] && d=$h2t || d=cat + [ -n "$out" ] && out=$(echo "$out" |eval "$d") + [ "$d" != "${d##lynx}" ] && out=$(echo "$out" |perl -e "\$host='$(echo "$_resty_host" |sed 's/^\(https*:\/\/[^\/*]*\).*$/\1/')';" -e '@a=<>; $s=0; foreach (reverse(@a)) { if ($_ =~ /^References$/) { $s++; } unless ($s>0) { s/^\s+[0-9]+\. //; s/^file:\/\/localhost/$host/; } push(@ret,$_); } print(join("",reverse(@ret)))') + if [ "$ret" != "2" ]; then + [ -n "$out" ] && echo "$out" 1>&2 + return $ret + else + [ -n "$out" ] && echo "$out" + fi + ;; + http://*|https://*) + _resty_opts=$(printf '%q ' "${curlopt[@]}") + export _resty_opts + echo "$method" |grep '\*' >/dev/null || method="${method}*" + (echo "$method" |tee "${_resty_nohistory:-$host}") |cat 1>&2 \ + && _resty_host="$method" + ;; + *) + resty "http://$method" "${curlopt[@]}" + ;; + esac +} + +function HEAD() { + resty HEAD "$@" +} + +function OPTIONS() { + resty OPTIONS "$@" +} + +function GET() { + resty GET "$@" +} + +function POST() { + resty POST "$@" +} + +function PUT() { + resty PUT "$@" +} + +function DELETE() { + resty DELETE "$@" +} + +function TRACE() { + resty TRACE "$@" +} + +[ "$1" = "-W" ] && export _resty_nohistory="/dev/null" && [[ $# > 0 ]] && shift + +resty "$@" >/dev/null 2>&1