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