-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfile.c
147 lines (135 loc) · 3.36 KB
/
file.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <nusys.h>
#include <string.h>
#include <malloc.h>
#include "file.h"
#include "hash.h"
#define READ_BUF_SIZE 1024
#define LZ_WINDOW_SIZE 1024
#define LZ_WINDOW_START 958
#define LZ_MIN_MATCH_LEN 3
struct decode {
u16 read_pos;
u32 src;
u8 *dst;
u32 len;
};
typedef struct file_entry {
u32 name_hash;
u32 offset;
u32 size;
u32 compress_type;
} FileEntry;
extern u8 _file_packSegmentRomStart[];
static u32 num_files __attribute__((aligned(8))); //Must be 8-Byte Aligned to Read from ROM
static u32 file_pack_base;
static FileEntry *file_entries;
void FilePackInit()
{
file_pack_base = (u32)_file_packSegmentRomStart;
nuPiReadRom(file_pack_base, &num_files, sizeof(u32));
file_entries = malloc(num_files*sizeof(FileEntry));
nuPiReadRom(file_pack_base+sizeof(u32), file_entries, num_files*sizeof(FileEntry));
}
static int GetHashFileIdx(u32 hash)
{
int i;
for(i=0; i<num_files; i++) {
if(file_entries[i].name_hash == hash) {
return i;
}
}
//Return Sentiel Value for Not Found Hashes
return -1;
}
static void DecodeRaw(struct decode *decode)
{
u32 read_size;
while(decode->len) {
if(decode->len < READ_BUF_SIZE) {
//Fewer than 1024 bytes left
read_size = (decode->len+1)&0xFFFFFFFE;
decode->len = 0;
} else {
//At least 1024 bytes left
read_size = READ_BUF_SIZE;
decode->len -= READ_BUF_SIZE;
}
nuPiReadRom(decode->src, decode->dst, read_size);
//Advance to Next Read
decode->src += read_size;
decode->dst += read_size;
}
}
static u8 GetLZByte(struct decode *decode)
{
static u8 read_buf[READ_BUF_SIZE]; //Static to Retain Value between Calls
if(decode->read_pos == READ_BUF_SIZE) {
//Load Next Chunk to Read Buffer
nuPiReadRom(decode->src, &read_buf, READ_BUF_SIZE);
decode->src += READ_BUF_SIZE;
decode->read_pos = 0;
}
return read_buf[decode->read_pos++];
}
static void DecodeLZ(struct decode *decode)
{
u8 window[LZ_WINDOW_SIZE];
int window_ofs = LZ_WINDOW_START;
u16 flag = 0;
memset(window, 0, LZ_WINDOW_SIZE);
while (decode->len) {
flag >>= 1;
if (!(flag & 0x100)) {
flag = 0xFF00 | GetLZByte(decode);
}
if (flag & 0x1) {
window[window_ofs++] = *decode->dst++ = GetLZByte(decode);
window_ofs %= LZ_WINDOW_SIZE;
decode->len--;
} else {
int i;
u8 byte1 = GetLZByte(decode);
u8 byte2 = GetLZByte(decode);
int ofs = ((byte2 & 0xC0) << 2) | byte1;
int copy_len = (byte2 & 0x3F) + LZ_MIN_MATCH_LEN;
for (i = 0; i < copy_len; i++) {
window[window_ofs++] = *decode->dst++ = window[(ofs+i)%LZ_WINDOW_SIZE];
window_ofs %= LZ_WINDOW_SIZE;
}
decode->len -= i;
}
}
}
void *FileRead(const char *name)
{
int file_idx;
//Remove Initial Slashes
if(name[0] == '\\') {
name++;
}
file_idx = GetHashFileIdx(HashGetPath(name));
if(file_idx != -1) {
//Load File
struct decode decode;
int raw_len = (file_entries[file_idx].size+1) & 0xFFFFFFFE;
void *dst = malloc(raw_len);
decode.read_pos = READ_BUF_SIZE;
decode.src = file_pack_base+file_entries[file_idx].offset;
decode.dst = dst;
decode.len = raw_len;
if(file_entries[file_idx].compress_type) {
DecodeLZ(&decode);
} else {
DecodeRaw(&decode);
}
return dst;
} else {
return NULL;
}
}
void FileFree(void *ptr)
{
if(ptr) {
free(ptr);
}
}