1 
2 /***************************************************************************
3  *                    __            __ _ ___________                       *
4  *                    \ \          / /| |____   ____|                      *
5  *                     \ \        / / | |    | |                           *
6  *                      \ \  /\  / /  | |    | |                           *
7  *                       \ \/  \/ /   | |    | |                           *
8  *                        \  /\  /    | |    | |                           *
9  *                         \/  \/     |_|    |_|                           *
10  *                                                                         *
11  *                           Wiimms ISO Tools                              *
12  *                         http://wit.wiimm.de/                            *
13  *                                                                         *
14  ***************************************************************************
15  *                                                                         *
16  *   This file is part of the WIT project.                                 *
17  *   Visit http://wit.wiimm.de/ for project details and sources.           *
18  *                                                                         *
19  *   Copyright (c) 2009-2013 by Dirk Clemens <wiimm@wiimm.de>              *
20  *                                                                         *
21  ***************************************************************************
22  *                                                                         *
23  *   This program is free software; you can redistribute it and/or modify  *
24  *   it under the terms of the GNU General Public License as published by  *
25  *   the Free Software Foundation; either version 2 of the License, or     *
26  *   (at your option) any later version.                                   *
27  *                                                                         *
28  *   This program is distributed in the hope that it will be useful,       *
29  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
30  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
31  *   GNU General Public License for more details.                          *
32  *                                                                         *
33  *   See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt       *
34  *                                                                         *
35  ***************************************************************************/
36 
37 #include "file-formats.h"
38 #include "crypt.h"
39 
40 //
41 ///////////////////////////////////////////////////////////////////////////////
42 ///////////////				setup			///////////////
43 ///////////////////////////////////////////////////////////////////////////////
44 
validate_file_format_sizes(int trace_sizes)45 int validate_file_format_sizes ( int trace_sizes )
46 {
47     // 1. trace sizeof
48 
49  #ifdef TRACE_SIZEOF
50     if (trace_sizes)
51     {
52 	TRACE_SIZEOF(u8);
53 	TRACE_SIZEOF(u16);
54 	TRACE_SIZEOF(u32);
55 	TRACE_SIZEOF(u64);
56 
57 	TRACE_SIZEOF(be16_t);
58 	TRACE_SIZEOF(be32_t);
59 	TRACE_SIZEOF(be64_t);
60 
61 	TRACE_SIZEOF(dol_header_t);
62 	TRACE_SIZEOF(dol_record_t);
63 	TRACE_SIZEOF(wbfs_inode_info_t);
64 	TRACE_SIZEOF(wd_header_128_t);
65 	TRACE_SIZEOF(wd_header_t);
66 	TRACE_SIZEOF(wd_boot_t);
67 	TRACE_SIZEOF(wd_region_t);
68 	TRACE_SIZEOF(wd_ptab_info_t);
69 	TRACE_SIZEOF(wd_ptab_entry_t);
70 	TRACE_SIZEOF(wd_ptab_t);
71 	TRACE_SIZEOF(wd_ticket_t);
72 	TRACE_SIZEOF(wd_part_header_t);
73 	TRACE_SIZEOF(wd_tmd_content_t);
74 	TRACE_SIZEOF(wd_tmd_t);
75 	TRACE_SIZEOF(wd_part_control_t);
76 	TRACE_SIZEOF(wd_part_sector_t);
77 	TRACE_SIZEOF(wd_fst_item_t);
78 
79 	TRACE_SIZEOF(wbfs_head_t);
80 	TRACE_SIZEOF(wbfs_disc_info_t);
81 
82 	TRACE_SIZEOF(WIT_PATCH_MAGIC);
83 	TRACE_SIZEOF(wpat_magic);
84 	TRACE_SIZEOF(wpat_comment_t);
85 	TRACE_SIZEOF(wpat_data_t);
86 	TRACE_SIZEOF(wpat_filename_t);
87 	TRACE_SIZEOF(wpat_filenames_t);
88 	TRACE_SIZEOF(wpat_header_t);
89 	TRACE_SIZEOF(wpat_patch_file_t);
90 	TRACE_SIZEOF(wpat_size_t);
91 	TRACE_SIZEOF(wpat_toc_file_t);
92 	TRACE_SIZEOF(wpat_toc_header_t);
93 	TRACE_SIZEOF(wpat_type_t);
94 
95 
96      #ifdef DEBUG
97 	wd_part_control_t pc, pc_saved;
98 	ASSERT(!clear_part_control(&pc,
99 			WII_TMD_GOOD_SIZE,
100 			0xa00, 0x1000000 ));
101 	memcpy(&pc_saved,&pc,sizeof(pc_saved));
102 	ASSERT(!setup_part_control(&pc));
103 	ASSERT(!memcmp(&pc_saved,&pc,sizeof(pc_saved)));
104      #endif
105     }
106  #endif
107 
108     // 2. assertions
109 
110     wd_tmd_t * tmd = 0;
111     wd_ticket_t * tik = 0;
112 
113     #undef  CHECK
114     #define CHECK ASSERT
115     #undef  OFFSET
116     #define OFFSET(p,i) ((char*)&p->i-(char*)p)
117 
118     CHECK( 1 == sizeof(u8)  );
119     CHECK( 2 == sizeof(u16) );
120     CHECK( 4 == sizeof(u32) );
121     CHECK( 8 == sizeof(u64) );
122 
123     CHECK( 2 == sizeof(be16_t) );
124     CHECK( 4 == sizeof(be32_t) );
125     CHECK( 8 == sizeof(be64_t) );
126 
127     CHECK( sizeof(wbfs_inode_info_t) + WBFS_INODE_INFO_OFF == 0x100 );
128     CHECK( sizeof(wbfs_inode_info_t)	== WBFS_INODE_INFO_SIZE );
129 
130     CHECK( sizeof(dol_header_t)		== DOL_HEADER_SIZE );
131     CHECK( sizeof(wd_header_128_t)	==  0x80 );
132     CHECK( sizeof(wd_header_t)		== 0x100 );
133     CHECK( sizeof(wd_region_t)		== WII_REGION_SIZE );
134     CHECK( sizeof(wd_ptab_t)		== WII_MAX_PTAB_SIZE );
135     CHECK( sizeof(wd_boot_t)		== WII_BOOT_SIZE );
136     CHECK( sizeof(wd_part_sector_t)	== WII_SECTOR_SIZE );
137     CHECK( sizeof(wd_fst_item_t)	== 12 ); // test because of union
138 
139     CHECK( OFFSET(tik,title_key)	== WII_TICKET_KEY_OFF );
140     CHECK( OFFSET(tik,title_id)		== WII_TICKET_IV_OFF );
141     CHECK( OFFSET(tik,issuer)		== WII_TICKET_SIG_OFF );
142     CHECK( OFFSET(tik,fake_sign)	== WII_TICKET_BRUTE_FORCE_OFF );
143     CHECK( sizeof(wd_ticket_t)		== WII_TICKET_SIZE );
144 
145     CHECK( OFFSET(tmd,issuer)		== WII_TMD_SIG_OFF );
146     CHECK( OFFSET(tmd,fake_sign)	== WII_TMD_BRUTE_FORCE_OFF );
147     CHECK( OFFSET(tmd,content[0].hash)	== 0x1f4 );
148     CHECK( sizeof(wd_tmd_t)		== 0x1e4 );
149     CHECK( sizeof(wd_tmd_content_t)	== 0x24 );
150     CHECK( sizeof(wd_tmd_t) + sizeof(wd_tmd_content_t) == WII_TMD_GOOD_SIZE );
151 
152     //----- 3. calculate return value
153 
154     #undef  CHECK
155     #define CHECK(a) if (!(a)) return __LINE__;
156 
157     CHECK( 1 == sizeof(u8)  );
158     CHECK( 2 == sizeof(u16) );
159     CHECK( 4 == sizeof(u32) );
160     CHECK( 8 == sizeof(u64) );
161 
162     CHECK( 2 == sizeof(be16_t) );
163     CHECK( 4 == sizeof(be32_t) );
164     CHECK( 8 == sizeof(be64_t) );
165 
166     CHECK( sizeof(wbfs_inode_info_t) + WBFS_INODE_INFO_OFF == 0x100 );
167     CHECK( sizeof(wbfs_inode_info_t)	== WBFS_INODE_INFO_SIZE );
168 
169     CHECK( sizeof(dol_header_t)		== DOL_HEADER_SIZE );
170     CHECK( sizeof(wd_header_128_t)	==  0x80 );
171     CHECK( sizeof(wd_header_t)		== 0x100 );
172     CHECK( sizeof(wd_region_t)		== WII_REGION_SIZE );
173     CHECK( sizeof(wd_ptab_t)		== WII_MAX_PTAB_SIZE );
174     CHECK( sizeof(wd_boot_t)		== WII_BOOT_SIZE );
175     CHECK( sizeof(wd_part_sector_t)	== WII_SECTOR_SIZE );
176     CHECK( sizeof(wd_fst_item_t)	== 12 ); // test because of union
177 
178     CHECK( OFFSET(tik,title_key)	== WII_TICKET_KEY_OFF );
179     CHECK( OFFSET(tik,title_id)		== WII_TICKET_IV_OFF );
180     CHECK( OFFSET(tik,issuer)		== WII_TICKET_SIG_OFF );
181     CHECK( OFFSET(tik,fake_sign)	== WII_TICKET_BRUTE_FORCE_OFF );
182     CHECK( sizeof(wd_ticket_t)		== WII_TICKET_SIZE );
183 
184     CHECK( OFFSET(tmd,issuer)		== WII_TMD_SIG_OFF );
185     CHECK( OFFSET(tmd,fake_sign)	== WII_TMD_BRUTE_FORCE_OFF );
186     CHECK( OFFSET(tmd,content[0].hash)	== 0x1f4 );
187     CHECK( sizeof(wd_tmd_t)		== 0x1e4 );
188     CHECK( sizeof(wd_tmd_content_t)	== 0x24 );
189     CHECK( sizeof(wd_tmd_t) + sizeof(wd_tmd_content_t) == WII_TMD_GOOD_SIZE );
190 
191     return 0;
192 }
193 
194 //
195 ///////////////////////////////////////////////////////////////////////////////
196 ///////////////		endian conversions for structs		///////////////
197 ///////////////////////////////////////////////////////////////////////////////
198 
ntoh_dol_header(dol_header_t * dest,const dol_header_t * src)199 void ntoh_dol_header ( dol_header_t * dest, const dol_header_t * src )
200 {
201     DASSERT(dest);
202 
203     if (!src)
204 	src = dest;
205     else if ( dest != src )
206 	memcpy(dest,src,sizeof(*dest));
207 
208     const u32 * src_ptr = src->sect_off;
209     u32 * dest_ptr = dest->sect_off;
210     u32 * dest_end = (u32*)&dest->padding;
211 
212     while ( dest_ptr < dest_end )
213 	*dest_ptr++ = ntohl(*src_ptr++);
214 }
215 
216 //-----------------------------------------------------------------------------
217 
hton_dol_header(dol_header_t * dest,const dol_header_t * src)218 void hton_dol_header ( dol_header_t * dest, const dol_header_t * src )
219 {
220     DASSERT(dest);
221 
222     if (!src)
223 	src = dest;
224     else if ( dest != src )
225 	memcpy(dest,src,sizeof(*dest));
226 
227     const u32 * src_ptr = src->sect_off;
228     u32 * dest_ptr = dest->sect_off;
229     u32 * dest_end = (u32*)&dest->padding;
230 
231     while ( dest_ptr < dest_end )
232 	*dest_ptr++ = htonl(*src_ptr++);
233 }
234 
235 ///////////////////////////////////////////////////////////////////////////////
236 
ntoh_boot(wd_boot_t * dest,const wd_boot_t * src)237 void ntoh_boot ( wd_boot_t * dest, const wd_boot_t * src )
238 {
239     DASSERT(dest);
240 
241     if (!src)
242 	src = dest;
243     else if ( dest != src )
244 	memcpy(dest,src,sizeof(*dest));
245 
246     dest->dol_off4	= ntohl(src->dol_off4);
247     dest->fst_off4	= ntohl(src->fst_off4);
248     dest->fst_size4	= ntohl(src->fst_size4);
249     dest->max_fst_size4	= ntohl(src->max_fst_size4);
250 }
251 
252 //-----------------------------------------------------------------------------
253 
hton_boot(wd_boot_t * dest,const wd_boot_t * src)254 void hton_boot ( wd_boot_t * dest, const wd_boot_t * src )
255 {
256     DASSERT(dest);
257 
258     if (!src)
259 	src = dest;
260     else if ( dest != src )
261 	memcpy(dest,src,sizeof(*dest));
262 
263     dest->dol_off4	= htonl(src->dol_off4);
264     dest->fst_off4	= htonl(src->fst_off4);
265     dest->fst_size4	= htonl(src->fst_size4);
266     dest->max_fst_size4	= htonl(src->max_fst_size4);
267 }
268 
269 ///////////////////////////////////////////////////////////////////////////////
270 
ntoh_part_header(wd_part_header_t * dest,const wd_part_header_t * src)271 void ntoh_part_header ( wd_part_header_t * dest, const wd_part_header_t * src )
272 {
273     DASSERT(dest);
274 
275     if (!src)
276 	src = dest;
277     else if ( dest != src )
278 	memcpy(dest,src,sizeof(*dest));
279 
280     dest->tmd_size	= ntohl(src->tmd_size);
281     dest->tmd_off4	= ntohl(src->tmd_off4);
282     dest->cert_size	= ntohl(src->cert_size);
283     dest->cert_off4	= ntohl(src->cert_off4);
284     dest->h3_off4	= ntohl(src->h3_off4);
285     dest->data_off4	= ntohl(src->data_off4);
286     dest->data_size4	= ntohl(src->data_size4);
287 }
288 
289 //-----------------------------------------------------------------------------
290 
hton_part_header(wd_part_header_t * dest,const wd_part_header_t * src)291 void hton_part_header ( wd_part_header_t * dest, const wd_part_header_t * src )
292 {
293     DASSERT(dest);
294 
295     if (!src)
296 	src = dest;
297     else if ( dest != src )
298 	memcpy(dest,src,sizeof(*dest));
299 
300     dest->tmd_size	= htonl(src->tmd_size);
301     dest->tmd_off4	= htonl(src->tmd_off4);
302     dest->cert_size	= htonl(src->cert_size);
303     dest->cert_off4	= htonl(src->cert_off4);
304     dest->h3_off4	= htonl(src->h3_off4);
305     dest->data_off4	= htonl(src->data_off4);
306     dest->data_size4	= htonl(src->data_size4);
307 }
308 
309 ///////////////////////////////////////////////////////////////////////////////
310 
ntoh_inode_info(wbfs_inode_info_t * dest,const wbfs_inode_info_t * src)311 void ntoh_inode_info ( wbfs_inode_info_t * dest, const wbfs_inode_info_t * src )
312 {
313     DASSERT(dest);
314 
315     if (!src)
316 	src = dest;
317     else if ( dest != src )
318 	memcpy(dest,src,sizeof(*dest));
319 
320     dest->n_hd_sec	= ntohl(src->n_hd_sec);
321     dest->info_version	= ntohl(src->info_version);
322 
323     dest->itime		= ntoh64(src->itime);
324     dest->mtime		= ntoh64(src->mtime);
325     dest->ctime		= ntoh64(src->ctime);
326     dest->atime		= ntoh64(src->atime);
327     dest->dtime		= ntoh64(src->dtime);
328 }
329 
330 //-----------------------------------------------------------------------------
331 
hton_inode_info(wbfs_inode_info_t * dest,const wbfs_inode_info_t * src)332 void hton_inode_info ( wbfs_inode_info_t * dest, const wbfs_inode_info_t * src )
333 {
334     DASSERT(dest);
335 
336     if (!src)
337 	src = dest;
338     else if ( dest != src )
339 	memcpy(dest,src,sizeof(*dest));
340 
341     dest->n_hd_sec	= htonl(src->n_hd_sec);
342     dest->info_version	= htonl(src->info_version);
343 
344     dest->itime		= hton64(src->itime);
345     dest->mtime		= hton64(src->mtime);
346     dest->ctime		= hton64(src->ctime);
347     dest->atime		= hton64(src->atime);
348     dest->dtime		= hton64(src->dtime);
349 }
350 
351 //
352 ///////////////////////////////////////////////////////////////////////////////
353 ///////////////			struct dol_record_t		///////////////
354 ///////////////////////////////////////////////////////////////////////////////
355 
calc_dol_records(dol_record_t * rec,bool term_null,const dol_header_t * dol_head)356 uint calc_dol_records
357 (
358     dol_record_t	*rec,		// pointer to at least DOL_N_SECTIONS records
359     bool		term_null,	// true: add a NULL record at end of list
360     const dol_header_t	*dol_head	// source DOL header
361 )
362 {
363     DASSERT(rec);
364     DASSERT(dol_head);
365 
366     dol_header_t dh;
367     ntoh_dol_header(&dh,dol_head);
368     dol_record_t *dest = rec;
369     u32 last_addr = 0xffffffff;
370 
371     for(;;)
372     {
373 	u32 max_addr = 0;
374 	int i, found = -1;
375 	for ( i = 0; i < DOL_N_SECTIONS; i++ )
376 	{
377 	    if (   dh.sect_off[i]
378 		&& dh.sect_size[i]
379 		&& dh.sect_addr[i] < last_addr
380 		&& dh.sect_addr[i] > max_addr )
381 	    {
382 		found = i;
383 		max_addr = dh.sect_addr[i];
384 	    }
385 	}
386 	if ( found < 0 )
387 	    break;
388 
389 	memset(dest,0,sizeof(*dest));
390 	dest->addr	= dh.sect_addr[found];
391 	dest->size	= dh.sect_size[found];
392 	dest->xsize	= dest->size;
393 	dest->delta	= dest->addr - dh.sect_off[found];
394 
395 	if ( found < DOL_N_TEXT_SECTIONS )
396 	{
397 	    dest->name[0] = 'T';
398 	    dest->name[1] = found+'0';
399 	}
400 	else
401 	{
402 	    dest->name[0] = 'D';
403 	    dest->name[1] = found-DOL_N_TEXT_SECTIONS+'0';
404 	}
405 
406 	if ( dest > rec
407 	    && dest[-1].delta == dest->delta
408 	    && dest->addr + dest->size == dest[-1].addr )
409 	{
410 	    dest->xsize += dest[-1].xsize;
411 	}
412 	last_addr = dest->addr;
413 	dest++;
414     }
415 
416     if (term_null)
417 	memset(dest,0,sizeof(*dest));
418     return dest - rec;
419 }
420 
421 ///////////////////////////////////////////////////////////////////////////////
422 ///////////////////////////////////////////////////////////////////////////////
423 
search_dol_record(dol_record_t * rec,uint n_rec,u32 addr,u32 size)424 const dol_record_t * search_dol_record
425 (
426     dol_record_t	*rec,		// pointer to at least records
427     uint		n_rec,		// number of records, set it to DOL_N_SECTIONS
428 					//   if record lsit is NULL termianted
429     u32			addr,		// address to search
430     u32			size		// size of object, if NULL, ignore it
431 )
432 {
433     DASSERT(rec);
434 
435     while ( n_rec-- > 0 )
436     {
437 	if (!rec->size)
438 	    break;
439 
440 	if ( addr >= rec->addr && addr+size <= rec->addr+rec->xsize )
441 	    return rec;
442 	rec++;
443     }
444     return 0;
445 }
446 
447 //
448 ///////////////////////////////////////////////////////////////////////////////
449 ///////////////			enum wd_compression_t		///////////////
450 ///////////////////////////////////////////////////////////////////////////////
451 
wd_get_compression_name(wd_compression_t compr,ccp invalid_result)452 ccp wd_get_compression_name
453 (
454     wd_compression_t	compr,		// compression mode
455     ccp			invalid_result	// return value if 'compr' is invalid
456 )
457 {
458     static ccp tab[] =
459     {
460 	"NONE",
461 	"PURGE",
462 	"BZIP2",
463 	"LZMA",
464 	"LZMA2",
465     };
466 
467     return (u32)compr < sizeof(tab)/sizeof(*tab) ? tab[compr] : invalid_result;
468 }
469 
470 ///////////////////////////////////////////////////////////////////////////////
471 
wd_print_compression(char * buf,size_t buf_size,wd_compression_t compr_method,int compr_level,u32 chunk_size,int mode)472 ccp wd_print_compression
473 (
474     char		* buf,		// result buffer
475 					// If NULL, a local circulary static buffer is used
476     size_t		buf_size,	// size of 'buf', ignored if buf==NULL
477     wd_compression_t	compr_method,	// compression method
478     int			compr_level,	// compression level
479     u32			chunk_size,	// compression chunk size, multiple of MiB
480     int			mode		// 1=number, 2=name, 3=number and name
481 )
482 {
483     if (!buf)
484 	buf = GetCircBuf( buf_size = 20 );
485 
486     if ( compr_method < 0 || compr_method >= WD_COMPR__N )
487     {
488 	compr_method = WD_COMPR__N;
489 	compr_level = 0;
490     }
491     else if ( compr_method < WD_COMPR__FIRST_REAL || compr_level < 0 )
492 	compr_level = 0;
493     else if ( compr_level > 9 )
494 	compr_level = 9;
495 
496     char cbuf[10] = {0};
497     if ( compr_method != WD_COMPR__N )
498     {
499 	chunk_size /= WII_GROUP_SIZE; // reduce chunk_size to a factor
500 	if (chunk_size)
501 	    snprintf(cbuf,sizeof(cbuf),"@%u",chunk_size);
502     }
503 
504 
505     mode &= 3;
506     if ( mode == 1 )
507     {
508 	if ( compr_method == WD_COMPR__N )
509 	    snprintf(buf,buf_size,"-");
510 	else if (compr_level)
511 	    snprintf(buf,buf_size,"%u.%u%s",compr_method,compr_level,cbuf);
512 	else
513 	    snprintf(buf,buf_size,"%u%s",compr_method,cbuf);
514     }
515     else if ( mode == 2 )
516     {
517 	ccp name = wd_get_compression_name(compr_method,"-");
518 	if ( compr_method == WD_COMPR__N )
519 	    snprintf(buf,buf_size,"-");
520 	else if (compr_level)
521 	    snprintf(buf,buf_size,"%s.%u%s",name,compr_level,cbuf);
522 	else
523 	    snprintf(buf,buf_size,"%s%s",name,cbuf);
524     }
525     else
526     {
527 	ccp name = wd_get_compression_name(compr_method,"-");
528 	if ( compr_method == WD_COMPR__N )
529 	    snprintf(buf,buf_size,"- -");
530 	else if (compr_level)
531 	    snprintf(buf,buf_size,"%u.%u%s %s.%u%s",
532 			compr_method, compr_level, cbuf,
533 			name, compr_level, cbuf );
534 	else
535 	    snprintf(buf,buf_size,"%u%s %s%s",
536 			compr_method, cbuf, name, cbuf );
537     }
538 
539     return buf;
540 }
541 
542 //
543 ///////////////////////////////////////////////////////////////////////////////
544 ///////////////			struct wd_header_t		///////////////
545 ///////////////////////////////////////////////////////////////////////////////
546 
id_setup(void * dest_id,const void * source_id,int id_size)547 static void id_setup ( void * dest_id, const void * source_id, int id_size )
548 {
549     DASSERT(dest_id);
550     DASSERT(id_size>0);
551 
552     u8 * dest = dest_id;
553     memset(dest,'0',id_size);
554 
555     int i;
556     const u8 * src = source_id ? source_id : "WIT";
557     for ( i = 0; i < id_size && *src; i++ )
558 	*dest++ = *src++;
559 }
560 
561 ///////////////////////////////////////////////////////////////////////////////
562 
header_128_setup(wd_header_128_t * dhead,const void * id6,ccp disc_title,bool is_gc)563 void header_128_setup
564 (
565     wd_header_128_t	* dhead,	// valid pointer
566     const void		* id6,		// NULL or pointer to ID
567     ccp			disc_title,	// NULL or pointer to disc title (truncated)
568     bool		is_gc		// true: GameCube setup
569 )
570 {
571     memset(dhead,0,sizeof(*dhead));
572     id_setup(&dhead->disc_id,id6,6);
573 
574     if (!disc_title)
575 	disc_title = "WIT: Wiimms ISO Tools, http://wit.wiimm.de/";
576     strncpy(dhead->disc_title,disc_title,sizeof(dhead->disc_title)-1);
577 
578     if (is_gc)
579 	dhead->gc_magic = htonl(GC_MAGIC);
580     else
581 	dhead->wii_magic = htonl(WII_MAGIC);
582 }
583 
584 ///////////////////////////////////////////////////////////////////////////////
585 
header_setup(wd_header_t * dhead,const void * id6,ccp disc_title,bool is_gc)586 void header_setup
587 (
588     wd_header_t		* dhead,	// valid pointer
589     const void		* id6,		// NULL or pointer to ID
590     ccp			disc_title,	// NULL or pointer to disc title (truncated)
591     bool		is_gc		// true: GameCube setup
592 )
593 {
594     memset(dhead,0,sizeof(*dhead));
595     header_128_setup((wd_header_128_t*)dhead,id6,disc_title,is_gc);
596 }
597 
598 ///////////////////////////////////////////////////////////////////////////////
599 ///////////////////////////////////////////////////////////////////////////////
600 
get_header_128_disc_type(wd_header_128_t * dhead,wd_disc_attrib_t * attrib)601 wd_disc_type_t get_header_128_disc_type
602 (
603     wd_header_128_t	* dhead,	// valid pointer
604     wd_disc_attrib_t	* attrib	// not NULL: store disc attributes
605 )
606 {
607     DASSERT(dhead);
608 
609     //----- check Wii disc
610 
611     if ( ntohl(dhead->wii_magic) == WII_MAGIC )
612     {
613 	if (attrib)
614 	    *attrib = WD_DA_WII;
615 	return WD_DT_WII;
616     }
617 
618 
619     //----- check GameCube disc
620 
621     if ( ntohl(dhead->gc_magic) == GC_MAGIC )
622     {
623 	if (attrib)
624 	{
625 	    wd_disc_attrib_t att = WD_DA_GAMECUBE;
626 
627 	    ccp id6 = &dhead->disc_id;
628 	    if (   !memcmp(id6,"GCOPDV",6)
629 		|| !memcmp(id6,"COBRAM",6)
630 		|| !memcmp(id6,"GGCOSD",6)
631 		|| !memcmp(id6,"RGCOSD",6) )
632 	    {
633 		att |= WD_DA_GC_MULTIBOOT;
634 		if (!memcmp(id6+4,"DVD9",4))
635 		    att |= WD_DA_GC_DVD9;
636 	    }
637 	    *attrib = att;
638 	}
639 	return WD_DT_GAMECUBE;
640     }
641 
642 
643     //----- unknown disc
644 
645     if (attrib)
646 	*attrib = 0;
647     return WD_DT_UNKNOWN;
648 }
649 
650 ///////////////////////////////////////////////////////////////////////////////
651 
get_header_disc_type(wd_header_t * dhead,wd_disc_attrib_t * attrib)652 wd_disc_type_t get_header_disc_type
653 (
654     wd_header_t		* dhead,	// valid pointer
655     wd_disc_attrib_t	* attrib	// not NULL: store disc attributes
656 )
657 {
658     return get_header_128_disc_type((wd_header_128_t*)dhead,attrib);
659 }
660 
661 //
662 ///////////////////////////////////////////////////////////////////////////////
663 ///////////////			enum wd_age_rating_t		///////////////
664 ///////////////////////////////////////////////////////////////////////////////
665 
wd_print_age_rating(char * buf,size_t buf_size,u8 * age_rating)666 ccp wd_print_age_rating
667 (
668     char		* buf,		// result buffer
669 					// If NULL, a local circulary static buffer is used
670     size_t		buf_size,	// size of 'buf', ignored if buf==NULL
671     u8			* age_rating	// valid buffer of 'WD_AGE__N' bytes
672 )
673 {
674     if (!buf)
675 	buf = GetCircBuf( buf_size = 70 );
676 
677     DASSERT( WD_AGE__N == 10 );
678     snprintf( buf, buf_size,
679 		"Jap=%u USA=%u ?=%u Eur=%u,%u,%u,%u,%u,%u Kor=%u",
680 		age_rating[WD_AGE_JAPAN],
681 		age_rating[WD_AGE_USA],
682 		age_rating[WD_AGE_UNKNOWN],
683 		age_rating[WD_AGE_EUROPE1],
684 		age_rating[WD_AGE_EUROPE2],
685 		age_rating[WD_AGE_EUROPE3],
686 		age_rating[WD_AGE_EUROPE4],
687 		age_rating[WD_AGE_EUROPE5],
688 		age_rating[WD_AGE_EUROPE6],
689 		age_rating[WD_AGE_KOREA] );
690 
691     return buf;
692 }
693 
694 //
695 ///////////////////////////////////////////////////////////////////////////////
696 ///////////////			struct wd_ticket_t		///////////////
697 ///////////////////////////////////////////////////////////////////////////////
698 
699 const char not_encrypted_marker[] = "*** partition is not encrypted ***";
700 
701 ///////////////////////////////////////////////////////////////////////////////
702 
ticket_setup(wd_ticket_t * tik,const void * id4)703 void ticket_setup ( wd_ticket_t * tik, const void * id4 )
704 {
705     DASSERT(tik);
706     memset(tik,0,sizeof(*tik));
707     tik->sig_type = htonl(0x10001);
708     strncpy((char*)tik->issuer,"Root-CA00000001-XS00000003",sizeof(tik->issuer));
709 
710     static u8 base_id[] = { 0,1,0,0, 0,0,0,0 };
711     memcpy(tik->title_id,base_id,8);
712     id_setup(tik->title_id+4,id4,4);
713 
714     memset(tik->unknown7,0xff,sizeof(tik->unknown7));
715     tik->unknown3 = 0xffff;
716 
717     RANDOM_FILL(tik->title_key,sizeof(tik->title_key));
718     RANDOM_FILL(tik->ticket_id,sizeof(tik->ticket_id));
719     tik->ticket_id[0] = 0;
720     tik->ticket_id[1] = 1;
721 }
722 
723 ///////////////////////////////////////////////////////////////////////////////
724 
ticket_clear_encryption(wd_ticket_t * tik,int mark_not_encrypted)725 void ticket_clear_encryption ( wd_ticket_t * tik, int mark_not_encrypted )
726 {
727     ASSERT(tik);
728 
729     memset(tik->sig,0,sizeof(tik->sig));
730     memset(tik->sig_padding,0,sizeof(tik->sig_padding));
731     memset(tik->fake_sign,0,sizeof(tik->fake_sign));
732 
733     if (mark_not_encrypted)
734     {
735 	ASSERT( sizeof(not_encrypted_marker) < sizeof(tik->sig_padding));
736 	ASSERT( sizeof(not_encrypted_marker) < sizeof(tik->fake_sign));
737 	strncpy( (char*)tik->sig_padding, not_encrypted_marker, sizeof(tik->sig_padding)-1 );
738 	strncpy( (char*)tik->fake_sign, not_encrypted_marker, sizeof(tik->fake_sign)-1 );
739     }
740 }
741 
742 ///////////////////////////////////////////////////////////////////////////////
743 
ticket_is_marked_not_encrypted(const wd_ticket_t * tik)744 bool ticket_is_marked_not_encrypted ( const wd_ticket_t * tik )
745 {
746     ASSERT(tik);
747     DASSERT( sizeof(not_encrypted_marker) < sizeof(tik->sig_padding));
748     DASSERT( sizeof(not_encrypted_marker) < sizeof(tik->fake_sign));
749 
750     return !strncmp( (char*)tik->sig_padding, not_encrypted_marker, sizeof(tik->sig_padding) )
751 	&& !strncmp( (char*)tik->fake_sign, not_encrypted_marker, sizeof(tik->fake_sign) );
752 }
753 
754 ///////////////////////////////////////////////////////////////////////////////
755 
ticket_fake_sign(wd_ticket_t * tik,u32 tik_size)756 u32 ticket_fake_sign ( wd_ticket_t * tik, u32 tik_size )
757 {
758     ASSERT(tik);
759     ticket_clear_encryption(tik,0);
760 
761     if (!tik_size)  // auto calculation
762 	tik_size = sizeof(wd_ticket_t);
763 
764     // fake signing
765 
766  #ifdef DEBUG
767     TRACE("FAKESIGN: start brute force\n");
768     //TRACE_HEXDUMP16(0,0,tik,tik_size);
769  #endif
770 
771     u32 val = 0;
772     u8 hash[WII_HASH_SIZE];
773     do
774     {
775 	memcpy(tik->fake_sign,&val,sizeof(val));
776 	SHA1( ((u8*)tik)+WII_TICKET_SIG_OFF, tik_size-WII_TICKET_SIG_OFF, hash );
777 	if (!*hash)
778 	    break;
779 	//TRACE_HEXDUMP(0,0,1,WII_HASH_SIZE,hash,WII_HASH_SIZE);
780 	val++;
781 
782     } while (val);
783 
784     TRACE("FAKESIGN: success, count=%u\n", val+1);
785     return *hash ? 0 : val+1;
786 }
787 
788 ///////////////////////////////////////////////////////////////////////////////
789 
ticket_is_fake_signed(const wd_ticket_t * tik,u32 tik_size)790 bool ticket_is_fake_signed ( const wd_ticket_t * tik, u32 tik_size )
791 {
792     ASSERT(tik);
793 
794     if (!tik_size)  // auto calculation
795 	tik_size = sizeof(wd_ticket_t);
796 
797     int i;
798     for ( i = 0; i < sizeof(tik->sig); i++ )
799 	if (tik->sig[i])
800 	    return 0;
801 
802     u8 hash[WII_HASH_SIZE];
803     SHA1( ((u8*)tik)+WII_TICKET_SIG_OFF, tik_size-WII_TICKET_SIG_OFF, hash );
804     return !*hash;
805 }
806 
807 //
808 ///////////////////////////////////////////////////////////////////////////////
809 ///////////////			struct wd_tmd_t			///////////////
810 ///////////////////////////////////////////////////////////////////////////////
811 
tmd_setup(wd_tmd_t * tmd,u32 tmd_size,const void * id4)812 void tmd_setup ( wd_tmd_t * tmd, u32 tmd_size, const void * id4 )
813 {
814     DASSERT(tmd);
815     DASSERT(tmd_size>=sizeof(wd_tmd_t));
816 
817     memset(tmd,0,tmd_size);
818     if ( tmd_size >= sizeof(wd_tmd_t) + sizeof(wd_tmd_content_t) )
819     {
820 	tmd->n_content       = htons(1);
821 	tmd->content[0].type = htons(3);
822 	tmd->content[0].size = hton64(0xff7c0000);
823     }
824 
825     tmd->sig_type = htonl(0x10001);
826     strncpy((char*)tmd->issuer,"Root-CA00000001-CP00000004",sizeof(tmd->issuer));
827 
828     tmd->sys_version	= hton64(0x100000023ull);
829     tmd->title_type	= htonl(1);
830     tmd->group_id	= htons(0x3031);
831 
832     static u8 base_id[] = { 0,1,0,0, 0,0,0,0 };
833     memcpy(tmd->title_id,base_id,8);
834     id_setup(tmd->title_id+4,id4,4);
835 }
836 
837 ///////////////////////////////////////////////////////////////////////////////
838 
tmd_clear_encryption(wd_tmd_t * tmd,int mark_not_encrypted)839 void tmd_clear_encryption ( wd_tmd_t * tmd, int mark_not_encrypted )
840 {
841     ASSERT(tmd);
842 
843     memset(tmd->sig,0,sizeof(tmd->sig));
844     memset(tmd->sig_padding,0,sizeof(tmd->sig_padding));
845     memset(tmd->fake_sign,0,sizeof(tmd->fake_sign));
846 
847     if (mark_not_encrypted)
848     {
849 	ASSERT( sizeof(not_encrypted_marker) < sizeof(tmd->sig_padding));
850 	ASSERT( sizeof(not_encrypted_marker) < sizeof(tmd->fake_sign));
851 	strncpy( (char*)tmd->sig_padding, not_encrypted_marker, sizeof(tmd->sig_padding)-1 );
852 	strncpy( (char*)tmd->fake_sign, not_encrypted_marker, sizeof(tmd->fake_sign)-1 );
853     }
854 }
855 
856 ///////////////////////////////////////////////////////////////////////////////
857 
tmd_is_marked_not_encrypted(const wd_tmd_t * tmd)858 bool tmd_is_marked_not_encrypted ( const wd_tmd_t * tmd )
859 {
860     DASSERT( !tmd || sizeof(not_encrypted_marker) < sizeof(tmd->sig_padding));
861     DASSERT( !tmd || sizeof(not_encrypted_marker) < sizeof(tmd->fake_sign));
862 
863     return tmd
864 	&& !strncmp( (char*)tmd->sig_padding, not_encrypted_marker, sizeof(tmd->sig_padding) )
865 	&& !strncmp( (char*)tmd->fake_sign, not_encrypted_marker, sizeof(tmd->fake_sign) );
866 }
867 
868 ///////////////////////////////////////////////////////////////////////////////
869 
tmd_fake_sign(wd_tmd_t * tmd,u32 tmd_size)870 u32 tmd_fake_sign ( wd_tmd_t * tmd, u32 tmd_size )
871 {
872     ASSERT(tmd);
873     tmd_clear_encryption(tmd,0);
874 
875     if (!tmd_size)  // auto calculation
876 	tmd_size = sizeof(wd_tmd_t) + tmd->n_content * sizeof(wd_tmd_content_t);
877 
878     // fake signing
879 
880  #ifdef DEBUG
881     TRACE("FAKESIGN: start brute force\n");
882     //TRACE_HEXDUMP16(0,0,tmd,tmd_size);
883  #endif
884 
885     u32 val = 0;
886     u8 hash[WII_HASH_SIZE];
887     do
888     {
889 	memcpy(tmd->fake_sign,&val,sizeof(val));
890 	SHA1( ((u8*)tmd)+WII_TMD_SIG_OFF, tmd_size-WII_TMD_SIG_OFF, hash );
891 	if (!*hash)
892 	    break;
893 	//TRACE_HEXDUMP(0,0,1,WII_HASH_SIZE,hash,WII_HASH_SIZE);
894 	val++;
895 
896     } while (val);
897 
898     TRACE("FAKESIGN: success, count=%u\n", val+1);
899     return *hash ? 0 : val+1;
900 }
901 
902 ///////////////////////////////////////////////////////////////////////////////
903 
tmd_is_fake_signed(const wd_tmd_t * tmd,u32 tmd_size)904 bool tmd_is_fake_signed ( const wd_tmd_t * tmd, u32 tmd_size )
905 {
906     if (!tmd)
907 	return false;
908 
909     if (!tmd_size)  // auto calculation
910 	tmd_size = sizeof(wd_tmd_t) + tmd->n_content * sizeof(wd_tmd_content_t);
911 
912     int i;
913     for ( i = 0; i < sizeof(tmd->sig); i++ )
914 	if (tmd->sig[i])
915 	    return 0;
916 
917     u8 hash[WII_HASH_SIZE];
918     SHA1( ((u8*)tmd)+WII_TMD_SIG_OFF, tmd_size-WII_TMD_SIG_OFF, hash );
919     return !*hash;
920 }
921 
922 //
923 ///////////////////////////////////////////////////////////////////////////////
924 ///////////////		    struct wd_part_control_t		///////////////
925 ///////////////////////////////////////////////////////////////////////////////
926 
setup_part_control_helper(wd_part_control_t * pc)927 static int setup_part_control_helper ( wd_part_control_t * pc )
928 {
929     // tmd, tmd_size, cert, cert_size and h3 must 0 or be valid
930 
931     ASSERT(pc);
932     TRACE("setup_part_control_helper(%p)\n",pc);
933 
934     TRACE(" - PART: %p : %8x + %9zx\n", pc->part_bin, 0, sizeof(pc->part_bin) );
935 
936     // setup head
937 
938     wd_part_header_t * head = (wd_part_header_t*)pc->part_bin;
939     pc->head		= head;
940     pc->head_size	= sizeof(wd_part_header_t);
941     TRACE(" - HEAD: %p : %8x + %9x\n", pc->head, 0, pc->head_size );
942 
943     u8* head_end = pc->part_bin + ALIGN32(sizeof(wd_part_header_t),4);
944     u8* part_end = pc->part_bin + sizeof(pc->part_bin);
945 
946     // setup tmd
947 
948     u8* ptr		= pc->tmd
949 				? (u8*) pc->tmd
950 				: pc->part_bin + ALIGN32(sizeof(wd_part_header_t),32);
951     pc->tmd		= (wd_tmd_t*)ptr;
952     head->tmd_size	= htonl(pc->tmd_size);
953     head->tmd_off4	= htonl(ptr-pc->part_bin>>2);
954     TRACE(" - TMD:  %p : %8x + %9x\n", pc->tmd, ntohl(head->tmd_off4)<<2, pc->tmd_size );
955 
956     // setup tmd_content
957 
958     const u32 n_content = pc->tmd_size >= sizeof(wd_tmd_t)
959 			? ( pc->tmd_size - sizeof(wd_tmd_t) ) / sizeof(wd_tmd_content_t)
960 			: 0;
961     if ( !pc->tmd->n_content || pc->tmd->n_content > n_content )
962 	pc->tmd->n_content = n_content;
963 
964     pc->tmd_content	= n_content ? pc->tmd->content : 0;
965 
966     TRACE(" - CON0: %p : %8zx + %9zx [N=%u/%u]\n",
967 		pc->tmd_content,
968 		(ntohl(head->tmd_off4)<<2) + sizeof(wd_tmd_t),
969 		sizeof(wd_tmd_content_t), pc->tmd->n_content, n_content );
970 
971     // setup cert
972 
973     ptr			= pc->cert
974 				? (u8*) pc->cert
975 				: (u8*) pc->tmd + ALIGN32(pc->tmd_size,32);
976     pc->cert		= ptr;
977     head->cert_size	= htonl(pc->cert_size);
978     head->cert_off4	= htonl(ptr-pc->part_bin>>2);
979     TRACE(" - CERT: %p : %8x + %9x\n", pc->cert, ntohl(head->cert_off4)<<2, pc->cert_size );
980 
981     // setup h3
982 
983     if (!pc->h3)
984 	pc->h3		= pc->part_bin + sizeof(pc->part_bin) - WII_H3_SIZE;
985     pc->h3_size		= WII_H3_SIZE;
986     head->h3_off4	= htonl(pc->h3-pc->part_bin>>2);
987     TRACE(" - H3:   %p : %8x + %9x\n", pc->h3, ntohl(head->h3_off4)<<2, WII_H3_SIZE );
988 
989     // setup data
990 
991     if (!pc->data_off)
992 	pc->data_off	= sizeof(pc->part_bin);
993     head->data_off4	= htonl(pc->data_off>>2);
994     head->data_size4	= htonl(pc->data_size>>2);
995     TRACE(" - DATA: %p : %8x + %9llx\n",
996 		pc->part_bin + sizeof(pc->part_bin),
997 		ntohl(head->data_off4)<<2, pc->data_size );
998 
999     // validation check
1000 
1001     pc->is_valid = 0;
1002 
1003     if ( pc->tmd_size < WII_TMD_GOOD_SIZE
1004 	|| pc->cert_size < 0x10
1005 	|| pc->data_off < sizeof(pc->part_bin)
1006 	|| pc->data_size > WII_MAX_PART_SECTORS * (u64)WII_SECTOR_SIZE
1007     )
1008 	return 1;
1009 
1010     // check that all data is within part_bin
1011 
1012     u8 * tmd_beg  = (u8*)pc->tmd;
1013     u8 * tmd_end  = tmd_beg + pc->tmd_size;
1014     u8 * cert_beg = (u8*)pc->cert;
1015     u8 * cert_end = cert_beg + pc->cert_size;
1016     u8 * h3_beg   = (u8*)pc->h3;
1017     u8 * h3_end   = h3_beg   + pc->h3_size;
1018 
1019     if (   tmd_beg  < head_end || tmd_end  > part_end
1020 	|| cert_beg < head_end || cert_end > part_end
1021 	|| h3_beg   < head_end || h3_end   > part_end
1022     )
1023 	return 1;
1024 
1025     // check overlays
1026 
1027     if (   tmd_end  >= cert_beg && tmd_beg  < cert_end	// overlay tmd  <-> cert
1028 	|| tmd_end  >= h3_beg   && tmd_beg  < h3_end	// overlay tmd  <-> h3
1029 	|| cert_end >= h3_beg   && cert_beg < h3_end	// overlay cert <-> h3
1030     )
1031 	return 1;
1032 
1033     // all seems ok
1034 
1035     pc->is_valid = 1;
1036     return 0;
1037 }
1038 
1039 ///////////////////////////////////////////////////////////////////////////////
1040 
clear_part_control(wd_part_control_t * pc,u32 tmd_size,u32 cert_size,u64 data_size)1041 int clear_part_control
1042 	( wd_part_control_t * pc, u32 tmd_size, u32 cert_size, u64 data_size )
1043 {
1044     ASSERT(pc);
1045     TRACE("clear_part_control(%p,%x,%x,%llx)\n",pc,tmd_size,cert_size,data_size);
1046 
1047     memset(pc,0,sizeof(*pc));
1048 
1049     pc->tmd_size	= tmd_size;
1050     pc->cert_size	= cert_size;
1051     pc->data_size	= ALIGN64(data_size,WII_SECTOR_SIZE);
1052 
1053     return setup_part_control_helper(pc);
1054 }
1055 
1056 ///////////////////////////////////////////////////////////////////////////////
1057 
setup_part_control(wd_part_control_t * pc)1058 int setup_part_control ( wd_part_control_t * pc )
1059 {
1060     ASSERT(pc);
1061     TRACE("setup_part_control(%p)\n",pc);
1062 
1063     // clear controling data
1064     memset( pc->part_bin+sizeof(pc->part_bin), 0, +sizeof(*pc)-sizeof(pc->part_bin) );
1065 
1066     wd_part_header_t * head = (wd_part_header_t*)pc->part_bin;
1067 
1068     pc->tmd		= (wd_tmd_t*)
1069 			( pc->part_bin + ( ntohl(head->tmd_off4)   << 2 ));
1070     pc->tmd_size	=		   ntohl(head->tmd_size);
1071     pc->cert		= pc->part_bin + ( ntohl(head->cert_off4)  << 2 );
1072     pc->cert_size	=		   ntohl(head->cert_size);
1073     pc->h3		= pc->part_bin + ( ntohl(head->h3_off4)    << 2 );
1074     pc->data_off	=	      (u64)ntohl(head->data_off4)  << 2;
1075     pc->data_size	=	      (u64)ntohl(head->data_size4) << 2;
1076 
1077     return setup_part_control_helper(pc);
1078 }
1079 
1080 ///////////////////////////////////////////////////////////////////////////////
1081 
part_control_fake_sign(wd_part_control_t * pc,int calc_h4)1082 u32 part_control_fake_sign ( wd_part_control_t * pc, int calc_h4 )
1083 {
1084     ASSERT(pc);
1085 
1086     u32 stat = 0;
1087     if (pc->is_valid)
1088     {
1089 	// caluclate SHA1 hash 'h4'
1090 	if ( calc_h4 && pc->tmd_content )
1091 	    SHA1( pc->h3, pc->h3_size, pc->tmd_content->hash );
1092 
1093 	// fake signing
1094 	const u32 stat1 = tmd_fake_sign(pc->tmd,pc->tmd_size);
1095 	const u32 stat2 = ticket_fake_sign(&pc->head->ticket,0);
1096 	stat = stat1 && stat2 ? stat + stat2 : 0;
1097     }
1098 
1099     return stat;
1100 }
1101 
1102 ///////////////////////////////////////////////////////////////////////////////
1103 
part_control_is_fake_signed(const wd_part_control_t * pc)1104 int part_control_is_fake_signed ( const wd_part_control_t * pc )
1105 {
1106     ASSERT(pc);
1107     return pc->is_valid && pc->tmd && tmd_is_fake_signed(pc->tmd,pc->tmd_size);
1108 }
1109 
1110 //
1111 ///////////////////////////////////////////////////////////////////////////////
1112 ///////////////			wit patch files			///////////////
1113 ///////////////////////////////////////////////////////////////////////////////
1114 
1115 const char wpat_magic[12] = WIT_PATCH_MAGIC;
1116 
1117 ///////////////////////////////////////////////////////////////////////////////
1118 
wpat_get_type_name(wpat_type_t type,ccp return_if_invalid)1119 ccp wpat_get_type_name ( wpat_type_t type, ccp return_if_invalid )
1120 {
1121     static ccp tab[] =
1122     {
1123 	0,
1124 	"TOC:HEADER",		// WPAT_HEADER
1125 	"TOC:COMMENT",		// WPAT_COMMENT
1126 	"TOC:DATA",		// WPAT_DATA
1127 	"TOC:DELETE-FILE",	// WPAT_DELETE_FILE
1128 	"TOC:CREATE-FILE",	// WPAT_CREATE_FILE
1129 	"TOC:MOVE-FILE",	// WPAT_MOVE_FILE
1130 	"TOC:COPY-FILE",	// WPAT_COPY_FILE
1131 	"TOC:LINK-FILE",	// WPAT_LINK_FILE
1132 	"TOC:PATCH-FILE",	// WPAT_PATCH_FILE
1133     };
1134 
1135     const unsigned id = type &= WPAT_M_ID;
1136     ccp res = id < sizeof(tab)/sizeof(*tab) ? tab[id] : 0;
1137 
1138     return !res
1139 	    ? return_if_invalid
1140 	    : type & WPAT_F_TOC
1141 		? res
1142 		: res + 4;
1143 }
1144 
1145 ///////////////////////////////////////////////////////////////////////////////
1146 
wpat_get_size(wpat_size_t type_size)1147 u32 wpat_get_size ( wpat_size_t type_size )
1148 {
1149     return ( ntohl(type_size.size4) & 0xffffff ) << 2;
1150 }
1151 
1152 ///////////////////////////////////////////////////////////////////////////////
1153 
wpat_calc_size(wpat_type_t type,u32 size)1154 wpat_size_t wpat_calc_size ( wpat_type_t type, u32 size )
1155 {
1156     wpat_size_t type_size;
1157     type_size.size4 = htonl( size + 3 >> 2 );
1158     type_size.type  = type;
1159     return type_size;
1160 }
1161 
1162 //
1163 ///////////////////////////////////////////////////////////////////////////////
1164 ///////////////			consts & vars			///////////////
1165 ///////////////////////////////////////////////////////////////////////////////
1166 
1167 const char skeleton_marker[10] = "[SKELETON]";
1168 
1169 //
1170 ///////////////////////////////////////////////////////////////////////////////
1171 ///////////////			    E N D			///////////////
1172 ///////////////////////////////////////////////////////////////////////////////
1173 
1174