-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwud.cpp
157 lines (149 loc) · 4.7 KB
/
wud.cpp
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
148
149
150
151
152
153
154
155
156
157
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"wud.h"
long long wud_getFileSize64(FILE* file)
{
long long prevSeek = ftello(file);
fseeko(file, 0, SEEK_END);
long long fileSize = ftello(file);
fseeko(file, prevSeek, SEEK_SET);
return fileSize;
}
long long wud_getCurrentSeek64(FILE* file)
{
long long currentSeek = ftello(file);
return currentSeek;
}
void wud_setCurrentSeek64(FILE* file, long long newSeek)
{
fseeko(file, newSeek, SEEK_SET);
}
/*
* Open .wud (Wii U image) or .wux (Wii U compressed image) file
*/
wud_t* wud_open(char* path)
{
FILE* inputFile;
inputFile = fopen(path, "rb");
if( inputFile == NULL )
return NULL;
// allocate wud struct
wud_t* wud = (wud_t*)malloc(sizeof(wud_t));
memset(wud, 0x00, sizeof(wud_t));
wud->fileWud = inputFile;
// get size of file
long long inputFileSize = wud_getFileSize64(wud->fileWud);
// determine whether the WUD is compressed or not
wuxHeader_t wuxHeader = {0};
if( fread(&wuxHeader, sizeof(wuxHeader_t), 1, wud->fileWud) != 1 )
{
// file is too short to be either
wud_close(wud);
return NULL;
}
if( wuxHeader.magic0 == WUX_MAGIC_0 && wuxHeader.magic1 == WUX_MAGIC_1 )
{
// this is a compressed file
wud->isCompressed = true;
wud->sectorSize = wuxHeader.sectorSize;
wud->uncompressedSize = wuxHeader.uncompressedSize;
// validate header values
if( wud->sectorSize < 0x100 || wud->sectorSize >= 0x10000000 )
{
wud_close(wud);
return NULL;
}
// calculate offsets and sizes
wud->indexTableEntryCount = (unsigned int)((wud->uncompressedSize+(long long)(wud->sectorSize-1)) / (long long)wud->sectorSize);
wud->offsetIndexTable = wud_getCurrentSeek64(wud->fileWud);
wud->offsetSectorArray = (wud->offsetIndexTable + (long long)wud->indexTableEntryCount*sizeof(unsigned int));
// align to SECTOR_SIZE
wud->offsetSectorArray = (wud->offsetSectorArray + (long long)(wud->sectorSize-1));
wud->offsetSectorArray = wud->offsetSectorArray - (wud->offsetSectorArray%(long long)wud->sectorSize);
// read index table
unsigned int indexTableSize = sizeof(unsigned int) * wud->indexTableEntryCount;
wud->indexTable = (unsigned int*)malloc(sizeof(unsigned int) * wud->indexTableEntryCount);
wud_setCurrentSeek64(wud->fileWud, wud->offsetIndexTable);
if( fread(wud->indexTable, sizeof(unsigned int), wud->indexTableEntryCount, wud->fileWud) != wud->indexTableEntryCount )
{
// could not read index table
wud_close(wud);
return NULL;
}
}
else
{
// uncompressed file
wud->uncompressedSize = inputFileSize;
}
return wud;
}
/*
* Close wud/wux reader
*/
void wud_close(wud_t* wud)
{
fclose(wud->fileWud);
if( wud->indexTable )
free(wud->indexTable);
free(wud);
}
/*
* Read data
* Transparently handles WUX decompression
* Can read up to 4GB-1 at once
*/
unsigned int wud_readData(wud_t* wud, void* buffer, unsigned int length, long long offset)
{
// make sure there is no out-of-bounds read
long long fileBytesLeft = wud->uncompressedSize - offset;
if( fileBytesLeft <= 0 )
return 0;
if( fileBytesLeft < (long long)length )
length = (unsigned int)fileBytesLeft;
// read data
unsigned int readBytes = 0;
if( wud->isCompressed == false )
{
// uncompressed read is just a 1:1 copy
wud_setCurrentSeek64(wud->fileWud, offset);
readBytes = (unsigned int)fread(buffer, 1, length, wud->fileWud);
}
else
{
// compressed read must be handled on a per-sector level
while( length > 0 )
{
unsigned int sectorOffset = (unsigned int)(offset % (long long)wud->sectorSize);
unsigned int remainingSectorBytes = wud->sectorSize - sectorOffset;
unsigned int sectorIndex = (unsigned int)(offset / (long long)wud->sectorSize);
unsigned int bytesToRead = (remainingSectorBytes<length)?remainingSectorBytes:length; // read only up to the end of the current sector
// look up real sector index
sectorIndex = wud->indexTable[sectorIndex];
wud_setCurrentSeek64(wud->fileWud, wud->offsetSectorArray + (long long)sectorIndex*(long long)wud->sectorSize+(long long)sectorOffset);
readBytes += (unsigned int)fread(buffer, 1, bytesToRead, wud->fileWud);
// progress read offset, write pointer and decrease length
buffer = (void*)((char*)buffer + bytesToRead);
length -= bytesToRead;
offset += bytesToRead;
}
}
return readBytes;
}
/*
* Returns true if the file uses .wux compression, false otherwise
*/
bool wud_isWUXCompressed(wud_t* wud)
{
return wud->isCompressed;
}
/*
* Returns size of data in bytes
* For .wud: Size of raw file
* For .wux: Size of uncompressed data
*/
long long wud_getWUDSize(wud_t* wud)
{
return wud->uncompressedSize;
}