-
Notifications
You must be signed in to change notification settings - Fork 143
/
unpack-pbp.c
211 lines (174 loc) · 5.15 KB
/
unpack-pbp.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
# _____ ___ ____ ___ ____
# ____| | ____| | | |____| https://github.com/pspdev
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
#-----------------------------------------------------------------------
# (c) 2005 Naomi Peori <[email protected]>
# Licenced under Academic Free License version 2.0
# Review pspsdk README & LICENSE files for further details.
#
# 2006-12-26 - Andrew Whatson <[email protected]>
# - rewrote for easier reading
# - gave "correct" names to UNKNOWN.* files
# - improved memory efficiency with large PBPs
# - no longer outputs empty files
#
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef WORDS_BIGENDIAN
// Swap the bytes of an int for big-endian machines
static int swap_int(int n)
{
return ((n >> 24) & 0xff) | ((n >> 8) & 0xff00) | ((n << 8) & 0xff0000) | ((n << 24) & 0xff000000);
}
#endif
// Struct to describe the header of a PBP file
typedef struct {
char signature[4];
int version;
int offset[8];
} HEADER;
// Correct PBP signature
char correct_sig[4] = {
0x00,
0x50, // P
0x42, // B
0x50 // P
};
// Names of files included in a PBP
char *filename[8] = {
"PARAM.SFO",
"ICON0.PNG",
"ICON1.PMF",
"PIC0.PNG",
"PIC1.PNG",
"SND0.AT3",
"DATA.PSP",
"DATA.PSAR"
};
// Maximum size of read buffer
int maxbuffer = 16 * 1024 * 1024;
int main(int argc, char *argv[]) {
FILE *infile;
FILE *outfile;
HEADER header;
int loop0;
int total_size;
// Check for the correct number of arguments
if (argc != 2) {
printf("USAGE: %s <filename>\n", argv[0]);
return -1;
}
// Open the specified PBP
infile = fopen(argv[1], "rb");
if (infile == NULL) {
printf("ERROR: Could not open the input file. (%s)\n", argv[1]);
return -1;
}
// Get the size of the PBP
fseek(infile, 0, SEEK_END);
total_size = ftell(infile);
fseek(infile, 0, SEEK_SET);
if (total_size < 0) {
printf("ERROR: Could not get the input file size.\n");
fclose(infile);
return -1;
}
// Read in the header
size_t result = fread(&header, sizeof(HEADER), 1, infile);
if (result < 0) {
printf("ERROR: Could not read the input file header.\n");
fclose(infile);
return -1;
}
// Check the signature
for (loop0 = 0; loop0 < sizeof(correct_sig); loop0++) {
if (header.signature[loop0] != correct_sig[loop0]) {
printf("ERROR: Input file is not a PBP file.\n");
return -1;
}
}
#ifdef WORDS_BIGENDIAN
// Swap the bytes of the offsets for big-endian machines
for (loop0 = 0; loop0 < 8; loop0++) {
header.offset[loop0] = swap_int(header.offset[loop0]);
}
#endif
// For each file in the PBP
for (loop0 = 0; loop0 < 8; loop0++) {
void *buffer;
int size;
// Get the size of this file
if (loop0 == 7) {
size = total_size - header.offset[loop0];
} else {
size = header.offset[loop0 + 1] - header.offset[loop0];
}
// Print out the file details
printf("[%d] %10d bytes | %s\n", loop0, size, filename[loop0]);
// Skip the file if empty
if (!size) continue;
// Seek to the proper position in the file
if (fseek(infile, header.offset[loop0], SEEK_SET) != 0) {
printf("ERROR: Could not seek in the input file.\n");
return -1;
}
// Open the output file
outfile = fopen(filename[loop0], "wb");
if (outfile == NULL) {
printf("ERROR: Could not open the output file. (%s)\n", filename[loop0]);
return -1;
}
// Create the read buffer
buffer = malloc(maxbuffer);
if (buffer == NULL) {
printf("ERROR: Could not allocate the section data buffer. (%d)\n", maxbuffer);
return -1;
}
do {
int readsize;
// Make sure we don't exceed the maximum buffer size
if (size > maxbuffer) {
readsize = maxbuffer;
} else {
readsize = size;
}
size -= readsize;
// Read in the data from the PBP
size_t result = fread(buffer, readsize, 1, infile);
if (result < 0) {
printf("ERROR: Could not read in the section data.\n");
free(buffer);
return -1;
}
// Write the contents of the buffer to the output file
if (fwrite(buffer, readsize, 1, outfile) < 0) {
printf("ERROR: Could not write out the section data.\n");
free(buffer);
return -1;
}
// Repeat if we haven't finished writing the file
} while (size);
// Clean up the buffer
free(buffer);
// Close the output file
if (fclose(outfile) < 0) {
printf("ERROR: Could not close the output file.\n");
return -1;
}
}
// Close the PBP
if (fclose(infile) < 0) {
printf("ERROR: Could not close the input file.\n");
return -1;
}
// Exit successful
return 0;
}