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