Hacking locdat for Sorting SD Card Channels

Skeeve

Well-Known Member
OP
Newcomer
Joined
Jan 1, 2010
Messages
75
Trophies
0
XP
146
Country
Gambia, The
Hi!

In another forum I found a question whether or not there is an easier way to sort Channels on the SD Card because it is a bit boring to do it on the wii. Maybe there are tools around, but I don't know of any.

So I searched a bit and hacked a small perl script that might help you (or some of you). It's just in early alpha stage but as I go on vacation now, I thought I'd better push it out for anyone to test. Help and man page for example are currently completely missing.

Prerequisites are:<ol type='1'><li>perl must be installed</li><li>perl module Digest::MD5 (should be standard)</li><li>working openssl installation</li></ol>The prerequisites should be fulfilled by OS X (what I use) and Linux (I guess). For WinDOS you'll have to figure it out on your own.

Copy the code below into a text file called "locdat" and make it executable.

Insert your SD Card containing your channels into the computer.

Start the scriot with <!--fonto:Courier New--><span style="font-family:Courier New"><!--/fonto-->./locdat /Path/to/SD/Card<!--fontc--></span><!--/fontc-->. This will output a list of all the channels found. The list will look like this:

01-1-A: [XXXX] Name of the channel Region Platform

Meaning:
01: Page 1 of the SD Card menu (will go from 01 to 20)
1: Row 1 (will go from 1 to 3)
A: Column 1 (will go from A to D)
[XXXX]: The 4 Letters of the Channel's ID
Region: Something like "Europe", "US" ...
Platform: Something like "WiiWare", "N64", "Neo-Geo"...

If you save the list in a text file, either by redirecting the ouput or by calling <!--fonto:Courier New--><span style="font-family:Courier New"><!--/fonto-->./locdat /Path/to/SD/Card -out loc.txt<!--fontc--></span><!--/fontc-->, you can afterwards open the textfile in any descent texteditor (jEdit for example) and change the sequence to whatever you like. When Sorting, just the Channel ID in brackets and the colon before it is important. Everything else is ignored. So no need to move the cell addresses (01-1-A) around.

There are 2 special cases:
1. A line having just minus signs after the colon will create a page break in the SD Card Menu
2. A line having no Channel ID after the colon will create an empty entry

When you are satisfied with your changes, call <!--fonto:Courier New--><span style="font-family:Courier New"><!--/fonto-->./locdat /Path/to/SD/Card -e -in loc.txt<!--fontc--></span><!--/fontc--> to encode the new loc.dat in its default location.

I hope the explanation is sufficient enough. If not, just ask and hope for someone else to jump in as I won't be back before August 29 <img src="style_emoticons/<#EMO_DIR#>/wink.gif" style="vertical-align:middle" emoid=";)" border="0" alt="wink.gif" />

Note the 2 lines in the code you might need or want to modify:
a) my $OPENSSL= '/usr/bin/openssl';
b) my $lang= 'DE';

Set in a) the path to your openssl binary.
Set in b) your preferred language. As I'm German, I use "DE" here. This will pick the german Channel Description. Legal values are: JP US DE FR ES IT NL

Question: Is anyone here who might want to host the script so that the Copy&Paste procedure is not necessary but one can download the file?

<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->#!/usr/bin/perl
use strict;
use warnings;

use Digest::MD5;
use Encode 'decode';
use Getopt::Long;
use Pod::Usage;

=head1 locdat

No POD yet

SYNOPSIS

decoding

locdat SD_card_location
ÂÂÂÂwill decode loc.dat from the default location and print to STDOUT

locdat SD_card_location -out filename
ÂÂÂÂwill decode loc.dat from the default location and store it in filename

encoding

locdat SD_card_location -e
ÂÂÂÂwill encode STDIN and store the resulting loc.dat in the default location

locdat SD_card_location -in filename [-e]
ÂÂÂÂwill encode filename's content to a new loc.dat at the default location

locdat -out another_loc.dat [-e]
ÂÂÂÂwill create a new loc.dat named "another_loc.dat" from STDIN

locdat -in filename -out another_loc.dat [-e]
ÂÂÂÂwill create a new loc.dat named "another_loc.dat" from filename's content

=cut

# Where is openssl located?
my $OPENSSL= '/usr/bin/openssl';

# Preferred language
my $lang= 'DE';

# Default loc.dat location relative to SD Card location
my $defaultloc= 'private/wii/loc.dat';

# Default title location relative to SD Card location
my $defaulttitle= 'private/wii/title';

# Magic
my $magic= 'sdal';

# These are the Wii's shared secrets
# Taken from http://hackmii.com/1208/04/keys-keys-keys/
my %keys=(
ÂÂÂÂ'md5-blanker' => "\x0e\x65\x37\x81\x99\xbe\x45\x17\xab\x06\xec\x22\x45\x1a\x57\x93",
ÂÂÂÂ'sd-iv'ÂÂÂÂÂÂ => "\x21\x67\x12\xe6\xaa\x1f\x68\x9f\x95\xc5\xa2\x23\x24\xdc\x6a\x98",
ÂÂÂÂ'sd-key'ÂÂÂÂÂÂ=> "\xab\x01\xb9\xd8\xe1\x62\x2b\x08\xaf\xba\xd8\x4d\xbf\xc2\xa5\x5d",
);

# VC info taken from http://wiibrew.org/wiki/Virtual_Console
my %vc_info=(
ÂÂÂÂC => 'Commodore 64',
ÂÂÂÂE => 'Neo-Geo',
ÂÂÂÂF => 'NES',
ÂÂÂÂH => 'Wii channels', # (Only for saved channels, not VC)
ÂÂÂÂJ => 'SNES',
ÂÂÂÂL => 'Master System',
ÂÂÂÂM => 'Genesis/Mega Drive',
ÂÂÂÂN => 'N64',
ÂÂÂÂP => 'TurboGrafx-16/PC Engine',
ÂÂÂÂQ => 'TurboGrafx-CD',
ÂÂÂÂR => 'Wii DVD', # (Only for savegames, not VC)'
ÂÂÂÂW => 'WiiWare',
);

# Region info taken from the same source
my %region_info=(
ÂÂÂÂE => 'USA',ÂÂÂÂ
ÂÂÂÂJ => 'Japan',ÂÂ
ÂÂÂÂP => 'Europe',ÂÂ# (and other PAL regions such as Australia)
ÂÂÂÂD => 'Germany', # (only if separate version)
ÂÂÂÂF => 'France',ÂÂ# (only if separate version)
ÂÂÂÂI => 'Italian', # (only if separate version)
ÂÂÂÂS => 'Spanish', # (only if separate version)
ÂÂÂÂA => 'All',ÂÂÂÂ # (?, only seen on channels)ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ
ÂÂÂÂL => 'Limited', # (region free games)ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ
ÂÂÂÂM => 'Import',ÂÂ# (confirmed for Japaness imports in Europe)
ÂÂÂÂN => 'Import',ÂÂ# (confirmed in Japeness imports in US)
);

# Localized Channelnames
# Information from http://wiibrew.org/wiki/Content.bin
my %lang_offset= (
ÂÂÂÂJP => 0x09C, # Japanse
ÂÂÂÂUS => 0x0F0, # English
ÂÂÂÂDE => 0x144, # German
ÂÂÂÂFR => 0x198, # French
ÂÂÂÂES => 0x1EC, # Spanish
ÂÂÂÂIT => 0x240, # Italian
ÂÂÂÂNL => 0x294, # Dutch
);
my @langs=(qw(JP US DE FR ES IT NL));
my $namesize= 42*2;
my $namebytes= $namesize * scalar @langs;
my $namepattern= "a$namesize" x scalar @langs;


# Commandline for encrypting
# "-out <filename>" will be appended
my @encrypt=(
ÂÂÂÂ$OPENSSL,
ÂÂÂÂ'enc',
ÂÂÂÂ'-aes-128-cbc',
ÂÂÂÂ'-K',ÂÂjoin('',
ÂÂÂÂÂÂÂÂunpack('H2' x length $keys{'sd-key'}, $keys{'sd-key'})),
ÂÂÂÂ'-iv', join('',
ÂÂÂÂÂÂÂÂunpack('H2' x length $keys{'sd-iv' }, $keys{'sd-iv' })),
);

# Commandline for decrypting
# "-in <filename>" will be appended
my @decrypt= (@encrypt, '-d');

my (
ÂÂÂÂ$encode,
ÂÂÂÂ$infile,
ÂÂÂÂ$outfile,
ÂÂÂÂ$verbose,
);
help() unless GetOptions(
ÂÂÂÂ'e|encode'ÂÂ => \$encode,
ÂÂÂÂ'in=s'ÂÂÂÂÂÂ => \$infile,
ÂÂÂÂ'out=s'ÂÂÂÂÂÂ=> \$outfile,
ÂÂÂÂ'h|help'ÂÂÂÂ => \&help,
ÂÂÂÂ'm|man'ÂÂÂÂÂÂ=> \&man,
ÂÂÂÂ'v'ÂÂÂÂÂÂÂÂÂÂ=> \$verbose,
);

sub help { pod2usage(-verbose=>1); exit; }
sub manÂÂ{ pod2usage(-verbose=>2); exit; }

# infile defined?
if ($infile) {
ÂÂÂÂif (not -r $infile) {
ÂÂÂÂÂÂÂÂdie "Can not find $infile!\n";
ÂÂÂÂ}
}

my $loc_dat;
# SD Card location defined?
my ($SD)= @ARGV;
if (not $SD) {
ÂÂÂÂ$encode=1;
ÂÂÂÂif ( not $outfile ) {
ÂÂÂÂÂÂÂÂdie "For encoding -out or SD Card location is mandatory.\n";
ÂÂÂÂ}
}
else {
ÂÂÂÂ$loc_dat= "$SD/$defaultloc";
ÂÂÂÂif ( ! -r $loc_dat ) {
ÂÂÂÂÂÂÂÂdie "No such file: $loc_dat.\n";
ÂÂÂÂ}
}

if ($encode) { # encoding
ÂÂÂÂmy $in;
ÂÂÂÂif ( $infile ) {
ÂÂÂÂÂÂÂÂopen $in, '<:utf8', $infile
ÂÂÂÂÂÂÂÂÂÂÂÂor die "Can not read $infile: $!\n";
ÂÂÂÂ}
ÂÂÂÂelse {
ÂÂÂÂÂÂÂÂopen $in, '<&', \*STDIN
ÂÂÂÂÂÂÂÂÂÂÂÂor die "Can not dup STDIN: $!\n";
ÂÂÂÂ}
ÂÂÂÂmy(@list)= ("\x00\x00\x00\x00") x 240;
ÂÂÂÂmy $i=0;
ÂÂÂÂwhile (<$in>) {
ÂÂÂÂÂÂÂÂif (/:\s*-+\s*$/) {
ÂÂÂÂÂÂÂÂÂÂÂÂ$i+=(12-$i%12)%12;
ÂÂÂÂÂÂÂÂÂÂÂÂnext;
ÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂnext unless /^(?:\s*\d+-\d-[A-DX])?\s*:\s*(?:\[([A-Z\d]{4})\])?/;
ÂÂÂÂÂÂÂÂif ($i > scalar @list) {
ÂÂÂÂÂÂÂÂÂÂÂÂdie "Too many entries ".($i+1).".\n";
ÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂ$list[$i]= $1 if $1;
ÂÂÂÂÂÂÂÂ++$i;
ÂÂÂÂ}
ÂÂÂÂclose $in;
ÂÂÂÂmy $padding= "\x00" x 12;
ÂÂÂÂmy $ctx= Digest::MD5->new;
ÂÂÂÂ$ctx->add($magic);
ÂÂÂÂ$ctx->add($keys{'md5-blanker'});
ÂÂÂÂ$ctx->add(@list);
ÂÂÂÂ$ctx->add($padding);
ÂÂÂÂmy $md5= $ctx->digest;
ÂÂÂÂif ( not $outfile ) {
ÂÂÂÂÂÂÂÂ$outfile= "$SD/$defaultloc";
ÂÂÂÂ}
ÂÂÂÂopen my $out, '|-', @encrypt, '-out', $outfile
ÂÂÂÂÂÂÂÂor die "Can't write to $outfile: $!\n";
ÂÂÂÂprint $out $magic, $md5, join('', @list), $padding;
ÂÂÂÂclose $out;
}
else { # decoding
ÂÂÂÂopen my $in, '-|', @decrypt, '-in', $loc_dat
ÂÂÂÂor die "Error decrypting '$loc_dat': $!\n";
ÂÂÂÂ{ÂÂÂÂlocal $/;
ÂÂÂÂÂÂÂÂ$_=<$in>;
ÂÂÂÂ};
ÂÂÂÂclose $in;
ÂÂÂÂ# Filestructur info taken from http://wiibrew.org/wiki/Loc.dat
ÂÂÂÂmy($magic, $md5, $list, $padding)= unpack('a4 H32 a960 a12', $_);
ÂÂÂÂmy @list= unpack "a4" x 240, $list;
ÂÂÂÂ
ÂÂÂÂ# Retrieve information from content.bin
ÂÂÂÂ# structure taken from http://wiibrew.org/wiki/Content.bin
ÂÂÂÂ
ÂÂÂÂ# supress openssl warnings. It complains
ÂÂÂÂ# because not all its data will be read.
ÂÂÂÂ# The close below appears too early for openssl, but
ÂÂÂÂ# there is no use in reading more data.
ÂÂÂÂopen my $olderr, '>&', \*STDERR;
ÂÂÂÂopen STDERR, '>/dev/null';
ÂÂÂÂmy @info;
ÂÂÂÂforeach my $le (@list) {
ÂÂÂÂÂÂÂÂ# cleanup of the id
ÂÂÂÂÂÂÂÂ(my $id= $le)=~ tr/\x00//d;
ÂÂÂÂÂÂÂÂpush (@info, { id => $id });
ÂÂÂÂÂÂÂÂnext unless $id;
ÂÂÂÂÂÂÂÂ
ÂÂÂÂÂÂÂÂ# There is an id. Read information from its file
ÂÂÂÂÂÂÂÂmy $info= $info[-1];
ÂÂÂÂÂÂÂÂmy $c_bin= "$SD/$defaulttitle/$id/content.bin";
ÂÂÂÂÂÂÂÂif (not -r $c_bin) {
ÂÂÂÂÂÂÂÂÂÂÂÂ# No content.bin for that id
ÂÂÂÂÂÂÂÂÂÂÂÂwarn "Can not read $id ($c_bin): $!\n";
ÂÂÂÂÂÂÂÂÂÂÂÂ$info->{'name'}= '*file missing*';
ÂÂÂÂÂÂÂÂÂÂÂÂnext;
ÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂprint $c_bin if $verbose;
ÂÂÂÂÂÂÂÂ# decode the file (part of it)
ÂÂÂÂÂÂÂÂopen my $in, '-|', @decrypt, '-in', $c_bin
ÂÂÂÂÂÂÂÂÂÂÂÂor die "error running openssl on $c_bin: $!\n";
ÂÂÂÂÂÂÂÂ# skip what we don't want to read
ÂÂÂÂÂÂÂÂread($in, $_, $lang_offset{$langs[0]});
ÂÂÂÂÂÂÂÂ# read the channel names in all languages
ÂÂÂÂÂÂÂÂread($in, $_, $namebytes);
ÂÂÂÂÂÂÂÂ# ignore the rest of the file
ÂÂÂÂÂÂÂÂ#{ local $/; <$in>; }
ÂÂÂÂÂÂÂÂclose $in;
ÂÂÂÂÂÂÂÂ
ÂÂÂÂÂÂÂÂ# unpack the names
ÂÂÂÂÂÂÂÂmy %titles;
ÂÂÂÂÂÂÂÂ@titles{@langs}= map {
ÂÂÂÂÂÂÂÂÂÂÂÂ# decode a name. utf16be might be wrong
ÂÂÂÂÂÂÂÂÂÂÂÂ# could also well be ucs2be
ÂÂÂÂÂÂÂÂÂÂÂÂ$_= decode('utf16be', $_);
ÂÂÂÂÂÂÂÂÂÂÂÂs/\x00+$//;
ÂÂÂÂÂÂÂÂÂÂÂÂtr/\x00/ /;
ÂÂÂÂÂÂÂÂÂÂÂÂ$_= undef if /^\s+$/;
ÂÂÂÂÂÂÂÂÂÂÂÂ$_;
ÂÂÂÂÂÂÂÂ} unpack $namepattern, $_;
ÂÂÂÂÂÂÂÂ$info->{'name'}= $titles{$lang} || $titles{'US'} || '* no title found *';
ÂÂÂÂÂÂÂÂ$info->{'RC'}= $region_info{substr($id,3,1)} || '?';
ÂÂÂÂÂÂÂÂ$info->{'VC'}= $vc_info{ÂÂÂÂsubstr($id,0,1)} || '?',
ÂÂÂÂ}
ÂÂÂÂopen STDERR, '>&', $olderr;
ÂÂÂÂ
ÂÂÂÂmy $out;
ÂÂÂÂif ( $outfile ) {
ÂÂÂÂÂÂÂÂopen $out, '>:utf8', $outfile
ÂÂÂÂÂÂÂÂÂÂÂÂor die "Can not write to $outfile: $!\n";
ÂÂÂÂ}
ÂÂÂÂelse {
ÂÂÂÂÂÂÂÂopen $out, '>&:utf8', \*STDOUT
ÂÂÂÂÂÂÂÂÂÂÂÂor die "Can not dup STDOUT: $!\n";
ÂÂÂÂ}
ÂÂÂÂ# Print loc.dat in readable form
ÂÂÂÂmy $i=0;
ÂÂÂÂ# Pages from 01..20
ÂÂÂÂfor my $p ('01'..'20') {
ÂÂÂÂÂÂÂÂ# rows from 1..3
ÂÂÂÂÂÂÂÂfor my $r (1..3) {
ÂÂÂÂÂÂÂÂÂÂÂÂ# columns from A..D
ÂÂÂÂÂÂÂÂÂÂÂÂfor my $c ('A'..'D') {
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ# Cell coordinates as PAGE-ROW-COLUMN
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂprint $out "$p-$r-$c:";
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂmy $info= $info[$i];
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ# Print info if we got any
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂif ( $info->{'id'} ) {
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂprintf $out " [%4s] %-42s %-7s %s",
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ@{ $info }{qw( id name RC VC )};
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂprint $out "\n";
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ++$i;
ÂÂÂÂÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂ}
ÂÂÂÂÂÂÂÂ# Print a page separator.
ÂÂÂÂÂÂÂÂ# Cell coordinates are 4-X so that sorting
ÂÂÂÂÂÂÂÂ# the lines will keep them in place
ÂÂÂÂÂÂÂÂprint $out "$p-4-X: ",'-' x 49 if $p<20;
ÂÂÂÂÂÂÂÂprint $out "\n";
ÂÂÂÂ}
ÂÂÂÂclose $out;
}<!--c2--></div><!--ec2-->
 

makinavaja

New Member
Newbie
Joined
Dec 14, 2010
Messages
1
Trophies
0
XP
24
Country
Thank you very much for this script. For me its really usefull having around 160 channels installed on my sd card.
The script has been fully tested and it works under linux (ubuntu)
smile.gif


Makinavaja
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    The Real Jdbye @ The Real Jdbye: @BigOnYa series S is the way to go, its a bargain for a capable system