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 "tools.h"
38 #include "file-formats.h"
39 
40 //
41 ///////////////////////////////////////////////////////////////////////////////
42 ///////////////		low level endian conversions		///////////////
43 ///////////////////////////////////////////////////////////////////////////////
44 
be16(const void * be_data_ptr)45 u16 be16 ( const void * be_data_ptr )
46 {
47     const u8 * d = be_data_ptr;
48     return d[0] << 8 | d[1];
49 }
50 
be24(const void * be_data_ptr)51 u32 be24 ( const void * be_data_ptr )
52 {
53     const u8 * d = be_data_ptr;
54     return ( d[0] << 8 | d[1] ) << 8 | d[2];
55 }
56 
be32(const void * be_data_ptr)57 u32 be32 ( const void * be_data_ptr )
58 {
59     const u8 * d = be_data_ptr;
60     return (( d[0] << 8 | d[1] ) << 8 | d[2] ) << 8 | d[3];
61 }
62 
be64(const void * be_data_ptr)63 u64 be64 ( const void * be_data_ptr )
64 {
65     const u8 * d = be_data_ptr;
66     return (u64)be32(d) << 32 | be32(d+4);
67 }
68 
69 ///////////////////////////////////////////////////////////////////////////////
70 
le16(const void * le_data_ptr)71 u16 le16 ( const void * le_data_ptr )
72 {
73     const u8 * d = le_data_ptr;
74     return d[1] << 8 | d[0];
75 }
76 
le24(const void * le_data_ptr)77 u32 le24 ( const void * le_data_ptr )
78 {
79     const u8 * d = le_data_ptr;
80     return ( d[2] << 8 | d[1] ) << 8 | d[0];
81 }
82 
le32(const void * le_data_ptr)83 u32 le32 ( const void * le_data_ptr )
84 {
85     const u8 * d = le_data_ptr;
86     return (( d[3] << 8 | d[2] ) << 8 | d[1] ) << 8 | d[0];
87 }
88 
le64(const void * le_data_ptr)89 u64 le64 ( const void * le_data_ptr )
90 {
91     const u8 * d = le_data_ptr;
92     return (u64)le32(d+4) << 32 | le32(d);
93 }
94 
95 ///////////////////////////////////////////////////////////////////////////////
96 
hton64(u64 data)97 be64_t hton64 ( u64 data )
98 {
99     be64_t result;
100     ((u32*)&result)[0] = htonl( (u32)(data >> 32) );
101     ((u32*)&result)[1] = htonl( (u32)data );
102     return result;
103 }
104 
ntoh64(be64_t data)105 u64 ntoh64 ( be64_t data )
106 {
107     return (u64)ntohl(((u32*)&data)[0]) << 32 | ntohl(((u32*)&data)[1]);
108 }
109 
110 //
111 ///////////////////////////////////////////////////////////////////////////////
112 ///////////////			error messages			///////////////
113 ///////////////////////////////////////////////////////////////////////////////
114 
wd_print_error(ccp func,ccp file,uint line,enumError err,ccp format,...)115 enumError wd_print_error
116 (
117     ccp		func,		// calling function, use macro __FUNCTION__
118     ccp		file,		// source file, use macro __FILE__
119     uint	line,		// line number of source file, use macro __LINE__
120     enumError	err,		// error code
121     ccp		format,		// NULL or format string for fprintf() function.
122     ...				// parameters for 'format'
123 )
124 {
125     fflush(stdout);
126 
127     ccp msg_prefix, msg_name;
128     if ( err > ERR_ERROR )
129     {
130 	msg_prefix = "!!! ";
131 	msg_name   = "FATAL ERROR";
132     }
133     else if ( err > ERR_WARNING )
134     {
135 	msg_prefix = "!! ";
136 	msg_name   = "ERROR";
137     }
138     else if ( err > ERR_OK )
139     {
140 	msg_prefix = "! ";
141 	msg_name   = "WARNING";
142     }
143     else
144     {
145 	msg_prefix = "";
146 	msg_name   = "SUCCESS";
147     }
148 
149     if ( err > ERR_OK )
150 	fprintf(stderr,"%s%s in %s() @ %s#%d\n",
151 	    msg_prefix, msg_name, func, file, line );
152 
153     if (format)
154     {
155 	fputs(msg_prefix,stderr);
156 	va_list arg;
157 	va_start(arg,format);
158 	vfprintf(stderr,format,arg);
159 	va_end(arg);
160 	if ( format[strlen(format)-1] != '\n' )
161 	    fputc('\n',stderr);
162     }
163 
164     fflush(stderr);
165 
166     if ( err > ERR_ERROR )
167 	exit(ERR_FATAL);
168 
169     return err;
170 }
171 
172 //
173 ///////////////////////////////////////////////////////////////////////////////
174 ///////////////			aligning			///////////////
175 ///////////////////////////////////////////////////////////////////////////////
176 
wd_align32(u32 number,u32 align,int align_mode)177 u32 wd_align32
178 (
179     u32		number,		// object of aligning
180     u32		align,		// NULL or valid align factor
181     int		align_mode	// <0: round down, =0: round math, >0 round up
182 )
183 {
184     if ( align > 1 )
185     {
186 	const u32 mod = number % align;
187 	if (mod)
188 	{
189 	    if ( align_mode < 0 )
190 		number -= mod;
191 	    else if  ( align_mode > 0 )
192 		number += align - mod;
193 	    else if ( mod < align/2 )
194 		number -= mod;
195 	    else
196 		number += align - mod;
197 	}
198     }
199 
200     return number;
201 }
202 
203 ///////////////////////////////////////////////////////////////////////////////
204 
wd_align64(u64 number,u64 align,int align_mode)205 u64 wd_align64
206 (
207     u64		number,		// object of aligning
208     u64		align,		// NULL or valid align factor
209     int		align_mode	// <0: round down, =0: round math, >0 round up
210 )
211 {
212     if ( align > 1 )
213     {
214 	const u64 mod = number % align;
215 	if (mod)
216 	{
217 	    if ( align_mode < 0 )
218 		number -= mod;
219 	    else if  ( align_mode > 0 )
220 		number += align - mod;
221 	    else if ( mod < align/2 )
222 		number -= mod;
223 	    else
224 		number += align - mod;
225 	}
226     }
227 
228     return number;
229 }
230 
231 ///////////////////////////////////////////////////////////////////////////////
232 
wd_align_part(u64 number,u64 align,bool is_gamecube)233 u64 wd_align_part
234 (
235     u64		number,		// object of aligning
236     u64		align,		// NULL or valid align factor
237     bool	is_gamecube	// hint for automatic calculation (align==0)
238 )
239 {
240     if (!align)
241 	align = is_gamecube ? GC_GOOD_PART_ALIGN : WII_SECTOR_SIZE;
242     return wd_align64(number,align,1);
243 }
244 
245 //
246 ///////////////////////////////////////////////////////////////////////////////
247 ///////////////			print size			///////////////
248 ///////////////////////////////////////////////////////////////////////////////
249 
250 ccp wd_size_tab_1000[WD_SIZE_N_MODES+1] =
251 {
252     0,		// WD_SIZE_DEFAULT
253     0,		// WD_SIZE_AUTO
254 
255     "B",	// WD_SIZE_BYTES
256     "kB",	// WD_SIZE_K
257     "MB",	// WD_SIZE_M
258     "GB",	// WD_SIZE_G
259     "TB",	// WD_SIZE_T
260     "PB",	// WD_SIZE_P
261     "EB",	// WD_SIZE_E
262 
263     0		// all others
264 };
265 
266 //-----------------------------------------------------------------------------
267 
268 ccp wd_size_tab_1024[WD_SIZE_N_MODES+1] =
269 {
270     0,		// WD_SIZE_DEFAULT
271     0,		// WD_SIZE_AUTO
272 
273     "B",	// WD_SIZE_BYTES
274     "KiB",	// WD_SIZE_K
275     "MiB",	// WD_SIZE_M
276     "GiB",	// WD_SIZE_G
277     "TiB",	// WD_SIZE_T
278     "PiB",	// WD_SIZE_P
279     "EiB",	// WD_SIZE_E
280 
281     0		// all others
282 };
283 
284 ///////////////////////////////////////////////////////////////////////////////
285 
wd_get_size_unit(wd_size_mode_t mode,ccp if_invalid)286 ccp wd_get_size_unit // get a unit for column headers
287 (
288     wd_size_mode_t	mode,		// print mode
289     ccp			if_invalid	// output for invalid modes
290 )
291 {
292     const bool force_1000 = ( mode & WD_SIZE_M_BASE ) == WD_SIZE_F_1000;
293 
294     switch ( mode & WD_SIZE_M_MODE )
295     {
296 	//---- SI and IEC units
297 
298 	case WD_SIZE_DEFAULT:
299 	case WD_SIZE_AUTO:	return "size";
300 	case WD_SIZE_BYTES:	return "bytes";
301 
302 	case WD_SIZE_K:		return force_1000 ? "kB" : "KiB";
303 	case WD_SIZE_M:		return force_1000 ? "MB" : "MiB";
304 	case WD_SIZE_G:		return force_1000 ? "GB" : "GiB";
305 	case WD_SIZE_T:		return force_1000 ? "TB" : "TiB";
306 	case WD_SIZE_P:		return force_1000 ? "PB" : "PiB";
307 	case WD_SIZE_E:		return force_1000 ? "EB" : "EiB";
308 
309 	case WD_SIZE_HD_SECT:	return "HDS";
310 	case WD_SIZE_WD_SECT:	return "WDS";
311 	case WD_SIZE_GC:	return "GC";
312 	case WD_SIZE_WII:	return "Wii";
313     }
314 
315     return if_invalid;
316 }
317 
318 ///////////////////////////////////////////////////////////////////////////////
319 
wd_get_size_fw(wd_size_mode_t mode,int min_fw)320 int wd_get_size_fw // get a good value field width
321 (
322     wd_size_mode_t	mode,		// print mode
323     int			min_fw		// minimal fw => return max(calc_fw,min_fw);
324 					// this value is also returned for invalid modes
325 )
326 {
327     int fw = mode & (WD_SIZE_F_AUTO_UNIT|WD_SIZE_F_NO_UNIT) ? 0 : 4;
328 
329     switch ( mode & WD_SIZE_M_MODE )
330     {
331 	case WD_SIZE_DEFAULT:
332 	case WD_SIZE_AUTO:
333 	    if ( !(mode & WD_SIZE_F_NO_UNIT) )
334 		fw = 4;
335 	    fw += 4;
336 	    break;
337 
338 	case WD_SIZE_BYTES:	fw += 10; break;
339 	case WD_SIZE_K:		fw +=  7; break;
340 	case WD_SIZE_M:		fw +=  4; break;
341 	case WD_SIZE_G:		fw +=  3; break;
342 	case WD_SIZE_T:		fw +=  3; break;
343 	case WD_SIZE_P:		fw +=  3; break;
344 	case WD_SIZE_E:		fw +=  3; break;
345 
346 	case WD_SIZE_HD_SECT:	fw +=  8; break;
347 	case WD_SIZE_WD_SECT:	fw +=  6; break;
348 	case WD_SIZE_GC:	fw +=  4; break;
349 	case WD_SIZE_WII:	fw +=  4; break;
350 
351 	default:		fw = min_fw;
352     }
353 
354     return fw > min_fw ? fw : min_fw;
355 }
356 
357 ///////////////////////////////////////////////////////////////////////////////
358 
wd_print_size(char * buf,size_t buf_size,u64 size,bool aligned,wd_size_mode_t mode)359 char * wd_print_size
360 (
361     char		* buf,		// result buffer
362 					// NULL: use a local circulary static buffer
363     size_t		buf_size,	// size of 'buf', ignored if buf==NULL
364     u64			size,		// size to print
365     bool		aligned,	// true: print exact 8 chars for num+unit
366     wd_size_mode_t	mode		// print mode
367 )
368 {
369     DASSERT( WD_SIZE_N_MODES <= WD_SIZE_M_MODE + 1 );
370 
371     if (!buf)
372 	buf = GetCircBuf( buf_size = 20 );
373 
374     const bool force_1000 = ( mode & WD_SIZE_M_BASE ) == WD_SIZE_F_1000;
375 
376     switch ( mode & WD_SIZE_M_MODE )
377     {
378 	//---- SI and IEC units
379 
380 	case WD_SIZE_BYTES:
381 	    snprintf(buf,buf_size, aligned ? "%6llu B" : "%llu B", size );
382 	    break;
383 
384 	case WD_SIZE_K:
385 	    if (force_1000)
386 		snprintf(buf,buf_size, aligned ? "%5llu kB" : "%llu kB",
387 			( size + KB_SI/2 ) / KB_SI );
388 	    else
389 		snprintf(buf,buf_size, aligned ? "%4llu KiB" : "%llu KiB",
390 			( size + KiB/2 ) / KiB );
391 	    break;
392 
393 	case WD_SIZE_M:
394 	    if (force_1000)
395 		snprintf(buf,buf_size, aligned ? "%5llu MB" : "%llu MB",
396 			( size + MB_SI /2 ) / MB_SI  );
397 	    else
398 		snprintf(buf,buf_size, aligned ? "%4llu MiB" : "%llu MiB",
399 			( size + MiB /2 ) / MiB  );
400 	    break;
401 
402 	case WD_SIZE_G:
403 	    if (force_1000)
404 		snprintf(buf,buf_size, aligned ? "%5llu GB" : "%llu GB",
405 			( size + GB_SI/2 ) / GB_SI );
406 	    else
407 		snprintf(buf,buf_size, aligned ? "%4llu GiB" : "%llu GiB",
408 			( size + GiB/2 ) / GiB );
409 	    break;
410 
411 	case WD_SIZE_T:
412 	    if (force_1000)
413 		snprintf(buf,buf_size, aligned ? "%5llu TB" : "%llu TB",
414 			( size + TB_SI/2 ) / TB_SI );
415 	    else
416 		snprintf(buf,buf_size, aligned ? "%4llu TiB" : "%llu TiB",
417 			( size + TiB/2 ) / TiB );
418 	    break;
419 
420 	case WD_SIZE_P:
421 	    if (force_1000)
422 		snprintf(buf,buf_size, aligned ? "%5llu PB" : "%llu PB",
423 			( size + PB_SI/2 ) / PB_SI );
424 	    else
425 		snprintf(buf,buf_size, aligned ? "%4llu PiB" : "%llu PiB",
426 			( size + PiB/2 ) / PiB );
427 	    break;
428 
429 	case WD_SIZE_E:
430 	    if (force_1000)
431 		snprintf(buf,buf_size, aligned ? "%5llu EB" : "%llu EB",
432 			( size + EB_SI/2 ) / EB_SI );
433 	    else
434 		snprintf(buf,buf_size, aligned ? "%4llu EiB" : "%llu EiB",
435 			( size + EiB/2 ) / EiB );
436 	    break;
437 
438 
439 	//----- special formats
440 
441 	case WD_SIZE_HD_SECT:
442 	    snprintf(buf,buf_size, aligned ? "%4llu HDS" : "%llu HDS",
443 			( size + HD_SECTOR_SIZE/2 ) / HD_SECTOR_SIZE );
444 	    break;
445 
446 	case WD_SIZE_WD_SECT:
447 	    snprintf(buf,buf_size, aligned ? "%4llu WDS" : "%llu WDS",
448 			( size + WII_SECTOR_SIZE/2 ) / WII_SECTOR_SIZE );
449 	    break;
450 
451 	case WD_SIZE_GC:
452 	    snprintf(buf,buf_size, aligned ? "%5.2f GC" : "%4.2f GC",
453 			(double)size / GC_DISC_SIZE );
454 	    break;
455 
456 	case WD_SIZE_WII:
457 	    snprintf(buf,buf_size,"%4.2f Wii",
458 			(double)size / WII_SECTOR_SIZE / WII_SECTORS_SINGLE_LAYER );
459 	    break;
460 
461 
462 	//----- default == auto
463 
464 	default:
465 	    buf = force_1000
466 			? wd_print_size_1000(buf,buf_size,size,aligned)
467 			: wd_print_size_1024(buf,buf_size,size,aligned);
468 	    if ( !(mode&WD_SIZE_F_NO_UNIT) )
469 		return buf;
470 
471     }
472 
473     if ( mode & (WD_SIZE_F_AUTO_UNIT|WD_SIZE_F_NO_UNIT) )
474     {
475 	char * ptr = buf;
476 	while ( *ptr == ' ' )
477 	    ptr++;
478 	while ( *ptr && *ptr != ' ' )
479 	    ptr++;
480 	*ptr  = 0;
481     }
482 
483     return buf;
484 }
485 
486 ///////////////////////////////////////////////////////////////////////////////
487 
wd_print_size_1000(char * buf,size_t buf_size,u64 size,bool aligned)488 char * wd_print_size_1000
489 (
490     char		* buf,		// result buffer
491 					// NULL: use a local circulary static buffer
492     size_t		buf_size,	// size of 'buf', ignored if buf==NULL
493     u64			size,		// size to print
494     bool		aligned		// true: print exact 4+4 chars for num+unit
495 )
496 {
497     if (!buf)
498 	buf = GetCircBuf( buf_size = 20 );
499 
500     u64 num;
501     wd_size_mode_t unit;
502 
503     u64 mb = (size+MB_SI/2)/MB_SI; // maybe an overflow => extra if
504     if ( mb < 10000 && size < EB_SI )
505     {
506 	u64 kb = (size+KB_SI/2)/KB_SI;
507 	if ( kb < 10 )
508 	{
509 	    num  = size;
510 	    unit = WD_SIZE_BYTES;
511 	}
512 	else if ( kb < 10000 )
513 	{
514 	    num  = kb;
515 	    unit = WD_SIZE_K;
516 	}
517 	else
518 	{
519 	    num  = mb;
520 	    unit = WD_SIZE_M;
521 	}
522     }
523     else
524     {
525 	mb = size / MB_SI; // recalc because of possible overflow
526 	u64 tb = (mb+MB_SI/2)/MB_SI;
527 	if ( tb < 10000 )
528 	{
529 	    if ( tb < 10 )
530 	    {
531 		num  = (mb+KB_SI/2)/KB_SI;
532 		unit = WD_SIZE_G;
533 	    }
534 	    else
535 	    {
536 		num  = tb;
537 		unit = WD_SIZE_T;
538 	    }
539 	}
540 	else
541 	{
542 	    u64 pb = (mb+GB_SI/2)/GB_SI;
543 	    if ( pb < 10000 )
544 	    {
545 		num  = pb;
546 		unit = WD_SIZE_P;
547 	    }
548 	    else
549 	    {
550 		num  = (mb+TB_SI/2)/TB_SI;
551 		unit = WD_SIZE_E;
552 	    }
553 	}
554     }
555 
556     if ( num && !( num % 1000 ) && wd_size_tab_1000[unit+1] )
557     {
558 	unit++;
559 	num /= 1000;
560     }
561 
562     if (aligned)
563 	snprintf(buf,buf_size,"%4llu %-3s",num,wd_size_tab_1000[unit]);
564     else
565 	snprintf(buf,buf_size,"%llu %s",num,wd_size_tab_1000[unit]);
566 
567     return buf;
568 };
569 
570 ///////////////////////////////////////////////////////////////////////////////
571 
wd_print_size_1024(char * buf,size_t buf_size,u64 size,bool aligned)572 char * wd_print_size_1024
573 (
574     char		* buf,		// result buffer
575 					// NULL: use a local circulary static buffer
576     size_t		buf_size,	// size of 'buf', ignored if buf==NULL
577     u64			size,		// size to print
578     bool		aligned		// true: print exact 4+4 chars for num+unit
579 )
580 {
581     if (!buf)
582 	buf = GetCircBuf( buf_size = 20 );
583 
584     u64 num;
585     wd_size_mode_t unit;
586 
587     u64 mib = (size+MiB/2)/MiB; // maybe an overflow => extra if
588     if ( mib < 10000 && size < EiB )
589     {
590 	u64 kib = (size+KiB/2)/KiB;
591 	if ( kib < 10 )
592 	{
593 	    num  = size;
594 	    unit = WD_SIZE_BYTES;
595 	}
596 	else if ( kib < 10000 )
597 	{
598 	    num  = kib;
599 	    unit = WD_SIZE_K;
600 	}
601 	else
602 	{
603 	    num  = mib;
604 	    unit = WD_SIZE_M;
605 	}
606     }
607     else
608     {
609 	mib = size / MiB; // recalc because of possible overflow
610 	u64 tib = (mib+MiB/2)/MiB;
611 	if ( tib < 10000 )
612 	{
613 	    if ( tib < 10 )
614 	    {
615 		num  = (mib+KiB/2)/KiB;
616 		unit = WD_SIZE_G;
617 	    }
618 	    else
619 	    {
620 		num  = tib;
621 		unit = WD_SIZE_T;
622 	    }
623 	}
624 	else
625 	{
626 	    u64 pib = (mib+GiB/2)/GiB;
627 	    if ( pib < 10000 )
628 	    {
629 		num  = pib;
630 		unit = WD_SIZE_P;
631 	    }
632 	    else
633 	    {
634 		num  = (mib+TiB/2)/TiB;
635 		unit = WD_SIZE_E;
636 	    }
637 	}
638     }
639 
640     if ( num && !( num & 0x3ff ) && wd_size_tab_1024[unit+1] )
641     {
642 	unit++;
643 	num /= 0x400;
644     }
645 
646     if (aligned)
647 	snprintf(buf,buf_size,"%4llu %-3s",num,wd_size_tab_1024[unit]);
648     else
649 	snprintf(buf,buf_size,"%llu %s",num,wd_size_tab_1024[unit]);
650 
651     return buf;
652 };
653 
654 //
655 ///////////////////////////////////////////////////////////////////////////////
656 ///////////////			printing helpers		///////////////
657 ///////////////////////////////////////////////////////////////////////////////
658 
wd_normalize_indent(int indent)659 int wd_normalize_indent
660 (
661     int			indent		// base vlaue to normalize
662 )
663 {
664     return indent < 0 ? 0 : indent < 50 ? indent : 50;
665 }
666 
667 ///////////////////////////////////////////////////////////////////////////////
668 
wd_print_byte_tab(FILE * f,int indent,const u8 * tab,u32 used,u32 size,u32 addr_factor,const char chartab[256],bool print_all)669 void wd_print_byte_tab
670 (
671     FILE		* f,		// valid output file
672     int			indent,		// indention of the output
673     const u8		* tab,		// valid pointer to byte table
674     u32			used,		// print minimal 'used' values of 'tab'
675     u32			size,		// size of 'tab'
676     u32			addr_factor,	// each 'tab' element represents 'addr_factor' bytes
677     const char		chartab[256],	// valid pointer to a char table
678     bool		print_all	// false: ignore const lines
679 )
680 {
681     ASSERT(f);
682     ASSERT(tab);
683 
684     enum { line_count = 64 };
685     char buf[2*line_count];
686     char skip_buf[2*line_count];
687 
688     indent = wd_normalize_indent(indent);
689     const int addr_fw = snprintf(buf,sizeof(buf),"%llx",(u64)addr_factor*size);
690     indent += addr_fw; // add address field width
691 
692     const u8 * ptr = tab;
693     const u8 * tab_end = ptr + size - 1;
694     const u8 * tab_min = ptr + used;
695     if ( tab_min > ptr )
696 	tab_min--;
697     while ( !*tab_end && tab_end > tab_min )
698 	tab_end--;
699     tab_end++;
700 
701     int skip_count = 0;
702     u64 skip_addr = 0;
703 
704     while ( ptr < tab_end )
705     {
706 	const u64 addr = (u64)( ptr - tab ) * addr_factor;
707 
708 	char * dest = buf;
709 	const u8 * line_end = ptr + line_count;
710 	if ( line_end > tab_end )
711 	    line_end = tab_end;
712 
713 	int pos = 0, last_count = 0;
714 	const u8 cmp_val = *ptr;
715 	while ( ptr < line_end )
716 	{
717 	    if ( !( pos++ & 15 ) )
718 		*dest++ = ' ';
719 	    last_count += *ptr == cmp_val;
720 	    *dest++ = chartab[*ptr++];
721 	}
722 	*dest = 0;
723 	DASSERT( dest < buf + sizeof(buf) );
724 	if ( last_count < line_count )
725 	{
726 	    if (skip_count)
727 	    {
728 		if ( skip_count == 1 )
729 		    fprintf(f,"%*llx:%s\n",indent,skip_addr,skip_buf);
730 		else
731 		    fprintf(f,"%*llx:%s *%5u\n",indent,skip_addr,skip_buf,skip_count);
732 		skip_count = 0;
733 	    }
734 	    fprintf(f,"%*llx:%s\n",indent,addr,buf);
735 	}
736 	else if (!skip_count++)
737 	{
738 	    memcpy(skip_buf,buf,sizeof(skip_buf));
739 	    skip_addr = addr;
740 	}
741     }
742 
743     if ( skip_count == 1 )
744 	fprintf(f,"%*llx:%s\n",indent,skip_addr,skip_buf);
745     else if (skip_count)
746 	fprintf(f,"%*llx:%s *%5u\n",indent,skip_addr,skip_buf,skip_count);
747 }
748 
749 ///////////////////////////////////////////////////////////////////////////////
750 
GetCircBuf(u32 buf_size)751 char * GetCircBuf // never returns NULL
752 (
753     u32		buf_size	// wanted buffer size
754 )
755 {
756     static char buf[500];
757     static char * ptr = buf;
758     DASSERT( ptr >= buf && ptr <= buf + sizeof(buf) );
759 
760     if ( buf_size > sizeof(buf) )
761 	OUT_OF_MEMORY;
762 
763     if ( buf + sizeof(buf) - ptr < buf_size )
764 	ptr = buf;
765 
766     char * result = ptr;
767     ptr = result + buf_size;
768     DASSERT( ptr >= buf && ptr <= buf + sizeof(buf) );
769 
770     noPRINT("CIRC-BUF: %3u -> %3zu / %3zu / %3zu\n",
771 		buf_size, result-buf, ptr-buf, sizeof(buf) );
772     return result;
773 }
774 
775 //
776 ///////////////////////////////////////////////////////////////////////////////
777 ///////////////			string helpers			///////////////
778 ///////////////////////////////////////////////////////////////////////////////
779 
780 const char EmptyString[] = "";
781 const char MinusString[] = "-";
782 
783 ///////////////////////////////////////////////////////////////////////////////
784 
FreeString(ccp str)785 void FreeString ( ccp str )
786 {
787     noTRACE("FreeString(%p) EmptyString=%p MinusString=%p\n",
788 	    str, EmptyString, MinusString );
789     if ( str != EmptyString && str != MinusString )
790 	FREE((char*)str);
791 }
792 
793 ///////////////////////////////////////////////////////////////////////////////
794 
StringCopyE(char * buf,ccp buf_end,ccp src)795 char * StringCopyE ( char * buf, ccp buf_end, ccp src )
796 {
797     // RESULT: end of copied string pointing to NULL
798     // 'src' may be a NULL pointer.
799 
800     ASSERT(buf);
801     ASSERT(buf<buf_end);
802     buf_end--;
803 
804     if (src)
805 	while( buf < buf_end && *src )
806 	    *buf++ = *src++;
807 
808     *buf = 0;
809     return buf;
810 }
811 
812 //-----------------------------------------------------------------------------
813 
StringCopyS(char * buf,size_t buf_size,ccp src)814 char * StringCopyS ( char * buf, size_t buf_size, ccp src )
815 {
816     return StringCopyE(buf,buf+buf_size,src);
817 }
818 
819 ///////////////////////////////////////////////////////////////////////////////
820 
StringCat2E(char * buf,ccp buf_end,ccp src1,ccp src2)821 char * StringCat2E ( char * buf, ccp buf_end, ccp src1, ccp src2 )
822 {
823     // RESULT: end of copied string pointing to NULL
824     // 'src*' may be a NULL pointer.
825 
826     ASSERT(buf);
827     ASSERT(buf<buf_end);
828     buf_end--;
829 
830     if (src1)
831 	while( buf < buf_end && *src1 )
832 	    *buf++ = *src1++;
833 
834     if (src2)
835 	while( buf < buf_end && *src2 )
836 	    *buf++ = *src2++;
837 
838     *buf = 0;
839     return buf;
840 }
841 
842 //-----------------------------------------------------------------------------
843 
StringCat2S(char * buf,size_t buf_size,ccp src1,ccp src2)844 char * StringCat2S ( char * buf, size_t buf_size, ccp src1, ccp src2 )
845 {
846     return StringCat2E(buf,buf+buf_size,src1,src2);
847 }
848 
849 ///////////////////////////////////////////////////////////////////////////////
850 
StringCat3E(char * buf,ccp buf_end,ccp src1,ccp src2,ccp src3)851 char * StringCat3E ( char * buf, ccp buf_end, ccp src1, ccp src2, ccp src3 )
852 {
853     // RESULT: end of copied string pointing to NULL
854     // 'src*' may be a NULL pointer.
855 
856     ASSERT(buf);
857     ASSERT(buf<buf_end);
858     buf_end--;
859 
860     if (src1)
861 	while( buf < buf_end && *src1 )
862 	    *buf++ = *src1++;
863 
864     if (src2)
865 	while( buf < buf_end && *src2 )
866 	    *buf++ = *src2++;
867 
868     if (src3)
869 	while( buf < buf_end && *src3 )
870 	    *buf++ = *src3++;
871 
872     *buf = 0;
873     return buf;
874 }
875 
876 //-----------------------------------------------------------------------------
877 
StringCat3S(char * buf,size_t buf_size,ccp src1,ccp src2,ccp src3)878 char * StringCat3S ( char * buf, size_t buf_size, ccp src1, ccp src2, ccp src3 )
879 {
880     return StringCat3E(buf,buf+buf_size,src1,src2,src3);
881 }
882 
883 ///////////////////////////////////////////////////////////////////////////////
884 ///////////////////////////////////////////////////////////////////////////////
885 
PrintVersion(char * buf,size_t buf_size,u32 version)886 char * PrintVersion
887 (
888     char		* buf,		// result buffer
889 					// If NULL, a local circulary static buffer is used
890     size_t		buf_size,	// size of 'buf', ignored if buf==NULL
891     u32			version		// version number to print
892 )
893 {
894     if (!buf)
895 	buf = GetCircBuf( buf_size = 20 );
896 
897     version = htonl(version); // we use big endian here
898     const u8 * v = (const u8 *)&version;
899 
900     if (v[2])
901     {
902 	if ( !v[3] || v[3] == 0xff )
903 	    snprintf(buf,buf_size,"%u.%02x.%02x",v[0],v[1],v[2]);
904 	else
905 	    snprintf(buf,buf_size,"%u.%02x.%02x.beta%u",v[0],v[1],v[2],v[3]);
906     }
907     else
908     {
909 	if ( !v[3] || v[3] == 0xff )
910 	    snprintf(buf,buf_size,"%u.%02x",v[0],v[1]);
911 	else
912 	    snprintf(buf,buf_size,"%u.%02x.beta%u",v[0],v[1],v[3]);
913     }
914 
915     return buf;
916 }
917 
918 //
919 ///////////////////////////////////////////////////////////////////////////////
920 ///////////////			fake functions			///////////////
921 ///////////////////////////////////////////////////////////////////////////////
922 
wbfs_sha1_fake(const unsigned char * d,size_t n,unsigned char * md)923 unsigned char * wbfs_sha1_fake
924 	( const unsigned char *d, size_t n, unsigned char *md )
925 {
926     static unsigned char m[WII_HASH_SIZE];
927     if (!md)
928 	md = m;
929     memset(md,0,sizeof(*md));
930     return md;
931 }
932 
933 //
934 ///////////////////////////////////////////////////////////////////////////////
935 ///////////////			    E N D			///////////////
936 ///////////////////////////////////////////////////////////////////////////////
937 
938