1 /*---------------------------------------------------------------------------*
2   Project:  NitroSDK - WFS - libraries
3   File:     wfs_format.c
4 
5   Copyright 2007-2008 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  *---------------------------------------------------------------------------*/
14 
15 
16 #include <nitro/wfs/format.h>
17 
18 
19 /*---------------------------------------------------------------------------*/
20 /* Functions */
21 
22 /*---------------------------------------------------------------------------*
23   Name:         WFS_LoadTable
24 
25   Description:  Reads the NTR binary FAT from the device.
26 
27   Arguments:    archive: The WFSTableFormat structure to initialize
28                 allocator: The allocator used to internally allocate memory
29                 device: The device storing the target FAT.
30                 origin_a: The device-internal offset for the ROM loading the source FAT.
31                 origin_b: The device-internal offset for the ROM that merges the overlay.
32 
33   Returns:      TRUE if the FAT is loaded correctly.
34  *---------------------------------------------------------------------------*/
WFS_LoadTable(WFSTableFormat * archive,MIAllocator * allocator,MIDevice * device,u32 origin_a,u32 origin_b)35 BOOL WFS_LoadTable(WFSTableFormat *archive, MIAllocator *allocator,
36                    MIDevice *device, u32 origin_a, u32 origin_b)
37 {
38     const u32       diff = origin_b - origin_a;
39     const BOOL      mixed = (diff != 0);
40     u32             mixed_overlay_count = 0;
41     u32             origin_b_fat = 0;
42     CARDRomRegion   mem_region[WFS_TABLE_REGION_MAX];
43     int             i;
44 
45     /* Initializes the structure */
46     archive->origin = origin_a;
47     archive->buffer = NULL;
48     archive->length = 0;
49 
50     /* Load the A header and record it in fat/fnt */
51     {
52         u8                      buf[0x60];
53         const CARDRomHeader    *header = (const CARDRomHeader *)buf;
54         (void)MI_ReadDevice(device, buf, archive->origin, sizeof(buf));
55         archive->region[WFS_TABLE_REGION_FAT].offset = MI_LoadLE32(&header->fat.offset);
56         archive->region[WFS_TABLE_REGION_FAT].length = MI_LoadLE32(&header->fat.length);
57         archive->region[WFS_TABLE_REGION_FNT].offset = MI_LoadLE32(&header->fnt.offset);
58         archive->region[WFS_TABLE_REGION_FNT].length = MI_LoadLE32(&header->fnt.length);
59     }
60     /* Load the B header and record it in ov9/ov7 */
61     {
62         u8                      buf[0x60];
63         const CARDRomHeader    *header = (const CARDRomHeader *)buf;
64         (void)MI_ReadDevice(device, buf, origin_b, sizeof(buf));
65         archive->region[WFS_TABLE_REGION_OV9].offset = MI_LoadLE32(&header->main_ovt.offset) + diff;
66         archive->region[WFS_TABLE_REGION_OV9].length = MI_LoadLE32(&header->main_ovt.length);
67         archive->region[WFS_TABLE_REGION_OV7].offset = MI_LoadLE32(&header->sub_ovt.offset) + diff;
68         archive->region[WFS_TABLE_REGION_OV7].length = MI_LoadLE32(&header->sub_ovt.length);
69         origin_b_fat = header->fat.offset + diff;
70     }
71     /* If 'mixed', [fat += (ov9 + ov7)] */
72     if (mixed)
73     {
74         mixed_overlay_count = (archive->region[WFS_TABLE_REGION_OV9].length +
75                                archive->region[WFS_TABLE_REGION_OV7].length)
76                               / sizeof(WFSOVLFormat);
77     }
78     /* Calculate length */
79     {
80         u32 offset = 0;
81         offset += sizeof(u32);
82         for (i = 0; i < WFS_TABLE_REGION_MAX; ++i)
83         {
84             mem_region[i].offset = offset;
85             mem_region[i].length = archive->region[i].length;
86             if (i == WFS_TABLE_REGION_FAT)
87             {
88                 mem_region[i].length += mixed_overlay_count * sizeof(WFSFATFormat);
89             }
90             mem_region[i].length = MATH_ROUNDUP(mem_region[i].length, 32);
91             offset += sizeof(u32) + mem_region[i].length;
92         }
93         archive->length = offset;
94     }
95     /* Allocate the buffer */
96     if (allocator)
97     {
98         archive->buffer = MI_CallAlloc(allocator, archive->length, sizeof(u32));
99         if (archive->buffer)
100         {
101             /* Load either A or B's fat/fnt/ov9/ov7. NOTE: origin has been adjusted. */
102             {
103                 u8     *dst = archive->buffer;
104                 MI_StoreLE32(dst, archive->origin);
105                 dst += sizeof(u32);
106                 for (i = 0; i < WFS_TABLE_REGION_MAX; ++i)
107                 {
108                     const u32 length = archive->region[i].length;
109                     const u32 padding = mem_region[i].length - length;
110                     MI_StoreLE32(dst, length);
111                     dst += sizeof(u32);
112                     (void)MI_ReadDevice(device, dst, archive->origin + archive->region[i].offset, length);
113                     dst += length;
114                     MI_CpuFill8(dst, 0x00, padding);
115                     dst += padding;
116                 }
117             }
118             /* If 'mixed', [fat += (ov9 + ov7)] */
119             if (mixed)
120             {
121                 u32     count = archive->region[WFS_TABLE_REGION_FAT].length / sizeof(WFSFATFormat);
122                 u32     total = count + mixed_overlay_count;
123                 u8     *dst = &archive->buffer[mem_region[WFS_TABLE_REGION_FAT].offset];
124                 WFSFATFormat *fat = (WFSFATFormat*)(dst + sizeof(u32));
125                 MI_StoreLE32(dst, total * sizeof(WFSFATFormat));
126                 for (i = WFS_TABLE_REGION_OV9; i < WFS_TABLE_REGION_MAX; ++i)
127                 {
128                     WFSOVLFormat *ovl = (WFSOVLFormat *)&archive->buffer[mem_region[i].offset + sizeof(u32)];
129                     u32     num = archive->region[i].length / sizeof(WFSOVLFormat);
130                     u32     j;
131                     for (j = 0; j < num; ++j)
132                     {
133                         if (count >= total)
134                         {
135                             OS_TWarning("exceeded FAT iterator! (internal logic error)");
136                         }
137                         else
138                         {
139                             WFSFATFormat entry;
140                             (void)MI_ReadDevice(device, &entry,
141                                                 archive->origin + origin_b_fat + ovl[j].file_id * sizeof(WFSFATFormat),
142                                                 sizeof(entry));
143                             MI_StoreLE32(&fat[count].top, MI_LEToH32(entry.top) + diff);
144                             MI_StoreLE32(&fat[count].bottom, MI_LEToH32(entry.bottom) + diff);
145                             MI_StoreLE32(&ovl[j].file_id, count);
146                             ++count;
147                         }
148                     }
149 
150                 }
151             }
152         }
153     }
154     return (archive->buffer != NULL);
155 }
156 
157 /*---------------------------------------------------------------------------*
158   Name:         WFS_ParseTable
159 
160   Description:  Parses the memory that read the NTR binary FAT image.
161 
162   Arguments:    archive: The WFSTableFormat structure to initialize
163                                  The FAT image must be configured in advance in the members 'buffer' and 'length'.
164 
165 
166   Returns:      None.
167  *---------------------------------------------------------------------------*/
WFS_ParseTable(WFSTableFormat * archive)168 void WFS_ParseTable(WFSTableFormat *archive)
169 {
170     const u8   *src = archive->buffer;
171     u32         pos = 0;
172     int         i;
173     /* Get the base offset */
174     archive->origin = MI_LoadLE32(&src[pos]);
175     pos += sizeof(u32);
176     /* Extract information about each region from the given buffer */
177     for (i = 0; i < WFS_TABLE_REGION_MAX; ++i)
178     {
179         u32     len = MI_LoadLE32(&src[pos]);
180         pos += sizeof(u32);
181         archive->region[i].offset = pos;
182         archive->region[i].length = len;
183         pos += MATH_ROUNDUP(len, 32);
184         if (pos > archive->length)
185         {
186             OS_TPanic("specified invalid archive buffer!");
187         }
188     }
189 }
190 
191 
192 /*---------------------------------------------------------------------------*
193   $Log: wfs_format.c,v $
194   Revision 1.1  2007/04/13 04:12:37  yosizaki
195   Initial upload.
196 
197   $NoKeywords: $
198  *---------------------------------------------------------------------------*/
199