1 module zgrf.types;
2 
3 import zgrf.constants;
4 
5 /// Holds information that is present in all GRF files.
6 struct GRFHeader
7 {
8     /// "Master of Magic"
9     ubyte[15] signature;
10     /**
11      * Either [0x00, 0x01, 0x03, ..., 0x0C, 0x0D, 0x0E] => Use Mixcrypt
12      * or     [0x00, 0x00, 0x00, ..., 0x00, 0x00, 0x00] => Not encrypted
13      */
14     ubyte[15] encryption;
15     /// Offset of the filetable after the header: offset + GRFHeader.sizeof
16     uint filetableOffset;
17     /// Unknown
18     uint seed;
19     /// actual filecount = rawFilecount - seed - 7
20     uint rawFilecount;
21     /// actual filecount
22     uint filecount;
23     /// Version of the GRF. Either 0x102, 0x103 or 0x200.
24     uint grfVersion;
25 }
26 
27 /// Holds information about a single GRFFile
28 struct GRFFile
29 {
30     /// Compressed filesize using either zlib or lzma
31     uint compressed_size;
32     /// Same as above with extra padding for the DES algorithm
33     uint compressed_size_padded;
34     /// Uncompressed size
35     uint size;
36     /// Offset of the file after the file header
37     uint offset;
38     /// Hash of the filename
39     uint hash;
40     /// See zgrf.constants : FileFlags
41     FileFlags flags;
42     /// Offset in filetable
43     ulong offset_ft;
44     /// Filename
45     wstring name;
46     /// Raw filename
47     ubyte[] rawName;
48     /// Data content
49     ubyte[] data;
50     /// GRF where this file is saved in
51     GRF* grf;
52 }
53 
54 /// Hashmap of files
55 alias GRFFiletable = GRFFile[uint];
56 
57 /**
58  * Holds information about a GRF file.
59  *
60  * Examples:
61  * --------
62  * import zgrf.types;
63  *
64  * GRF grf = GRF("data.grf");
65  * --------
66  */
67 struct GRF
68 {
69     import std.stdio : File;
70 
71     /// Filehandle that is used to read any data from
72     File filehandle;
73     /// Filename of the GRF file
74     string filename;
75     /// Filesize of the GRF file
76     size_t filesize;
77     /// GRF Header. Will be filled once [zgrf.grf.readHeader] is called.
78     GRFHeader header;
79     /// Associative array of the files. Will be filled once [zgrf.grf.readFiletable] is called.
80     GRFFiletable files;
81 
82     /**
83      * Opens the filehandle and stores the filesize
84      *
85      * Params:
86      *  name = Filename of the GRF
87      */
88     this(string name)
89     {
90         filename = name;
91         filehandle = File(filename, "rb");
92         import core.stdc.stdio : SEEK_SET, SEEK_END;
93 
94         filehandle.seek(0, SEEK_END);
95         filesize = filehandle.tell();
96         filehandle.seek(0, SEEK_SET);
97     }
98 }
99 
100 /**
101  * Holds information about multiple GRF.
102  * Use this struct if you wish to open multiple GRF files
103  * but retain a single GRF. Essentially merging the two GRF
104  * files.
105  *
106  * Examples:
107  * -----------
108  * import zgrf.types;
109  *
110  * // rdata.grf is loaded first and any files that are not in rdata.grf
111  * // are loaded from data.grf
112  * VirtualGRF grf = VirtualGRF(["rdata.grf", "data.grf"]);
113  * ----------
114  */
115 struct VirtualGRF
116 {
117     /// The GRFs in this VirtualGRF
118     GRF[] grfs;
119     /// The merged filetable from the GRFs
120     GRFFiletable files;
121 
122     /// See [GRF]
123     this(string[] filenames)
124     {
125         foreach(filename; filenames)
126         {
127             grfs ~= GRF(filename);
128         }
129     }
130 }