Files Delphi

Title: Delving into the formats of files - MARC, Microsoft's MSNe Archive Format
Question: Ever wondered how to figure out the format of a file? This little example show's you how I cracked MSN Explorer's archive file format...
Answer:
Ever wondered how to figure out the format of a file? This little example show's you how I cracked MSN Explorer's archive file format...
After seeing MSN Explorer on the news I decided to download it and liked it's
jazzy interface and graphics. But a question lingered in my mind, where were
these graphics stored.
Being a programmer I naturally picked up a resource hacker and began to scour
through MSN Explorer's program files, but none of them contained the graphics
I saw in the interface, so I began to look at the *.mar files.
At first it all looked like mumbo jumbo data, but I noticed some familiar
data like the GIF89a marker which donates the beginning of a GIF file and
also plain HTML code, so I looked to the top of the file to see if there was
a tree or some sort of file directory structure to work on, and there was.
Below is the description of the format so far, and is the first I know of
to be released by anyone.
I've also included some Borland Delphi (PASCAL) code to show you how to
traverse the file.
I'll be using ui.mar in this description, as it comes with MSN Explorer and
is located in the MSNCoreFiles folder.
1. Header
The *.mar header is a simple twelve byte header, that contains the file
signiture, MARC, also what I beleive to be the version and the number of files
the archive holds.
UI.MAR Header Hex Dump
-------------------------------------------------------------------------
00000000 4D 41 52 43 03 00 00 00 F4 00 00 00 MARC........
Header Format
-------------------------------------------------------------------------
Length Type Description UI.MAR
-------------------------------------------------------------------------
4 Bytes CHAR MARC File Signature MARC
4 Bytes LONG MARC File Version? 3
4 Bytes LONG Number of files 224
-------------------------------------------------------------------------
12 Bytes Total
2. File Directory
Following straight on from the header is the table of the files
contained within the header.
This table contains the file name, offset and size, though not in that order.
UI.MAR File Table Hex Dump (First three files)
-------------------------------------------------------------------------
00000012 61 64 73 70 61 63 65 2E 68 74 6D 00 00 00 00 00 adspace.htm.....
00000028 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000044 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060 00 00 00 00 00 00 00 00 29 03 00 00 34 B4 F1 FF ........)...4...
00000076 DC 40 00 00 63 6F 6F 6B 69 65 69 6E 66 6F 2E 68 .@..cookieinfo.h
00000092 74 6D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 tm..............
00000108 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000124 00 00 00 00 00 00 00 00 00 00 00 00 37 08 00 00 ............7...
00000140 91 52 FA 4A 05 44 00 00 66 61 76 6F 72 69 74 65 .R.J.D..favorite
00000156 73 2F 66 61 76 6F 72 69 74 65 73 2D 64 69 61 6C s/favorites-dial
00000172 6F 67 2E 68 74 6D 00 00 00 00 00 00 00 00 00 00 og.htm..........
00000188 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000204 BB 09 00 00 6A 9F B9 3B 62 4D 00 00 ....j..;bM..
Table Format
-------------------------------------------------------------------------
Length Type Description UI.MAR
-------------------------------------------------------------------------
56 Bytes CHAR Filename of the File adspace.htm
4 Bytes LONG Size of the File Data 809
4 Bytes LONG (unknown) ????
4 Bytes LONG Offset of the File Data 16604
-------------------------------------------------------------------------
68 Bytes Total
The (unknown) data I beleive is a checksum, however I could not figure out
how to generate this using all the methods I have including CRC (16 & 32),
Adler, Kermit and a few others. If you find a way please let me know so I
can ammend this specification.
And thats basically it, except for the raw data...
3. Example Code (Borland Delphi)
Below is a simple unit you can copy and create to let you navigate the
files, it is only a reader and does not write MARC files.
MARC.PAS
-------------------------------------------------------------------------
unit MARC;
{***********************************************************}
{ }
{ Microsoft Archive (MARC) }
{ }
{ File Format is Copyright 2000 Microsoft Corp. }
{ This code is Copyright 2000 Lloyd Kinsella. }
{ }
{ E - Mai: lloydk@workshell.co.uk }
{ }
{***********************************************************}
{ }
{ Developer Notes: }
{ }
{ At present this unit will only allow you to "read" the }
{ *.mar files due to an "unknown" peice of data required }
{ in order to write a true MARC file. }
{ }
{***********************************************************}
interface
uses Windows, SysUtils, Classes;
type
TMARCHeaderStruct = record
Signature: array [1..4] of Byte;
Version: LongInt;
FileCount: LongInt;
end;
type
TMARCFileStruct = record
Filename: array [1..56] of Char;
Size: LongInt;
Unknown: LongInt;
Offset: LongInt;
end;
type
TMARC = class(TObject)
private
FFilename: String;
FVersion: LongInt;
procedure LoadFromFile(Filename: String);
public
Files: TList;
constructor Create(Filename: String);
destructor Destroy; override;
property Filename: String read FFilename;
property Version: LongInt read FVersion;
end;
type
TMARCFile = class
private
FFilename: String;
FSize: LongInt;
FUnknown: LongInt;
FOffset: LongInt;
public
Data: TMemoryStream;
constructor Create(FileInfo: TMARCFileStruct);
destructor Destroy; override;
procedure SaveToFile(Filename: String);
property Filename: String read FFilename;
property Size: LongInt read FSize;
property Unknown: LongInt read FUnknown;
property Offset: LongInt read FOffset;
end;
implementation
constructor TMARC.Create(Filename: String);
begin
inherited Create;
FFilename := '';
FVersion := 0;
Files := TList.Create;
LoadFromFile(Filename);
end;
destructor TMARC.Destroy;
begin
Files.Free;
inherited Destroy;
end;
procedure TMARC.LoadFromFile(Filename: String);
var
F: TFileStream;
Header: TMARCHeaderStruct;
I: Integer;
FileInfo: TMARCFileStruct;
MarcFile: TMARCFile;
CurrentPos: LongInt;
begin
F := TFileStream.Create(Filename,fmOpenRead or fmShareDenyWrite);
F.Read(Header,SizeOf(TMARCHeaderStruct));
FFilename := Filename;
FVersion := Header.Version;
for I := 1 to Header.FileCount do
begin
F.Read(FileInfo,SizeOf(TMARCFileStruct));
MarcFile := TMARCFile.Create(FileInfo);
CurrentPos := F.Position;
F.Seek(FileInfo.Offset,soFromBeginning);
MarcFile.Data.CopyFrom(F,FileInfo.Size);
MarcFile.Data.Seek(0,soFromBeginning);
F.Seek(CurrentPos,soFromBeginning);
Files.Add(MarcFile);
end;
F.Free;
end;
constructor TMARCFile.Create(FileInfo: TMARCFileStruct);
begin
inherited Create;
FFilename := FileInfo.Filename;
FSize := FileInfo.Size;
FUnknown := FileInfo.Unknown;
FOffset := FileInfo.Offset;
Data := TMemoryStream.Create;
end;
destructor TMARCFile.Destroy;
begin
Data.Free;
inherited Destroy;
end;
procedure TMARCFile.SaveToFile(Filename: String);
var
CurrentPos: LongInt;
F: TFileStream;
begin
CurrentPos := Data.Position;
Data.Seek(0,soFromBeginning);
F := TFileStream.Create(Filename,fmCreate);
F.CopyFrom(Data,0);
F.Free;
Data.Seek(CurrentPos,soFromBeginning);
end;
end.
-------------------------------------------------------------------------------
I've made a career of file format hacking along with others, and I've set up www.fileformats.org to listt details on as many file formats I can, from BMP to MP3!