1 /*---------------------------------------------------------------------------*
2 Project: Dolphin/Revolution GD library
3 File: GDFile.c
4
5 Copyright 2001-2006 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: GDFile.c,v $
14 Revision 1.3 02/20/2006 04:24:39 mitu
15 changed include path from dolphin/ to revolution/.
16
17 Revision 1.2 02/03/2006 08:54:48 hirose
18 Avoided use of EPPC and use WIN32.
19
20 Revision 1.1.1.1 2005/05/12 02:15:49 yasuh-to
21 transitioned from the Dolphin source tree
22
23
24 3 02/08/05 19:53 Hirose
25 Const type specifier support.
26
27 2 9/14/01 4:03p Carl
28 Fixed binary mode issue.
29 Rewrote host-side file reader to mirror target-side.
30
31 1 9/12/01 1:52p Carl
32 Initial revision of GD: Graphics Display List Library.
33
34 $NoKeywords: $
35 *---------------------------------------------------------------------------*/
36
37 #include <revolution/gd.h>
38
39 #ifndef WIN32
40 #include <revolution/os.h>
41 #include <revolution/dvd.h>
42
43 #else
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <sys/stat.h>
48 #include <assert.h>
49
50 #define ASSERT assert
51 #define OSRoundUp32B(x) (((u32)(x) + 31) & ~31)
52 #define OSAlloc(x) ((void*)OSRoundUp32B(malloc((x)+31)))
53 #define OSFree(x) free(x)
54
55 #endif
56
57 /*---------------------------------------------------------------------------*/
58
59 #ifdef WIN32
60
61 /*---------------------------------------------------------------------------*/
62 // Name: myFwrite, myFread...
63 //
64 // Description: Internal file access routines.
65 //
66 // Arguments: as shown
67 //
68 // Returns: 0 for no error
69 // -1 for write error
70 // -2 for read error
71 //
72 /*---------------------------------------------------------------------------*/
73
74 // Write a u32 in big-endian format
75
myFwrite_u32(FILE * fp,u32 data)76 static s32 myFwrite_u32( FILE *fp, u32 data )
77 {
78 u32 count;
79 u8 db[4];
80
81 db[0] = (u8)((data >> 24) & 0xff);
82 db[1] = (u8)((data >> 16) & 0xff);
83 db[2] = (u8)((data >> 8) & 0xff);
84 db[3] = (u8)((data >> 0) & 0xff);
85
86 count = fwrite( db, 1, 4, fp );
87
88 if (count != 4)
89 {
90 return -1;
91 } else {
92 return 0;
93 }
94 }
95
96 // Write a stream of bytes
97
myFwrite_u8s(FILE * fp,u8 * data,u32 length)98 static s32 myFwrite_u8s( FILE *fp, u8 *data, u32 length )
99 {
100 u32 count;
101
102 count = fwrite( data, 1, length, fp );
103
104 if (count != length)
105 {
106 return -1;
107 }
108 else
109 {
110 return 0;
111 }
112 }
113
114 // Read a u32 in big-endian format
115
myFread_u32(FILE * fp,u32 * data)116 static s32 myFread_u32( FILE *fp, u32 *data )
117 {
118 u32 count;
119 u8 db[4];
120
121 count = fread( db, 1, 4, fp );
122
123 *data = ((u32) db[0] << 24) | ((u32) db[1] << 16) |
124 ((u32) db[2] << 8) | ((u32) db[3] << 0);
125
126 if (count != 4)
127 {
128 return -2;
129 } else {
130 return 0;
131 }
132 }
133
134 // Read a stream of bytes
135
myFread_u8s(FILE * fp,u8 * data,u32 length)136 static s32 myFread_u8s( FILE *fp, u8 *data, u32 length )
137 {
138 u32 count;
139
140 count = fread( data, 1, length, fp );
141
142 if (count != length)
143 {
144 return -2;
145 } else {
146 return 0;
147 }
148 }
149
150 // File error-checking macro:
151 #define CHECKERR(err, fp) \
152 if (err) { \
153 fclose(fp); \
154 return err; \
155 }
156
157 /*---------------------------------------------------------------------------*/
158 // Name: GDWriteDLFile
159 //
160 // Description: This host-side routine is for writing a file containing
161 // multiple display lists and patch lists. Note that all
162 // numbers written out are written in big-endian format.
163 // This speeds up target-side reading of the file.
164 //
165 // Arguments: fName file name
166 // numDLs how many display lists to write
167 // numPLs how many patch lists to write
168 // DLDescArray array describing display lists to write
169 // PLDescArray array describing patch lists to write
170 //
171 // Returns: 0 no error
172 // -1 error writing file
173 // -3 error opening file
174 //
175 /*---------------------------------------------------------------------------*/
176
GDWriteDLFile(char * fName,u32 numDLs,u32 numPLs,GDGList * DLDescArray,GDGList * PLDescArray)177 s32 GDWriteDLFile(char *fName, u32 numDLs, u32 numPLs,
178 GDGList *DLDescArray, GDGList *PLDescArray)
179 {
180 FILE *fp;
181 s32 err;
182 u32 i;
183 u32 j;
184 u32 offset;
185 u32 padBytes;
186 u32 *patchList;
187 u32 plLength;
188
189 if ( (fp = fopen(fName, "wb")) == NULL )
190 {
191 // Cannot open file
192 return -3;
193 }
194
195 err = myFwrite_u32(fp, GDFileVersionNumber);
196 CHECKERR(err, fp);
197 err = myFwrite_u32(fp, numDLs);
198 CHECKERR(err, fp);
199 err = myFwrite_u32(fp, numPLs);
200
201 // The first offset points to the DLDescArray
202 offset = 20;
203 err = myFwrite_u32(fp, offset);
204 CHECKERR(err, fp);
205
206 // The second offset points to the PLDescArray
207 offset += numDLs * sizeof(GDGList);
208 err = myFwrite_u32(fp, offset);
209 CHECKERR(err, fp);
210
211 // Advance offset past the PLDescArray
212 offset += numPLs * sizeof(GDGList);
213
214 // Need to compute offset alignment to 32 bytes here.
215 // The actual padding is added after the tables themselves.
216 padBytes = OSRoundUp32B(offset) - offset;
217 offset += padBytes;
218
219 // write out the DL table
220 for(i=0; i<numDLs; i++)
221 {
222 err = myFwrite_u32( fp, offset );
223 CHECKERR(err, fp);
224 ASSERT((DLDescArray[i].byteLength & 31) == 0);
225 err = myFwrite_u32( fp, DLDescArray[i].byteLength );
226 CHECKERR(err, fp);
227 offset += DLDescArray[i].byteLength;
228 }
229
230 // write out the PL table
231 for(i=0; i<numPLs; i++)
232 {
233 err = myFwrite_u32( fp, offset );
234 CHECKERR(err, fp);
235 err = myFwrite_u32( fp, PLDescArray[i].byteLength );
236 CHECKERR(err, fp);
237 offset += PLDescArray[i].byteLength;
238 }
239
240 // Insert alignment padding bytes here
241 err = myFwrite_u8s( fp, "00000000000000000000000000000000", padBytes);
242 CHECKERR(err, fp);
243
244 for(i=0; i<numDLs; i++)
245 {
246 err = myFwrite_u8s(fp, DLDescArray[i].ptr, DLDescArray[i].byteLength);
247 CHECKERR(err, fp);
248 }
249
250 for(i=0; i<numPLs; i++)
251 {
252 patchList = (u32 *) PLDescArray[i].ptr;
253 plLength = PLDescArray[i].byteLength/sizeof(u32);
254
255 for(j=0; j<plLength; j++)
256 {
257 err = myFwrite_u32( fp, patchList[j] );
258 CHECKERR(err, fp);
259 }
260 }
261
262 fclose(fp);
263
264 return 0;
265 }
266
267 /*---------------------------------------------------------------------------*/
268 // Name: GDReadDLFile
269 //
270 // Description: This host-side routine is for reading a file containing
271 // multiple display lists and patch lists.
272 //
273 // Arguments: fName file name
274 // numDLs how many display lists were read
275 // numPLs how many patch lists were read
276 // DLDescArray array describing display lists read
277 // PLDescArray array describing patch lists read
278 //
279 // Returns: 0 no error
280 // -2 error reading file
281 // -3 error opening file
282 // -4 bad file version number
283 // -5 error allocating space for data
284 //
285 /*---------------------------------------------------------------------------*/
286
u32swap(u32 * num)287 static inline void u32swap(u32 *num)
288 {
289 u32 swap;
290 u8 *numb = (u8 *) num;
291
292 swap = ((u32) num[0] << 24) | ((u32) num[1] << 16) |
293 ((u32) num[2] << 8) | ((u32) num[3] << 0);
294
295 *num = swap;
296 }
297
GDReadDLFile(const char * fName,u32 * numDLs,u32 * numPLs,GDGList ** DLDescArray,GDGList ** PLDescArray)298 s32 GDReadDLFile(const char *fName, u32 *numDLs, u32 *numPLs,
299 GDGList **DLDescArray, GDGList **PLDescArray)
300 {
301 FILE *fp;
302 s32 err;
303 struct stat statbuf;
304 u32 length;
305 u32 i;
306 u8 *buf;
307 GDLFileHeader *hdr;
308
309 *numDLs = *numPLs = 0;
310 *DLDescArray = *PLDescArray = NULL;
311
312 if ((fp = fopen(fName, "rb")) == FALSE)
313 {
314 return -3;
315 }
316
317 // get file length
318 err = fstat(fileno(fp), &statbuf);
319 if (err)
320 {
321 fclose(fp);
322 return -2;
323 }
324 length = statbuf.st_size;
325
326 // allocate buffer
327 if( NULL == (buf = OSAlloc(OSRoundUp32B(length))) )
328 {
329 fclose(fp);
330 return -5;
331 }
332
333 // read file
334 err = myFread_u8s( fp, buf, length );
335 if (err)
336 {
337 fclose(fp);
338 OSFree(buf);
339 return -2;
340 }
341
342 fclose(fp);
343
344 hdr = (GDLFileHeader *) buf;
345
346 u32swap( &hdr->versionNumber );
347
348 if (hdr->versionNumber != GDFileVersionNumber)
349 {
350 OSFree(buf);
351 return -4;
352 }
353
354 u32swap( &hdr->numDLs );
355 *numDLs = hdr->numDLs;
356
357 u32swap( &hdr->numPLs );
358 *numPLs = hdr->numPLs;
359
360 u32swap( (u32*) &hdr->DLDescArray );
361 *DLDescArray = (GDGList *) ( (u32) hdr->DLDescArray + (u32) hdr );
362
363 u32swap( (u32*) &hdr->PLDescArray );
364 *PLDescArray = (GDGList *) ( (u32) hdr->PLDescArray + (u32) hdr );
365
366 // Convert offsets into pointers
367 for(i=0; i<*numDLs; i++)
368 {
369 u32swap( (u32*) &(*DLDescArray)[i].ptr );
370 (*DLDescArray)[i].ptr = (void*)((u32)(*DLDescArray)[i].ptr + (u32)hdr);
371
372 u32swap( &(*DLDescArray)[i].byteLength );
373 }
374
375 for(i=0; i<*numPLs; i++)
376 {
377 u32swap( (u32*) &(*PLDescArray)[i].ptr );
378 (*PLDescArray)[i].ptr = (void*)((u32)(*PLDescArray)[i].ptr + (u32)hdr);
379
380 u32swap( &(*PLDescArray)[i].byteLength );
381 }
382
383 return 0;
384 }
385
386
387 #else
388
389
390 /*---------------------------------------------------------------------------*/
391 // Name: GDReadDLFile
392 //
393 // Description: This target-side routine is for reading a file containing
394 // multiple display lists and patch lists.
395 //
396 // Arguments: fName file name
397 // numDLs how many display lists were read
398 // numPLs how many patch lists were read
399 // DLDescArray array describing display lists read
400 // PLDescArray array describing patch lists read
401 //
402 // Returns: 0 no error
403 // -2 error reading file
404 // -3 error opening file
405 // -4 bad file version number
406 // -5 error allocating space for data
407 //
408 /*---------------------------------------------------------------------------*/
409
GDReadDLFile(const char * fName,u32 * numDLs,u32 * numPLs,GDGList ** DLDescArray,GDGList ** PLDescArray)410 s32 GDReadDLFile(const char *fName, u32 *numDLs, u32 *numPLs,
411 GDGList **DLDescArray, GDGList **PLDescArray)
412 {
413 DVDFileInfo finfo;
414 u32 length;
415 u32 i;
416 u8 *buf;
417 GDLFileHeader *hdr;
418
419 *numDLs = *numPLs = 0;
420 *DLDescArray = *PLDescArray = NULL;
421
422 if (FALSE == DVDOpen(fName, &finfo))
423 {
424 OSReport("Can't open file %s\n", fName);
425 return -3;
426 }
427
428 length = DVDGetLength(&finfo);
429
430 if( NULL == (buf = OSAlloc(OSRoundUp32B(length))) )
431 {
432 OSReport("Alloc failed\n");
433 DVDClose(&finfo);
434 return -5;
435 }
436
437 if (OSRoundUp32B(length) !=
438 DVDRead(&finfo, buf, (s32)OSRoundUp32B(length), 0))
439 {
440 OSReport("Error occurred when reading %s\n", fName);
441 DVDClose(&finfo);
442 OSFree(buf);
443 return -2;
444 }
445
446 DVDClose(&finfo);
447
448 hdr = (GDLFileHeader *) buf;
449
450 if (hdr->versionNumber != GDFileVersionNumber)
451 {
452 OSReport("Bad version number for GDL file %s\n", fName);
453 OSFree(buf);
454 return -4;
455 }
456
457 *numDLs = hdr->numDLs;
458 *numPLs = hdr->numPLs;
459 *DLDescArray = (GDGList *) ( (u32) hdr->DLDescArray + (u32) hdr );
460 *PLDescArray = (GDGList *) ( (u32) hdr->PLDescArray + (u32) hdr );
461
462 // Convert offsets into pointers
463 for(i=0; i<*numDLs; i++)
464 {
465 (*DLDescArray)[i].ptr = (void*)((u32)(*DLDescArray)[i].ptr + (u32)hdr);
466 }
467
468 for(i=0; i<*numPLs; i++)
469 {
470 (*PLDescArray)[i].ptr = (void*)((u32)(*PLDescArray)[i].ptr + (u32)hdr);
471 }
472
473 return 0;
474 }
475
476 #endif
477