#!perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id: regsort.pl 1720 2008-02-25 16:15:08Z itsme $ # # todo: add support for rgu file features: # - comments # - linecontinuation with "\s*\\\n\s*" sequence # - linecontinuation with "\s*,\n\s*" sequence # - deletekey : \[-keyname\] # - deletevalue : valname=- # - unquoted keyname # fix bug in parsing of lines like # CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969DB8053D3322AC=multi_sz:"\Windows\GAC_CustomMarshalers_v2_0_0_0_cneutral_1.dll","\Windows\.NET CF 2.0\CustomMarshalers.dll","" use strict; use IO::File; use Getopt::Long; my %escmap= ( 0=>"\0", n=>"\n", r=>"\r", t=>"\t" ); my %escrmap= reverse %escmap; # translates 'hex(7)' to multi_sz # translates valuename '@' to 'Default' my $registry= ReadRegFile(shift || "-"); WriteRegFile(shift || "-", $registry); exit(0); sub WriteRegFile { my ($fn, $reg)= @_; my $fh= $fn eq "-" ? *STDOUT : IO::File->new($fn, "w") or die "$fn: $!\n"; print "REGEDIT4\n"; my $prev; for my $key (sort { lc($a->{path}) cmp lc($b->{path}) } @$reg) { if (!defined $prev || $prev ne $key->{path}) { print "\n[$key->{path}]\n"; $prev= $key->{path}; } for my $val (sort { (!defined $a->{name} && !defined $b->{name}) ? 0 : !defined $a->{name} ? -1 : !defined $b->{name} ? 1 : lc($a->{name}) cmp lc($b->{name}) } @{$key->{values}}) { if (!defined $val->{name}) { printf("@=%s\n", $val->{value}); } else { printf("\"%s\"=%s\n", QuoteStr($val->{name}), $val->{value}); } } } $fh->close(); } sub ReadRegFile { my ($fn)= @_; my @reg; my $in= $fn eq "-" ? *STDIN : IO::File->new($fn, "r") or die "$fn: $!\n"; my ($curvaluename, $curvaluestring); my $curkey; while(<$in>) { s/\s+$//; if (/^REGEDIT4$/ || /^$/ || /^;/) { # header line } elsif (/^\[(.*)\]$/) { # line with path $curkey= { path=>$1, values=>[] }; push @reg, $curkey; } elsif (/^\s*(?:"((?:[^"\\]|\\["\\0nrt]|\\x\w\w)*)"|@)\s*=\s*(.*)/ || /^\s*([^"]*?)\s*=\s*(.*)/) { # line with quoted valuename my ($name, $value)= ($1, $2); if ($value =~ /(.*)\\$/) { $curvaluename= $name; $curvaluestring= $1; } else { push @{$curkey->{values}}, { name=>UnQuoteStr($name), value=>$value, }; } } elsif (/^\s+(.*)/) { # continued line my ($value)= ($1); if ($value =~ /(.*)\\$/) { $curvaluestring .= $1; } else { $curvaluestring .= $value; push @{$curkey->{values}}, { name=>UnQuoteStr($curvaluename), value=>$curvaluestring, }; } } else { print"$_\n"; } } $in->close(); return \@reg; } sub UnQuoteStr { my ($str)= @_; return undef unless (defined $str); $str =~ s/\\(?:x(\w\w)|(.))/defined $1 ? chr(hex($1)) : exists $escmap{$2} ? $escmap{$2}:$2/ge; return $str; } sub QuoteStr { my ($str)= @_; $str =~ s/./exists $escrmap{$&}?"\\$escrmap{$&}":(ord($&)<0x20 || ord($&)>=0x7e)?sprintf("\\x%02x", ord($&)):$&/ge; return $str; }