Magic-League.com Forum Index Magic-League.com
Forums of Magic-League: Free Online Magic: the Gathering Play with Apprentice and Magic Workstation; casual or tournament play.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Decrypt cardinfo.dat?



 
Reply to topic    Magic-League.com Forum Index -> Apprentice
Author Message
Siberys



Joined: 31 Mar 2008
Posts: 4

PostPosted: Tue Apr 01, 2008 6:38 pm    Post subject: Decrypt cardinfo.dat? Reply with quote

Does anyone know a way to decrypt the cardinfo.dat file, so I can read it in plain text?

Thanks!
Back to top
Gredunza



Joined: 04 Apr 2008
Posts: 3

PostPosted: Fri Apr 04, 2008 8:23 am    Post subject: Reply with quote

I would also dearly love to know this one.

I've read this thread, which contained very little relevant information, aside from a redirection to MakeAppr.
Now, I don't know C/C++, so it helped me very little in discovering the structure of the thing and when I tried to actually use the program, it threw an exception and died on load.

I do, however, know Perl (you may gasp with disgust). And if there's anything Perl can do is process text.
So, I've spent the better part of the afternoon trying to reverse engineer the thing and I did come up with some information.

What I do know, and take it with much skepticism:
There are two concatenated blocks, with no line separators (that's right. NONE), a "Card Info" block, which basically operates like so, per record:
1. A character which I think stands for card color. This is usually a control character in the C0 (\x01-\x1F) range, but not always.
2. The NUL (\x00) character.
3. The card type text.
4. NUL or, if available, the STX (\x02) and NUL characters, followed by the Casting cost.
5. NUL or, if available, the ETX (\x03) and NUL characters, followed by power/toughness in N/M format.
6. A character I've yet to understand.
7. The NUL character.
8. Card text, separated by newlines (\n) (Oh, the twisted web you've weaved).
9. The DC4 (\x14) character and NUL characters.
10. Flavour text (Nowadays "www.Magic-League.com") (which makes an excellent line separator for this block).

It's fairly obvious the NUL char is the tokenizer. But that's all I'm certain in.
While I do get it, I'm not sure how to process it without record delimiters. Probably just regex it, as it seems the most sensible thing to do.

Now, all this is followed by the "Card name / editions" block. Which operates similarly, but I've yet to completely perceive its resonance.

Obviously, people are still adding sets to the file, so if anyone cares to post the full specification, that would extremely nice.
Back to top
Gredunza



Joined: 04 Apr 2008
Posts: 3

PostPosted: Sat Apr 05, 2008 12:24 am    Post subject: Reply with quote

Man, was I naive....
After much trial and error, this is the regex I came up with:
Code:
/(.)\x00(.+?)[\x01-\x1F]?\x00([0-9A-Z\/\s{}]+?)?[\x00-\x07]?\x00([0-9X?*\-+]+?\s*\/+\s*[0-9X?*\-+]+|\x00)?(.)[\x00-\x07](.*?|\x00)?[\x18\x14]\x00(.*?(?=.\x00))/isg

Don't worry, it doesn't bite. Well, nothing vital, anyway.

Like most Regular Expressions, it's a bit... Write Once, Read Never..
But I'll try to expand:
1. Card type identifier (any single character).
2. The NUL character (\x00).
3. Card type text (any characters).
4. Optionally, a control character in the C0 (\x01-\x1F) range (I opted for generalizing).
5. The NUL character.
6. Optionally, casting cost (any alphanumerical, '/', '{', '}' or space characters)
7. Optionally, a control character in the \x00-\x07 range.
8. The NUL character.
9. Optionally, the NUL character or, if available, power / toughness (any numerical, 'X', '*', '-', '+' or '?' characters, followed by any optional space, at least one '/' character, and a repetition of the first part).
10. An unknown character (any single character).
11. A control character in the \x00-\x07 range.
12. Optionally, the NUL character, or, if available, card text (any characters).
13. Either the DC4 (\x14) or CAN (\x18) control character.
14. The NUL character.
15. Optionally, flavour text (any characters, positioned by the next record's first two characters (steps 1 and 2)).

The backreferences yield:
$1 = Card type identifier.
$2 = Card type text.
$3 = Casting cost.
$4 = Power / Toughness.
$5 = The weird character.
$6 = Card text.
$7 = Flavour text.

I'm sure there's a million ways to optimize it, but it does work.

Full Perl code:

Code:
#!/usr/bin/perl -w
use strict;
local $/ = undef;
local $_ = <>;
s/^.{3}\x00//; # Chop off first 4 characters of the file.
while (/(.)\x00(.+?)[\x01-\x1F]?\x00([0-9A-Z\/\s{}]+?)?[\x00-\x07]?\x00([0-9X?*\-+]+?\s*\/+\s*[0-9X?*\-+]+|\x00)?(.)[\x00-\x07](.*?|\x00)?[\x18\x14]\x00(.*?(?=.\x00))/isg) {
   print "\$1 = card color identifier: $1\n" if defined $1;
   print "\$2 = card type text: $2\n" if defined $2;
   print "\$3 = Casting Cost: $3\n" if defined $3;
   print "\$4 = Power / Toughness: $4\n" if defined $4;
   print "\$5 = Unknown Character: $5\n" if defined $5;
   print "\$6 = Card Text: $6\n" if defined $6;
   print "\$7 = Flavour Text: $7\n" if defined $7;
   print "\n";
}
Back to top
Siberys



Joined: 31 Mar 2008
Posts: 4

PostPosted: Sat Apr 05, 2008 9:22 am    Post subject: Reply with quote

You'll have to excuse my ignorance, but I'm not exactly what you'd call proficient in perl; How can I run that program?

Thanks
Back to top
Gredunza



Joined: 04 Apr 2008
Posts: 3

PostPosted: Mon Apr 07, 2008 8:45 am    Post subject: Reply with quote

You shouldn't run that program yet. It's partial and incomplete.
If you are interested in Perl, however, or would like to get even this partial information, you'll need to install Perl.

If you're using Linux, I suspect you have, at least, Perl 5.8 or you know how to install either 5.8 or 5.10.

If you're on Windows, you can install ActivePerl or Strawberry Perl (the only Perl with a giant strawberry!). Both are free, of course.
Once you're done with that, it should be as simple as saving all that code in a file, say 'cardinfo.pl', opening cmd, going to your Apprentice\Sets\ directory and typing "perl P:\ath\to\cardinfo.pl cardinfo.dat > cardinfo.txt"

Now, I'm working with a friend on writing up the whole specification for the file.

Which, with all due respect, is one of the worst and strangest databasing schemes I've ever seen. A CSV would've been better.

The first block can realistically be parsed with a Regular Expression, but it's potentially incorrect and, IMHO, just ugly as it would require quite a bit of hard coding. I try not to hard code.
This is because the first block, containing card type, casting cost, P/T, card text and flavour text is one continuous stream of characters.
I earlier said that there are no record delimiters, this was only partly correct, as there are no delimiters at all.
It's a bit confusing, but, basically, it has the length of a field, followed by the field text, but neither is a constant.
The second block is far more civilized, with each record ending in two NULs.
Anyhoo, we hope to have this straightened up soon.
Back to top
Siberys



Joined: 31 Mar 2008
Posts: 4

PostPosted: Tue Apr 08, 2008 4:07 pm    Post subject: Reply with quote

Thanks! Good luck on the project - you don't know how useful it'll be to me.

Siberys
Back to top
Brefin



Joined: 31 Oct 2007
Posts: 18

PostPosted: Wed Apr 09, 2008 7:16 pm    Post subject: Reply with quote

Since you seem to have an interest in Perl and such. I thought I'd pass on something helpful.

Attached is a rough script for reading cardinfo.dat. The script works, but as you can see I was lame in giving the script the file to work with.

I used what I learned in making this script to adapt a gatherer reading script to output cardinfo.dat. A key thing is to treat cardinfo.dat as a binary file and use perl's packing routines to convert the values as needed to read and write the file.

Code:
#!/usr/bin/perl
use warnings;

#my $file = "/Volumes/Nefarious/Source/mindless-1.6/cardinfo.dat";
#my $file = "/Users/brefin/Documents/Card Games/Magic- The Gathering/MTG Card Sets/cardinfo.dat";
#my $file = "/Users/brefin/Documents/Scratch/lorwyn_appr/Sets/cardinfo.dat";
#my $file = "/Users/brefin/Documents/Scratch/jtp_lorwyn_appr/Sets/cardinfo.dat";
my $file = "/Users/brefin/Documents/Scratch/Morningtide patch/Sets/cardinfo.dat";

open(CARDINFO, "<$file") || die "Failed to open file\n";
binmode CARDINFO;

my ($offset, $card_count);
# Get offset
$offset = read_dword(CARDINFO);
print "Offset for card headers: $offset\n";

# Get card count
seek CARDINFO, $offset, 0;
$card_count = read_dword(CARDINFO);
print "Card count: $card_count\n";

for (1..$card_count)
{
   my $card = read_card(CARDINFO);
   print "Card: $card->{NAME}, $card->{SETS}, $card->{COLOR}, $card->{TYPE}, $card->{COST}, $card->{POWER}, $card->{TEXT}, $card->{FLAVOR}\n";
#   if($card->{NAME} eq "Forest") { last; }
};

close(CARDINFO);

sub read_card
{
   my $file = shift;
   my $card = read_card_header($file);
   my $cur_loc = tell $file;
   
   seek $file, $card->{OFFSET}, 0;
   read_card_body($file, $card);
   seek $file, $cur_loc, 0;
   return $card;
}

sub read_card_header
{
   my $file = shift;
   my $header = {};
   

   $header->{NAME} = read_string($file);
   $header->{OFFSET} = read_dword($file);
   $header->{COLOR} = read_byte($file);
   $header->{SETS} = read_string($file);
   $header->{WTF} = read_word($file);
   
   return $header;   
}

sub read_card_body
{
   my $file = shift;
   my $card = shift;
   
   $card->{TYPE} = read_string($file);
   $card->{COST} = read_string($file);
   $card->{POWER} = read_string($file);
   $card->{TEXT} = read_string($file);
   $card->{FLAVOR} = read_string($file);
}

# File stubs
sub read_string
{
   my $file = shift;
   my ($string);
   read $file, $string, read_word($file);
   
   return $string;
}

sub read_byte
{
   my $file = shift;
   my $val;
   read $file, $val, 1;
   return unpack("C", $val);
}

sub read_word
{
   my $file = shift;
   my $val;
   read $file, $val, 2;
   return unpack("v", $val);
}

sub read_dword
{
   my $file = shift;
   my $val;
   read $file, $val, 4;
   return unpack("V", $val);
}
Back to top
Brefin



Joined: 31 Oct 2007
Posts: 18

PostPosted: Wed Apr 09, 2008 7:48 pm    Post subject: Reply with quote

I see... the original reference I used has been removed from the web. But I located the page in the wayback machine: http://web.archive.org/web/20050503155724/http://www.digitalsquirrel.com/warlord/appr2txt.html

The database format isn't dumb, just the binary output for a language that speaks more of binary structures in memory. I've seen worse, for instance, outputting game data as straight memory dumps of what's in memory. Talk about hard to move between platforms, but it loads plenty fast on its original platform without extra work.

Edited: Fixed broken URL. Always remember to preview!
Back to top
Display posts from previous:   
Reply to topic    Magic-League.com Forum Index -> Apprentice All times are GMT - 7 Hours
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
Magic: the Gathering Cards

All content on this page may not be reproduced without consent of Magic-League Directors.
Magic the Gathering is TM and copyright Wizards of the Coast, Inc, a subsidiary of Hasbro, Inc. All rights reserved.


About Us | Contact Us | Privacy Policy