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 #define _GNU_SOURCE 1
38 
39 #include "debug.h"
40 #include "iso-interface.h"
41 #include "lib-bzip2.h"
42 #include "lib-lzma.h"
43 
44 ///////////////////////////////////////////////////////////////////////////////
45 
46 
47 	//////////////////////////////////
48 	//  [[2do]]:
49 	//	- WIA_MM_GROWING
50 	//	- raw data not 4-aligned
51 	//////////////////////////////////
52 
53 //
54 ///////////////////////////////////////////////////////////////////////////////
55 ///////////////			    consts			///////////////
56 ///////////////////////////////////////////////////////////////////////////////
57 
58 #define WATCH_GROUP -1		// -1: disabled
59 #define WATCH_SUB_GROUP 0
60 
61 ///////////////////////////////////////////////////////////////////////////////
62 
63 #if 0
64     #undef  PRINT
65     #define PRINT noPRINT
66     #undef  PRINT_IF
67     #define PRINT_IF noPRINT
68 #endif
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 
72 typedef enum mm_mode_t
73 {
74     WIA_MM_IGNORE = WD_PAT_IGNORE,
75 
76     WIA_MM_HEADER_DATA,		// header data, part of wia_disc_t
77     WIA_MM_CACHED_DATA,		// cached data, write at close
78     WIA_MM_RAW_GDATA,		// raw data, managed with 'gdata'
79     WIA_MM_PART_GDATA_0,	// partition data #0, managed with 'gdata'
80     WIA_MM_PART_GDATA_1,	// partition data #1, managed with 'gdata'
81     WIA_MM_EOF,			// end of file marker
82     WIA_MM_GROWING,		// growing space
83 
84 } mm_mode_t;
85 
86 //
87 ///////////////////////////////////////////////////////////////////////////////
88 ///////////////			    static data			///////////////
89 ///////////////////////////////////////////////////////////////////////////////
90 
91 static bool empty_decrypted_sector_initialized = false;
92 static wd_part_sector_t empty_decrypted_sector;
93 
94 //
95 ///////////////////////////////////////////////////////////////////////////////
96 ///////////////			    manage WIA			///////////////
97 ///////////////////////////////////////////////////////////////////////////////
98 
ResetWIA(wia_controller_t * wia)99 void ResetWIA
100 (
101     wia_controller_t	* wia		// NULL or valid pointer
102 )
103 {
104     if (wia)
105     {
106 	wd_close_disc(wia->wdisc);
107 	FREE(wia->part);
108 	FREE(wia->raw_data);
109 	FREE(wia->group);
110 	FREE(wia->gdata);
111 	wd_reset_memmap(&wia->memmap);
112 
113 	memset(wia,0,sizeof(*wia));
114     }
115 }
116 
117 ///////////////////////////////////////////////////////////////////////////////
118 
AllocBufferWIA(wia_controller_t * wia,u32 chunk_size,bool is_writing,bool calc_only)119 static u32 AllocBufferWIA
120 (
121     wia_controller_t	* wia,		// valid pointer
122     u32			chunk_size,	// wanted chunk size
123     bool		is_writing,	// true: cut chunk size
124     bool		calc_only	// true: don't allocate memory
125 )
126 {
127     DASSERT(wia);
128 
129     u32 chunk_groups = chunk_size <= 1
130 		? WIA_DEF_CHUNK_FACTOR
131 		: ( chunk_size + WIA_BASE_CHUNK_SIZE/2 ) / WIA_BASE_CHUNK_SIZE;
132 
133     if (!chunk_groups)
134 	chunk_groups = 1;
135     else if ( is_writing && chunk_groups > WIA_MAX_CHUNK_FACTOR )
136 	chunk_groups = WIA_MAX_CHUNK_FACTOR;
137 
138     chunk_size = chunk_groups * WIA_BASE_CHUNK_SIZE;
139 
140     wia->chunk_size	= chunk_size;
141     wia->chunk_groups	= chunk_groups;
142     wia->chunk_sectors	= chunk_groups * WII_GROUP_SECTORS;
143 
144     u32 needed_tempbuf_size
145 		= wia->chunk_groups
146 		* ( WII_GROUP_SIZE + WII_N_HASH_GROUP * sizeof(wia_exception_t) );
147     wia->memory_usage = needed_tempbuf_size + chunk_size;
148 
149     if (calc_only)
150     {
151 	wia->gdata_size = chunk_size;
152 	FREE(wia->gdata);
153 	wia->gdata = 0;
154     }
155     else
156     {
157 	PRINT("CHUNK_SIZE=%s, GDATA_SIZE=%s, IOBUF_SIZE=%s/%s, G+S=%u,%u\n",
158 	    wd_print_size_1024(0,0,wia->chunk_size,0),
159 	    wd_print_size_1024(0,0,wia->gdata_size,0),
160 	    wd_print_size_1024(0,0,needed_tempbuf_size,0),
161 	    wd_print_size_1024(0,0,tempbuf_size,0),
162 	    wia->chunk_groups, wia->chunk_sectors );
163 
164 	AllocTempBuffer(needed_tempbuf_size);
165 	if ( !wia->gdata || wia->gdata_size != chunk_size )
166 	{
167 	    wia->gdata_size = chunk_size;
168 	    FREE(wia->gdata);
169 	    wia->gdata = MALLOC(wia->gdata_size);
170 	}
171     }
172 
173     DASSERT( calc_only || wia->gdata );
174     DASSERT( calc_only || tempbuf );
175     DASSERT( wia->chunk_sectors == wia->chunk_groups * WII_GROUP_SECTORS );
176 
177     return wia->chunk_size;
178 };
179 
180 ///////////////////////////////////////////////////////////////////////////////
181 
CalcMemoryUsageWIA(wd_compression_t compression,int compr_level,u32 chunk_size,bool is_writing)182 u32 CalcMemoryUsageWIA
183 (
184     wd_compression_t	compression,	// compression method
185     int			compr_level,	// valid are 1..9 / 0: use default value
186     u32			chunk_size,	// wanted chunk size
187     bool		is_writing	// false: reading mode, true: writing mode
188 )
189 {
190     wia_controller_t wia;
191     memset(&wia,0,sizeof(wia));
192     u32 size = AllocBufferWIA(&wia,chunk_size,is_writing,true);
193     ResetWIA(&wia);
194 
195     switch(compression)
196     {
197 	case WD_COMPR__N:
198 	case WD_COMPR_NONE:
199 	case WD_COMPR_PURGE:
200 	    break;
201 
202 	case WD_COMPR_BZIP2:
203 	 #ifndef NO_BZIP2
204 	    size += CalcMemoryUsageBZIP2(compr_level,is_writing);
205 	 #endif
206 	    break;
207 
208 	case WD_COMPR_LZMA:
209 	    size += CalcMemoryUsageLZMA(compr_level,is_writing);
210 	    break;
211 
212 	case WD_COMPR_LZMA2:
213 	    size += CalcMemoryUsageLZMA2(compr_level,is_writing);
214 	    break;
215     }
216 
217     return size;
218 }
219 
220 ///////////////////////////////////////////////////////////////////////////////
221 
CalcDefaultSettingsWIA(wd_compression_t * compression,int * compr_level,u32 * chunk_size)222 int CalcDefaultSettingsWIA
223 (
224     wd_compression_t	* compression,	// NULL or compression method
225     int			* compr_level,	// NULL or compression level
226     u32			* chunk_size	// NULL or wanted chunk size
227 )
228 {
229     //----- get param
230 
231     wd_compression_t
232 	compr = compression ? *compression : WD_COMPR__DEFAULT;
233     int level = compr_level ? *compr_level : 0;
234     u32 csize = chunk_size  ? *chunk_size  : 0;
235 
236 
237     //----- normalize compression method
238 
239     if ( (unsigned)compr >= WD_COMPR__N )
240 	compr = WD_COMPR__DEFAULT;
241 
242 
243     //----- normalize compression level
244 
245     u32 clevel = WIA_DEF_CHUNK_FACTOR;
246     switch(compr)
247     {
248 	case WD_COMPR__N:
249 	case WD_COMPR_NONE:
250 	case WD_COMPR_PURGE:
251 	    level = 0;
252 	    //clevel = WIA_DEF_CHUNK_FACTOR; // == default setting
253 	    break;
254 
255 	case WD_COMPR_BZIP2:
256 	 #ifdef NO_BZIP2
257 	    level = 0;
258 	 #else
259 	    level = CalcCompressionLevelBZIP2(level);
260 	 #endif
261 	    //clevel = WIA_DEF_CHUNK_FACTOR; // == default setting
262 	    break;
263 
264 	case WD_COMPR_LZMA:
265 	case WD_COMPR_LZMA2:
266 	    level = CalcCompressionLevelLZMA(level);
267 	    //clevel = WIA_DEF_CHUNK_FACTOR; // == default setting
268 	    break;
269     }
270 
271 
272     //----- normalize compression chunksize
273 
274     if ( csize > 1 )
275     {
276 	clevel = csize / WIA_BASE_CHUNK_SIZE;
277 	if (!clevel)
278 	    clevel = 1;
279 	else if ( clevel > WIA_MAX_CHUNK_FACTOR )
280 	    clevel = WIA_MAX_CHUNK_FACTOR;
281     }
282     csize = clevel * WIA_BASE_CHUNK_SIZE;
283 
284 
285     //----- store results
286 
287     int stat = 0;
288     if ( compression && *compression != compr )
289     {
290 	*compression = compr;
291 	stat |= 1;
292     }
293     if ( compr_level && *compr_level != level )
294     {
295 	*compr_level = level;
296 	stat |= 2;
297     }
298     if ( chunk_size && *chunk_size != csize )
299     {
300 	*chunk_size = csize;
301 	stat |= 4;
302     }
303     return stat;
304 }
305 
306 ///////////////////////////////////////////////////////////////////////////////
307 
IsWIA(const void * data,size_t data_size,void * id6_result,wd_disc_type_t * disc_type,wd_compression_t * compression)308 bool IsWIA
309 (
310     const void		* data,		// data to check
311     size_t		data_size,	// size of data
312     void		* id6_result,	// not NULL: store ID6 (6 bytes without null term)
313     wd_disc_type_t	* disc_type,	// not NULL: store disc type
314     wd_compression_t	* compression	// not NULL: store compression
315 )
316 {
317     bool is_wia = false;
318     const wia_file_head_t * fhead = data;
319     if ( data_size >= sizeof(wia_file_head_t) )
320     {
321 	if (!memcmp(fhead->magic,WIA_MAGIC,sizeof(fhead->magic)))
322 	{
323 	    sha1_hash_t hash;
324 	    SHA1( (u8*)fhead, sizeof(*fhead)-sizeof(fhead->file_head_hash), hash );
325 	    is_wia = !memcmp(hash,fhead->file_head_hash,sizeof(hash));
326 	    //HEXDUMP(0,0,0,-WII_HASH_SIZE,hash,WII_HASH_SIZE);
327 	    //HEXDUMP(0,0,0,-WII_HASH_SIZE,fhead->file_head_hash,WII_HASH_SIZE);
328 	}
329     }
330 
331     const wia_disc_t * disc = (const wia_disc_t*)(fhead+1);
332 
333     if (id6_result)
334     {
335 	memset(id6_result,0,6);
336 	if ( is_wia && data_size >= (ccp)&disc->dhead - (ccp)data + 6 )
337 	    memcpy(id6_result,&disc->dhead,6);
338     }
339 
340     if (disc_type)
341     {
342 	*disc_type = is_wia && data_size >= (ccp)&disc->disc_type
343 						- (ccp)data + sizeof(disc->disc_type)
344 		? ntohl(disc->disc_type)
345 		: 0;
346     }
347 
348     if (compression)
349     {
350 	*compression = is_wia && data_size >= (ccp)&disc->compression
351 						- (ccp)data + sizeof(disc->compression)
352 		? ntohl(disc->compression)
353 		: 0;
354     }
355 
356     return is_wia;
357 }
358 
359 //
360 ///////////////////////////////////////////////////////////////////////////////
361 ///////////////			read helpers			///////////////
362 ///////////////////////////////////////////////////////////////////////////////
363 
calc_except_size(const void * except,u32 n_groups)364 static u32 calc_except_size
365 (
366     const void		* except,	// pointer to wia_except_list_t
367     u32			n_groups	// number of groups
368 )
369 {
370     DASSERT(except);
371     DASSERT( be16(except) == ntohs(((wia_except_list_t*)except)->n_exceptions) );
372 
373     wia_except_list_t * elist = (wia_except_list_t*)except;
374     while ( n_groups-- > 0 )
375 	elist = (wia_except_list_t*)( elist->exception + ntohs(elist->n_exceptions) );
376 
377     return (ccp)elist - (ccp)except;
378 }
379 
380 ///////////////////////////////////////////////////////////////////////////////
381 
calc_group_size(wia_controller_t * wia,u32 first_group,u32 n_groups)382 static u64 calc_group_size
383 (
384     wia_controller_t	* wia,		// valid pointer
385     u32			first_group,	// index of first group
386     u32			n_groups	// number of groups
387 )
388 {
389     DASSERT(wia);
390     DASSERT( first_group <= wia->disc.n_groups );
391     DASSERT( first_group + n_groups <= wia->disc.n_groups );
392 
393     u64 size = 0;
394     wia_group_t * grp = wia->group + first_group;
395     while ( n_groups-- > 0 )
396     {
397 	size += ntohl(grp->data_size);
398 	grp++;
399     }
400 
401     return size;
402 }
403 
404 ///////////////////////////////////////////////////////////////////////////////
405 
expand_segments(SuperFile_t * sf,const wia_segment_t * seg,void * seg_end,void * dest_ptr,u32 dest_size)406 static enumError expand_segments
407 (
408     SuperFile_t		* sf,		// source file
409     const wia_segment_t	* seg,		// source segment pointer
410     void		* seg_end,	// end of segment space
411     void		* dest_ptr,	// pointer to destination
412     u32			dest_size	// size of destination
413 )
414 {
415     DASSERT( seg );
416     DASSERT( seg_end );
417     DASSERT( dest_ptr );
418     DASSERT( dest_size >= 8 );
419     DASSERT( !(dest_size&3) );
420 
421     u8 * dest = dest_ptr;
422     memset(dest,0,dest_size);
423 
424     while ( seg != seg_end )
425     {
426 	const u32 offset = ntohl(seg->offset);
427 	const u32 size   = ntohl(seg->size);
428 	if (!size)
429 	    break;
430 
431 	noPRINT("SEG: %p: %x+%x\n",seg,offset,size);
432 
433 	if ( (u8*)seg >= (u8*)seg_end || offset + size > dest_size )
434 	{
435 	    PRINT("seg=%p..%p, off=%x, size=%x, end=%x/%x\n",
436 		seg, seg_end, offset, size, offset + size, dest_size );
437 	    return ERROR0(ERR_WIA_INVALID,
438 		"Invalid WIA data segment: %s\n",sf->f.fname);
439 	}
440 
441 	memcpy( dest + offset, seg->data, size );
442 	seg = (wia_segment_t*)( seg->data + size );
443     }
444 
445     return ERR_OK;
446 }
447 
448 ///////////////////////////////////////////////////////////////////////////////
449 
read_data(SuperFile_t * sf,u64 file_offset,u32 file_data_size,bool have_except,void * inbuf,u32 inbuf_size)450 static enumError read_data
451 (
452     SuperFile_t		* sf,		// source file
453     u64			file_offset,	// file offset
454     u32			file_data_size,	// expected file data size
455     bool		have_except,	// true: data contains exception list and
456 					// the exception list is stored in 'tempbuf'
457     void		* inbuf,	// valid pointer to data
458     u32			inbuf_size	// size of data to read
459 )
460 {
461     DASSERT( sf );
462     DASSERT( sf->wia );
463     DASSERT( inbuf );
464     DASSERT( inbuf_size );
465 
466     wia_controller_t * wia = sf->wia;
467     DASSERT(wia);
468 
469     if ( file_data_size > 2 * tempbuf_size )
470 	return ERROR0(ERR_WIA_INVALID,
471 	    "WIA chunk size to large: %s\n",sf->f.fname);
472 
473     bool align_except = false;
474     u32 data_bytes_read = 0;
475 
476     u8  * dest    = have_except ? tempbuf : inbuf;
477     u32 dest_size = have_except ? tempbuf_size : inbuf_size;
478 
479     switch ((wd_compression_t)wia->disc.compression)
480     {
481       //----------------------------------------------------------------------
482 
483       case WD_COMPR_NONE:
484       {
485 	noPRINT(">> READ NONE: %9llx, %6x => %6x, except=%d, dest=%p, iobuf=%p\n",
486 		file_offset, file_data_size, inbuf_size, have_except, dest, tempbuf );
487 
488 	if ( file_data_size > dest_size )
489 	    return ERROR0(ERR_WIA_INVALID,
490 		"WIA chunk size to large: %s\n",sf->f.fname);
491 
492 	enumError err = ReadAtF( &sf->f, file_offset, dest, file_data_size );
493 	if (err)
494 	    return err;
495 	data_bytes_read = file_data_size;
496 	align_except = true;
497       }
498       break;
499 
500       //----------------------------------------------------------------------
501 
502       case WD_COMPR_PURGE:
503       {
504 	enumError err = ReadAtF( &sf->f, file_offset, tempbuf, file_data_size );
505 	if (err)
506 	    return err;
507 
508 	if ( file_data_size <= WII_HASH_SIZE )
509 	    return ERROR0(ERR_WIA_INVALID,
510 		"Invalid WIA data size: %s\n",sf->f.fname);
511 
512 	file_data_size -= WII_HASH_SIZE;
513 	sha1_hash_t hash;
514 	SHA1(tempbuf,file_data_size,hash);
515 	if (memcmp(hash,tempbuf+file_data_size,WII_HASH_SIZE))
516 	{
517 	    HEXDUMP16(0,0,inbuf,16);
518 	    HEXDUMP(0,0,0,-WII_HASH_SIZE,tempbuf+file_data_size,WII_HASH_SIZE);
519 	    HEXDUMP(0,0,0,-WII_HASH_SIZE,hash,WII_HASH_SIZE);
520 	    return ERROR0(ERR_WIA_INVALID,
521 		"SHA1 check for WIA data segment failed: %s\n",sf->f.fname);
522 	}
523 
524 	const u32 except_size
525 	    = have_except ? calc_except_size(tempbuf,wia->chunk_groups) + 3 & ~(u32)3 : 0;
526 	wia_segment_t * seg = (wia_segment_t*)( tempbuf + except_size );
527 	err = expand_segments( sf, seg, tempbuf+file_data_size,
528 				inbuf, inbuf_size );
529 	if (err)
530 	    return err;
531 	data_bytes_read = inbuf_size; // extraction is ok
532 	have_except = false; // no more exception handling needed
533       }
534       break;
535 
536       //----------------------------------------------------------------------
537 
538       case WD_COMPR_BZIP2:
539 
540  #ifdef NO_BZIP2
541 	return ERROR0(ERR_NOT_IMPLEMENTED,
542 			"No WIA/BZIP2 support for this release! Sorry!\n");
543  #else
544       {
545 	ASSERT(sf->f.fp);
546 	enumError err = SeekF(&sf->f,file_offset);
547 	if (err)
548 	    return err;
549 
550 	BZIP2_t bz;
551 	err = DecBZIP2_Open(&bz,&sf->f);
552 	if (err)
553 	    return err;
554 
555 	err = DecBZIP2_Read(&bz,dest,dest_size,&data_bytes_read);
556 	if (err)
557 	    return err;
558 
559 	err = DecBZIP2_Close(&bz);
560 	if (err)
561 	    return err;
562       }
563       break;
564 
565  #endif // !NO_BZIP2
566 
567       //----------------------------------------------------------------------
568 
569       case WD_COMPR_LZMA:
570       {
571 	noPRINT("SEEK TO %llx=%llu\n",file_offset,file_offset);
572 	enumError err = SeekF(&sf->f,file_offset);
573 	if (err)
574 	    return err;
575 
576 	err = DecLZMA_File2Buf( sf, file_data_size, dest, dest_size,
577 				&data_bytes_read, wia->disc.compr_data );
578 	if (err)
579 	    return err;
580       }
581       break;
582 
583       //----------------------------------------------------------------------
584 
585       case WD_COMPR_LZMA2:
586       {
587 	enumError err = SeekF(&sf->f,file_offset);
588 	if (err)
589 	    return err;
590 
591 	err = DecLZMA2_File2Buf( sf, file_data_size, dest, dest_size,
592 				&data_bytes_read, wia->disc.compr_data );
593 	if (err)
594 	    return err;
595       }
596       break;
597 
598       //----------------------------------------------------------------------
599 
600       // no default case defined
601       //	=> compiler checks the existence of all enum values
602 
603       case WD_COMPR__N:
604 	ASSERT(0);
605     }
606 
607     if (have_except)
608     {
609 	u32 except_size = calc_except_size(dest,wia->chunk_groups);
610 	if (align_except)
611 	    except_size = except_size + 3 & ~(u32)3;
612 	noPRINT("%u exceptions, size=%u\n",be16(dest),except_size);
613 
614 	data_bytes_read -= except_size;
615 	DASSERT( dest != inbuf );
616 	DASSERT( dest == tempbuf );
617 	memcpy( inbuf, dest + except_size, inbuf_size );
618 	//HEXDUMP16(0,1,inbuf,16);
619     }
620 
621     if ( data_bytes_read != inbuf_size )
622 	    return ERROR0(ERR_WIA_INVALID,
623 		"WIA chunk size miss match [%x,%x]: %s\n",
624 			data_bytes_read, inbuf_size, sf->f.fname );
625 
626     return ERR_OK;
627 }
628 
629 ///////////////////////////////////////////////////////////////////////////////
630 
read_gdata(SuperFile_t * sf,u32 group,u32 size,bool have_except)631 static enumError read_gdata
632 (
633     SuperFile_t		* sf,		// source file
634     u32			group,		// group index
635     u32			size,		// group size
636     bool		have_except	// true: data contains exception list and
637 					// the exception list is stored in tempbuf
638 )
639 {
640     DASSERT(sf);
641     DASSERT(sf->wia);
642     wia_controller_t * wia = sf->wia;
643 
644     if ( group >= wia->group_used || size > wia->gdata_size )
645 	return ERROR0(ERR_WIA_INVALID,
646 			"Access to invalid group: %s\n",sf->f.fname);
647 
648 
649     wia->gdata_group = group;
650     wia_group_t * grp = wia->group + group;
651     u32 gsize = ntohl(grp->data_size);
652     if (gsize)
653     {
654 	memset(wia->gdata+size,0,wia->gdata_size-size);
655 	return read_data( sf, (u64)ntohl(grp->data_off4)<<2,
656 			gsize, have_except, wia->gdata, size );
657     }
658 
659     memset(wia->gdata,0,wia->gdata_size);
660     if (have_except)
661 	memset(tempbuf,0,sizeof(wia_except_list_t));
662     return ERR_OK;
663 }
664 
665 ///////////////////////////////////////////////////////////////////////////////
666 
read_part_gdata(SuperFile_t * sf,u32 part_index,u32 group,u32 size)667 static enumError read_part_gdata
668 (
669     SuperFile_t		* sf,		// source file
670     u32			part_index,	// partition index
671     u32			group,		// group index
672     u32			size		// group size
673 )
674 {
675     DASSERT(sf);
676     DASSERT(sf->wia);
677 
678     noPRINT("SIZE = %x -> %x\n", size, size / WII_SECTOR_SIZE * WII_SECTOR_DATA_SIZE );
679     enumError err = read_gdata( sf, group,
680 				size / WII_SECTOR_SIZE * WII_SECTOR_DATA_SIZE, true );
681     if (err)
682 	return err;
683 
684     wia_controller_t * wia = sf->wia;
685     DASSERT( part_index < wia->disc.n_part );
686     if ( wia->gdata_part != part_index )
687     {
688 	wia->gdata_part = part_index;
689 	wd_aes_set_key(&wia->akey,wia->part[part_index].part_key);
690     }
691 
692 
693     //----- process hash and exceptions
694 
695     u8 * hashtab0 = tempbuf + tempbuf_size - WII_GROUP_HASH_SIZE * wia->chunk_groups;
696     u8 * hashtab = hashtab0;
697 
698     int g;
699     wia_except_list_t * except_list = (wia_except_list_t*)tempbuf;
700     u8 * gdata = wia->gdata;
701     for ( g = 0;
702 	  g < wia->chunk_groups;
703 	  g++, gdata += WII_GROUP_DATA_SIZE, hashtab += WII_GROUP_HASH_SIZE )
704     {
705 	DASSERT( hashtab + WII_GROUP_HASH_SIZE <= tempbuf + tempbuf_size );
706 	memset(hashtab,0,WII_GROUP_HASH_SIZE);
707 	wd_calc_group_hashes(gdata,hashtab,0,0);
708 
709 	u32 n_except = ntohs(except_list->n_exceptions);
710 	wia_exception_t * except = except_list->exception;
711 	if (n_except)
712 	{
713 	 #if WATCH_GROUP >= 0 && defined(TEST)
714 	    if ( wia->gdata_group == WATCH_GROUP && g == WATCH_SUB_GROUP )
715 	    {
716 		FILE * f = fopen("pool/read.except.dump","wb");
717 		if (f)
718 		{
719 		    const size_t sz = sizeof(wia_exception_t);
720 		    HexDump(f,0,0,9,sz,except_list,sizeof(except_list));
721 		    HexDump(f,0,0,9,sz,except_list->exception,n_except*sz);
722 		    fclose(f);
723 		}
724 	    }
725 	 #endif
726 
727 	    noPRINT("%u exceptions for group %u\n",n_except,group);
728 	    for ( ; n_except > 0; n_except--, except++  )
729 	    {
730 		noPRINT_IF(wia->gdata_group == WATCH_GROUP && g == WATCH_SUB_GROUP,
731 			    "EXCEPT: %4x: %02x %02x %02x %02x\n",
732 			    ntohs(except->offset), except->hash[0],
733 			    except->hash[1], except->hash[2], except->hash[3] );
734 		DASSERT( ntohs(except->offset) + WII_HASH_SIZE <= WII_GROUP_HASH_SIZE );
735 		memcpy( hashtab + ntohs(except->offset), except->hash, WII_HASH_SIZE );
736 	    }
737 	}
738 	except_list = (wia_except_list_t*)except;
739 	DASSERT( (u8*)except_list < hashtab0 );
740     }
741     DASSERT( hashtab == tempbuf + tempbuf_size );
742 
743  #if WATCH_GROUP >= 0 && defined(TEST)
744     if ( wia->gdata_group == WATCH_GROUP )
745     {
746 	PRINT("##### WATCH GROUP #%u #####\n",WATCH_GROUP);
747 	FILE * f = fopen("pool/read.calc.dump","wb");
748 	if (f)
749 	{
750 	    HexDump(f,0,0,9,16,hashtab,WII_GROUP_HASH_SIZE*wia->chunk_groups);
751 	    fclose(f);
752 	}
753     }
754  #endif
755 
756 
757     //----- encrpyt and join data
758 
759  #if WATCH_GROUP >= 0 && defined(TEST)
760     if ( wia->gdata_group == WATCH_GROUP )
761     {
762 	FILE * f = fopen("pool/read.split.dump","wb");
763 	if (f)
764 	{
765 	    HexDump(f,0,0,9,16,wia->gdata,WII_GROUP_DATA_SIZE*wia->chunk_groups);
766 	    fclose(f);
767 	}
768 
769 	f = fopen("pool/read.hash.dump","wb");
770 	if (f)
771 	{
772 	    HexDump(f,0,0,9,16,hashtab0,WII_GROUP_HASH_SIZE*wia->chunk_groups);
773 	    fclose(f);
774 	}
775     }
776  #endif
777 
778     if ( wia->encrypt )
779 	wd_encrypt_sectors(0,&wia->akey,wia->gdata,
780 				hashtab0,wia->gdata,wia->chunk_sectors);
781     else
782 	wd_join_sectors(wia->gdata,hashtab0,wia->gdata,wia->chunk_sectors);
783 
784 
785  #if WATCH_GROUP >= 0 && defined(TEST)
786     if ( wia->gdata_group == WATCH_GROUP )
787     {
788 	FILE * f = fopen("pool/read.all.dump","wb");
789 	if (f)
790 	{
791 	    HexDump(f,0,0,9,16,wia->gdata,wia->chunk_size);
792 	    fclose(f);
793 	}
794     }
795  #endif
796 
797     return ERR_OK;
798 }
799 
800 //
801 ///////////////////////////////////////////////////////////////////////////////
802 ///////////////			    ReadWIA()			///////////////
803 ///////////////////////////////////////////////////////////////////////////////
804 
ReadWIA(struct SuperFile_t * sf,off_t off,void * p_buf,size_t count)805 enumError ReadWIA
806 (
807     struct SuperFile_t	* sf,		// source file
808     off_t		off,		// file offset
809     void		* p_buf,	// destination buffer
810     size_t		count		// number of bytes to read
811 )
812 {
813     ASSERT(sf);
814     ASSERT(sf->wia);
815 
816     TRACE("#W# -----\n");
817     TRACE(TRACE_RDWR_FORMAT, "#W# ReadWIA()",
818 		GetFD(&sf->f), GetFP(&sf->f),
819 		(u64)off, (u64)off+count, count, "" );
820 
821     char * buf = p_buf;
822     memset(buf,0,count);
823 
824     if (SIGINT_level>1)
825 	return ERR_INTERRUPT;
826 
827     wia_controller_t * wia = sf->wia;
828     if (!wia->is_valid)
829 	return ERR_WIA_INVALID;
830 
831     const u64 off2 = off + count;
832     const wd_memmap_item_t * item = wia->memmap.item;
833     const wd_memmap_item_t * item_end = item + wia->memmap.used;
834 
835     for ( ; item < item_end && item->offset < off2; item++ )
836     {
837       const u64 end = item->offset + item->size;
838       noTRACE("> off=%llx..%llx, item=%llx..%llx\n", (u64)off, off2, item->offset, end );
839       if ( item->offset < off2 && end > off )
840       {
841 	u64 overlap1 = item->offset > off ? item->offset : off;
842 	const u64 overlap2 = end < off2 ? end : off2;
843 	noTRACE(" -> %llx .. %llx\n",overlap1,overlap2);
844 
845 	switch (item->mode)
846 	{
847 	 case WIA_MM_HEADER_DATA:
848 	    DASSERT(item->data);
849 	    noPRINT("> COPY DATA: %9llx .. %9llx\n",overlap1,overlap2);
850 	    memcpy( buf + (overlap1-off),
851 		    (u8*)item->data + (overlap1-item->offset),
852 		    overlap2 - overlap1 );
853 	    break;
854 
855 
856 	 case WIA_MM_RAW_GDATA:
857 	    {
858 		DASSERT( item->index >= 0 && item->index < wia->raw_data_used );
859 		wia_raw_data_t * rdata = wia->raw_data + item->index;
860 		while ( overlap1 < overlap2 )
861 		{
862 		    // align content on WII_SECTOR_SIZE!
863 
864 		    const int base_sector = item->offset / WII_SECTOR_SIZE;
865 		    const int sector      = overlap1 / WII_SECTOR_SIZE - base_sector;
866 		    const int base_group  = sector / wia->chunk_sectors;
867 		    const int group       = base_group + ntohl(rdata->group_index);
868 
869 		    u64 base_off = base_sector * (u64)WII_SECTOR_SIZE
870 				 + base_group  * (u64)wia->chunk_size;
871 		    u64 end_off  = base_off + wia->chunk_size;
872 		    if ( end_off > end )
873 			 end_off = end;
874 
875 		    noPRINT("\tWIA_MM_RAW_GDATA: s=%d,%d, g=%d,%d/%d, off=%llx..%llx/%llx\n",
876 			    base_sector, sector,
877 			    base_group, group, wia->group_used,
878 			    base_off, end_off, end );
879 		    DASSERT( base_group < ntohl(rdata->n_groups) );
880 		    DASSERT( group >= 0 && group < wia->group_used );
881 
882 		    if ( group != wia->gdata_group )
883 		    {
884 			noPRINT("----- SETUP RAW%4u GROUP %4u/%4u>%4u, off=%9llx, size=%6llx\n",
885 				item->index, base_group, ntohl(rdata->n_groups), group,
886 				base_off, end_off - base_off );
887 			enumError err = read_gdata( sf, group, end_off - base_off, false );
888 			DASSERT( group == wia->gdata_group );
889 			if (err)
890 			    return err;
891 		    }
892 
893 		    if ( end_off > overlap2 )
894 			 end_off = overlap2;
895 
896 		    noPRINT("> READ RAW DATA:"
897 			    " %llx .. %llx -> %llx + %llx, base = %9llx + %6x\n",
898 				overlap1, end_off,
899 				overlap1 - base_off, end_off - overlap1,
900 				base_off, wia->gdata_used );
901 		    memcpy( buf + (overlap1-off),
902 			    wia->gdata + ( overlap1 - base_off ),
903 			    end_off - overlap1 );
904 		    overlap1 = end_off;
905 		}
906 	    }
907 	    break;
908 
909 
910 	 case WIA_MM_PART_GDATA_0:
911 	 case WIA_MM_PART_GDATA_1:
912 	    {
913 		DASSERT( item->index >= 0 && item->index < wia->disc.n_part );
914 		wia_part_t * part = wia->part + item->index;
915 		wia_part_data_t * pd = part->pd + ( item->mode - WIA_MM_PART_GDATA_0 );
916 
917 		while ( overlap1 < overlap2 )
918 		{
919 		    int group = ( overlap1 - item->offset ) / wia->chunk_size;
920 		    DASSERT( group < pd->n_groups );
921 		    u64 base_off = item->offset + group * (u64)wia->chunk_size;
922 		    u64 end_off  = base_off + wia->chunk_size;
923 		    if ( end_off > end )
924 			 end_off = end;
925 
926 		    group += pd->group_index;
927 		    DASSERT( group >= 0 && group < wia->group_used );
928 
929 		    if ( group != wia->gdata_group || item->index != wia->gdata_part )
930 		    {
931 			noPRINT("----- SETUP PART%3u GROUP %4u/%4u>%4u, off=%9llx, size=%6llx\n",
932 				item->index,
933 				group - pd->group_index, pd->n_groups, group,
934 				base_off, end_off-base_off );
935 			enumError err
936 			    = read_part_gdata( sf, item->index, group, end_off-base_off );
937 			if (err)
938 			    return err;
939 		    }
940 
941 		    if ( end_off > overlap2 )
942 			 end_off = overlap2;
943 
944 		    noPRINT("> READ PART DATA:"
945 			    " %llx .. %llx -> %llx + %llx, base = %9llx + %6x\n",
946 				overlap1, end_off,
947 				overlap1 - base_off, end_off - overlap1,
948 				base_off, wia->gdata_used );
949 		    memcpy( buf + (overlap1-off),
950 			    wia->gdata + ( overlap1 - base_off ),
951 			    end_off - overlap1 );
952 		    overlap1 = end_off;
953 		}
954 	    }
955 	    break;
956 
957 
958 	  default:
959 	    return ERROR0(ERR_INTERNAL,0);
960 	}
961       }
962     }
963     return ERR_OK;
964 }
965 
966 //
967 ///////////////////////////////////////////////////////////////////////////////
968 ///////////////			DataBlockWIA()			///////////////
969 ///////////////////////////////////////////////////////////////////////////////
970 
DataBlockWIA(SuperFile_t * sf,off_t off,size_t hint_align,off_t * block_size)971 off_t DataBlockWIA
972 	( SuperFile_t * sf, off_t off, size_t hint_align, off_t * block_size )
973 {
974     // [[2do]] [datablock] : analyze chunks
975 
976     ASSERT(sf);
977     ASSERT(sf->wia);
978 
979     wia_controller_t * wia = sf->wia;
980     if (!wia->is_valid)
981 	return DataBlockStandard(sf,off,hint_align,block_size);
982 
983     const wd_memmap_item_t * item = wia->memmap.item;
984     const wd_memmap_item_t * item_end = item + wia->memmap.used;
985 
986     for ( ; item < item_end && off >= item->offset + item->size; item++ )
987 	PRINT("%llx %llx+%llx\n",(u64)off,item->offset,item->size);
988 
989     if ( off < item->offset )
990 	 off = item->offset;
991 
992     if (block_size)
993     {
994 	if ( hint_align < HD_BLOCK_SIZE )
995 	    hint_align = HD_BLOCK_SIZE;
996 
997 	item_end--;
998 	while ( item < item_end )
999 	{
1000 	    // [[2do]] this loops ends always with item==item_end
1001 	    if ( item[1].offset - (item->offset + item->size) >= hint_align )
1002 		break;
1003 	    item++;
1004 	}
1005 	*block_size = item->offset + item->size - off;
1006     }
1007 
1008     return off;
1009 }
1010 
1011 //
1012 ///////////////////////////////////////////////////////////////////////////////
1013 ///////////////			setup read WIA			///////////////
1014 ///////////////////////////////////////////////////////////////////////////////
1015 
SetupReadWIA(struct SuperFile_t * sf)1016 enumError SetupReadWIA
1017 (
1018     struct SuperFile_t	* sf		// file to setup
1019 )
1020 {
1021     PRINT("#W# SetupReadWIA(%p) file=%d/%p, wc=%p wbfs=%p v=%s/%s\n",
1022 		sf, GetFD(&sf->f), GetFP(&sf->f),
1023 		sf->wc, sf->wbfs,
1024 		PrintVersionWIA(0,0,WIA_VERSION_READ_COMPATIBLE),
1025 		PrintVersionWIA(0,0,WIA_VERSION) );
1026     ASSERT(sf);
1027 
1028     if (sf->wia)
1029 	return ERROR0(ERR_INTERNAL,0);
1030 
1031 
1032     //----- setup controller
1033 
1034     wia_controller_t * wia = CALLOC(1,sizeof(*wia));
1035     sf->wia = wia;
1036     wia->gdata_group = wia->gdata_part = -1;  // reset gdata
1037     wia->encrypt = encoding & ENCODE_ENCRYPT || !( encoding & ENCODE_DECRYPT );
1038 
1039     AllocBufferWIA(wia,WIA_BASE_CHUNK_SIZE,false,false);
1040 
1041 
1042     //----- read and check file header
1043 
1044     wia_file_head_t *fhead = &wia->fhead;
1045     enumError err = ReadAtF(&sf->f,0,fhead,sizeof(*fhead));
1046     if (err)
1047 	return err;
1048 
1049     const bool is_wia = IsWIA(fhead,sizeof(*fhead),0,0,0);
1050     wia_ntoh_file_head(fhead,fhead);
1051     if ( !is_wia || fhead->disc_size > MiB )
1052 	return ERROR0(ERR_WIA_INVALID,"Invalid file header: %s\n",sf->f.fname);
1053 
1054     if ( WIA_VERSION < fhead->version_compatible
1055 	|| fhead->version < WIA_VERSION_READ_COMPATIBLE )
1056     {
1057 	if ( WIA_VERSION_READ_COMPATIBLE < WIA_VERSION )
1058 	    return ERROR0(ERR_WIA_INVALID,
1059 		"WIA version %s is not supported (compatible %s .. %s): %s\n",
1060 		PrintVersionWIA(0,0,fhead->version),
1061 		PrintVersionWIA(0,0,WIA_VERSION_READ_COMPATIBLE),
1062 		PrintVersionWIA(0,0,WIA_VERSION),
1063 		sf->f.fname );
1064 	else
1065 	    return ERROR0(ERR_WIA_INVALID,
1066 		"WIA version %s is not supported (%s expected): %s\n",
1067 		PrintVersionWIA(0,0,fhead->version),
1068 		PrintVersionWIA(0,0,WIA_VERSION),
1069 		sf->f.fname );
1070     }
1071 
1072 
1073     //----- check file size
1074 
1075     if ( sf->f.st.st_size < fhead->wia_file_size )
1076 	SetupSplitFile(&sf->f,OFT_WIA,0);
1077 
1078     if ( sf->f.st.st_size != fhead->wia_file_size )
1079 	return ERROR0(ERR_WIA_INVALID,
1080 		"Wrong file size %llu (%llu expected): %s\n",
1081 		(u64)sf->f.st.st_size, fhead->wia_file_size, sf->f.fname );
1082 
1083 
1084     //----- read and check disc info
1085 
1086     DASSERT( fhead->disc_size   <= tempbuf_size );
1087     DASSERT( sizeof(wia_disc_t) <= tempbuf_size );
1088 
1089     memset(tempbuf,0,sizeof(wia_disc_t));
1090     ReadAtF(&sf->f,sizeof(*fhead),tempbuf,fhead->disc_size);
1091     if (err)
1092 	return err;
1093 
1094     sha1_hash_t hash;
1095     SHA1(tempbuf,fhead->disc_size,hash);
1096     if (memcmp(hash,fhead->disc_hash,sizeof(hash)))
1097 	return ERROR0(ERR_WIA_INVALID,
1098 	    "Hash error for disc area: %s\n",sf->f.fname);
1099 
1100     wia_disc_t *disc = &wia->disc;
1101     wia_ntoh_disc(disc,(wia_disc_t*)tempbuf);
1102 
1103     AllocBufferWIA(wia,disc->chunk_size,false,false);
1104     if ( wia->chunk_size != disc->chunk_size )
1105 	return ERROR0(ERR_WIA_INVALID,
1106 	    "Only multiple of %s, but not %s, are supported as a chunk size: %s\n",
1107 		wd_print_size_1024(0,0,wia->chunk_size,false),
1108 		wd_print_size_1024(0,0,disc->chunk_size,false), sf->f.fname );
1109 
1110 
1111     //----- read and check partition header
1112 
1113     const u32 load_part_size = disc->part_t_size * disc->n_part;
1114     if ( load_part_size > tempbuf_size )
1115 	return ERROR0(ERR_WIA_INVALID,
1116 	    "Total partition header size to large: %s\n",sf->f.fname);
1117 
1118     ReadAtF(&sf->f,disc->part_off,tempbuf,load_part_size);
1119     if (err)
1120 	return err;
1121 
1122     SHA1(tempbuf,load_part_size,hash);
1123     if (memcmp(hash,disc->part_hash,sizeof(hash)))
1124 	return ERROR0(ERR_WIA_INVALID,
1125 	    "Hash error for partition header: %s\n",sf->f.fname);
1126 
1127     wia->part = CALLOC(disc->n_part,sizeof(wia_part_t));
1128 
1129     int ip;
1130     const u8 * src = tempbuf;
1131     int shortage = sizeof(wia_part_t) - disc->part_t_size;
1132     for ( ip = 0; ip < disc->n_part; ip++ )
1133     {
1134 	wia_part_t *part = wia->part + ip;
1135 	wia_ntoh_part(part,(wia_part_t*)src);
1136 	if ( shortage > 0 )
1137 	    memset( (u8*)part + disc->part_t_size, 0, shortage );
1138 	src += disc->part_t_size;
1139     }
1140 
1141 
1142     //----- check compression method
1143 
1144     switch ((wd_compression_t)disc->compression)
1145     {
1146 	case WD_COMPR__N:
1147 	case WD_COMPR_NONE:
1148 	case WD_COMPR_PURGE:
1149 	    // nothing to do
1150 	    break;
1151 
1152 	case WD_COMPR_BZIP2:
1153 	 #ifdef NO_BZIP2
1154 	    return ERROR0(ERR_NOT_IMPLEMENTED,
1155 			"No bzip2 support for this release! Sorry!\n");
1156 	 #else
1157 	    wia->memory_usage += CalcMemoryUsageBZIP2(disc->compr_level,false);
1158 	    PRINT("DISABLE CACHE & OPEN STREAM\n");
1159 	    ClearCache(&sf->f);
1160 	    OpenStreamFile(&sf->f);
1161 	 #endif
1162 	    break;
1163 
1164 	case WD_COMPR_LZMA:
1165 	    wia->memory_usage += CalcMemoryUsageLZMA(disc->compr_level,false);
1166 	    break;
1167 
1168 	case WD_COMPR_LZMA2:
1169 	    wia->memory_usage += CalcMemoryUsageLZMA2(disc->compr_level,false);
1170 	    break;
1171 
1172 	default:
1173 	    return ERROR0(ERR_NOT_IMPLEMENTED,
1174 			"No support for compression method #%u (%x/hex, %s)\n",
1175 			disc->compression, disc->compression,
1176 			wd_get_compression_name(disc->compression,"unknown") );
1177     }
1178 
1179 
1180     //----- read and check raw data table
1181 
1182     PRINT("** RAW DATA TABLE: n=%u, off=%llx, size=%x\n",
1183 		disc->n_raw_data, disc->raw_data_off, disc->raw_data_size );
1184 
1185     if (disc->n_raw_data)
1186     {
1187 	wia->raw_data_used = disc->n_raw_data;
1188 	const u32 raw_data_len = wia->raw_data_used * sizeof(wia_raw_data_t);
1189 	wia->raw_data = MALLOC(raw_data_len);
1190 
1191 	err = read_data( sf, disc->raw_data_off, disc->raw_data_size,
1192 			 0, wia->raw_data, raw_data_len );
1193 	if (err)
1194 	    return err;
1195 
1196 	wia->memory_usage += wia->raw_data_size * sizeof(*wia->raw_data);
1197     }
1198 
1199 
1200     //----- read and check group table
1201 
1202     PRINT("** GROUP TABLE: n=%u, off=%llx, size=%x\n",
1203 		disc->n_groups, disc->group_off, disc->group_size );
1204 
1205     if (disc->n_groups)
1206     {
1207 	wia->group_used = disc->n_groups;
1208 	const u32 group_len = wia->group_used * sizeof(wia_group_t);
1209 	wia->group = MALLOC(group_len);
1210 
1211 	err = read_data( sf, disc->group_off, disc->group_size,
1212 			 0, wia->group, group_len );
1213 	if (err)
1214 	    return err;
1215 
1216 	wia->memory_usage += wia->group_size * sizeof(*wia->group);
1217     }
1218 
1219 
1220     //----- setup memory map
1221 
1222     wd_memmap_item_t * it;
1223 
1224     it = wd_insert_memmap(&wia->memmap,WIA_MM_HEADER_DATA,0,sizeof(disc->dhead));
1225     DASSERT(it);
1226     it->data = disc->dhead;
1227     snprintf(it->info,sizeof(it->info),"Disc header");
1228 
1229     it = wd_insert_memmap(&wia->memmap,WIA_MM_EOF,wia->fhead.iso_file_size,0);
1230     DASSERT(it);
1231     snprintf(it->info,sizeof(it->info),"--- end of file ---");
1232 
1233     const int g_fw = sprintf(iobuf,"%u",disc->n_groups);
1234 
1235     //----- setup memory map: partitions
1236 
1237     wia_part_t * part = wia->part;
1238     for ( ip = 0; ip < disc->n_part; ip++, part++ )
1239     {
1240 	int id;
1241 	for ( id = 0; id < sizeof(part->pd)/sizeof(part->pd[0]); id++ )
1242 	{
1243 	    wia_part_data_t * pd = part->pd + id;
1244 	    const u64 size = pd->n_sectors * (u64)WII_SECTOR_SIZE;
1245 	    if (size)
1246 	    {
1247 		it = wd_insert_memmap(&wia->memmap,WIA_MM_PART_GDATA_0+id,
1248 				pd->first_sector * (u64)WII_SECTOR_SIZE, size );
1249 		DASSERT(it);
1250 		it->index = ip;
1251 		const u64 compr_size = calc_group_size(wia,pd->group_index,pd->n_groups);
1252 		snprintf(it->info,sizeof(it->info),
1253 				"Part%3u,%5u chunk%s @%0*u, %s -> %s",
1254 				it->index,
1255 				pd->n_groups, pd->n_groups == 1 ? " " : "s",
1256 				g_fw, pd->group_index,
1257 				wd_print_size_1024(0,0,size,true),
1258 				wd_print_size_1024(0,0,compr_size,true) );
1259 	    }
1260 	}
1261     }
1262 
1263 
1264     //----- setup memory map: raw data
1265 
1266     for ( ip = 0; ip < wia->raw_data_used; ip++ )
1267     {
1268 	wia_raw_data_t * rd = wia->raw_data + ip;
1269 	const u64 size = ntoh64(rd->raw_data_size);
1270 	it = wd_insert_memmap(&wia->memmap,WIA_MM_RAW_GDATA,
1271 				ntoh64(rd->raw_data_off), size );
1272 	DASSERT(it);
1273 	it->index = ip;
1274 	const u32 group_index = ntohl(rd->group_index);
1275 	const u32 n_groups = ntohl(rd->n_groups);
1276 	const u64 compr_size = calc_group_size(wia,group_index,n_groups);
1277 	snprintf(it->info,sizeof(it->info),
1278 			"RAW%4u,%5u chunk%s @%0*u, %s -> %s",
1279 			it->index,
1280 			n_groups, n_groups == 1 ? " " : "s",
1281 			g_fw, group_index,
1282 			wd_print_size_1024(0,0,size,true),
1283 			wd_print_size_1024(0,0,compr_size,true) );
1284     }
1285 
1286 
1287     //----- logging
1288 
1289     if ( verbose > 2 )
1290     {
1291 	printf("  Compression mode: %s (method %s, level %u, chunk size %u MiB, mem ~%u MiB)\n",
1292 		wd_print_compression(0,0,disc->compression,
1293 				disc->compr_level,disc->chunk_size,2),
1294 		wd_get_compression_name(disc->compression,"?"),
1295 		disc->compr_level, disc->chunk_size / MiB,
1296 		( wia->memory_usage + MiB/2 ) / MiB );
1297 	fflush(0);
1298     }
1299 
1300     if ( logging > 0 )
1301     {
1302 	printf("\nWIA memory map:\n\n");
1303 	wd_print_memmap(stdout,3,&wia->memmap);
1304 	putchar('\n');
1305     }
1306 
1307 
1308     //----- finish setup
1309 
1310     sf->file_size = fhead->iso_file_size;
1311     wia->is_valid = true;
1312     SetupIOD(sf,OFT_WIA,OFT_WIA);
1313 
1314     return ERR_OK;
1315 }
1316 
1317 //
1318 ///////////////////////////////////////////////////////////////////////////////
1319 ///////////////			  write helpers			///////////////
1320 ///////////////////////////////////////////////////////////////////////////////
1321 
calc_segments(wia_segment_t * seg,void * seg_end,const void * src_ptr,u32 src_size)1322 static wia_segment_t * calc_segments
1323 (
1324     wia_segment_t	* seg,		// destination segment pointer
1325     void		* seg_end,	// end of segment space
1326     const void		* src_ptr,	// pointer to source
1327     u32			src_size	// size of source
1328 )
1329 {
1330     DASSERT( seg );
1331     DASSERT( seg_end );
1332     DASSERT( src_ptr );
1333     DASSERT( src_size >= 8 );
1334     DASSERT( !(src_size&3) );
1335 
1336     const u32 * src = (u32*)src_ptr;
1337     const u32 * src_end  = src + src_size/4;
1338     while ( src_end > src && !src_end[-1] )
1339 	src_end--;
1340     const u32 * src_end2 = src + 2 >= src_end ? src : src_end - 2;
1341     noPRINT("SRC: %p, end=%zx,%zx\n", src, src_end2-src, src_end-src );
1342 
1343     while ( src < src_end )
1344     {
1345 	// skip null data
1346 	while ( src < src_end && !*src )
1347 	    src++;
1348 	if ( src == src_end )
1349 	    break;
1350 	const u32 * src_beg = src;
1351 
1352 	// find next hole
1353 	while ( src < src_end2 )
1354 	{
1355 	    if (src[2])
1356 		src += 3;
1357 	    else if (src[1])
1358 		src += 2;
1359 	    else if (src[0])
1360 		src++;
1361 	    else
1362 		break;
1363 	}
1364 	if ( src >= src_end2 )
1365 	    src = src_end;
1366 
1367 	const u32 offset	= (u8*)src_beg - (u8*)src_ptr;
1368 	seg->offset		= htonl(offset);
1369 	const u32 size		= (u8*)src - (u8*)src_beg;
1370 	seg->size		= htonl(size);
1371 	noPRINT("SEG: %p: %x+%x\n",seg,offset,size);
1372 
1373 	DASSERT(!(size&3));
1374 	DASSERT( seg->data + size < (u8*)seg_end );
1375 	memcpy(seg->data,src_beg,size);
1376 	seg = (wia_segment_t*)( seg->data + size );
1377     }
1378 
1379     if ( (u8*)seg > (u8*)seg_end )
1380 	ERROR0(ERR_INTERNAL,"buffer overflow");
1381 
1382     return seg;
1383 }
1384 
1385 ///////////////////////////////////////////////////////////////////////////////
1386 
write_data(struct SuperFile_t * sf,wia_except_list_t * except,const void * data_ptr,u32 data_size,int group,u32 * write_count)1387 static enumError write_data
1388 (
1389     struct SuperFile_t	* sf,		// destination file
1390     wia_except_list_t	* except,	// NULL or exception list
1391     const void		* data_ptr,	// NULL or u32-aligned pointer to data
1392     u32			data_size,	// size of data, u32-aligned
1393     int			group,		// >=0: write group data
1394     u32			* write_count	// not NULL: store written data count
1395 )
1396 {
1397     DASSERT( sf );
1398     DASSERT(data_ptr);
1399     DASSERT(!(data_size&3));
1400 
1401     wia_controller_t * wia = sf->wia;
1402     DASSERT(wia);
1403 
1404     u32 except_size = except ? calc_except_size(except,wia->chunk_groups) : 0;
1405     TRACE_IF( except_size > wia->chunk_groups * sizeof(wia_except_list_t),
1406 		"%zd exceptions in group %d, size=%u=0x%x\n",
1407 		( except_size - wia->chunk_groups * sizeof(wia_except_list_t) )
1408 			/ sizeof(wia_exception_t),
1409 		group, except_size, except_size );
1410 
1411     DefineProgressChunkSF(sf,data_size,data_size+except_size);
1412 
1413     u32 written = 0;
1414     switch((wd_compression_t)wia->disc.compression)
1415     {
1416       //----------------------------------------------------------------------
1417 
1418       case WD_COMPR_NONE:
1419       {
1420 	if (except_size)
1421 	{
1422 	    except_size = except_size + 3 & ~(u32)3; // u32 alignment
1423 	    enumError err = WriteAtF( &sf->f, wia->write_data_off, except, except_size );
1424 	    if (err)
1425 		return err;
1426 	    written += except_size;
1427 	}
1428 
1429 	if (data_size)
1430 	{
1431 	    enumError err = WriteAtF( &sf->f, wia->write_data_off + except_size,
1432 					data_ptr, data_size );
1433 	    if (err)
1434 		return err;
1435 	    written += data_size;
1436 	}
1437 
1438 	noPRINT(">> WRITE NONE: %9llx, %6x+%6x => %6x, grp %d\n",
1439 		    wia->write_data_off, except_size, data_size, written, group );
1440       }
1441       break;
1442 
1443       //----------------------------------------------------------------------
1444 
1445       case WD_COMPR_PURGE:
1446       {
1447 	if (except_size)
1448 	{
1449 	    except_size = except_size + 3 & ~(u32)3; // u32 alignment
1450 	    if ( (u8*)except != tempbuf )
1451 		memmove(tempbuf,except,except_size);
1452 	}
1453 
1454 	wia_segment_t * seg1 = (wia_segment_t*)(tempbuf+except_size);
1455 	wia_segment_t * seg2
1456 	    = calc_segments( seg1, tempbuf + tempbuf_size,
1457 				data_ptr, data_size );
1458 
1459 	if ( except_size || seg2 > seg1+1 )
1460 	{
1461 	    written = except_size + ( (ccp)seg2 - (ccp)seg1 );
1462 	    SHA1(tempbuf,written,tempbuf+written);
1463 	    written += WII_HASH_SIZE;
1464 
1465 	    enumError err = WriteAtF( &sf->f, wia->write_data_off, tempbuf, written );
1466 	    if (err)
1467 		return err;
1468 	}
1469 
1470 	noPRINT(">> WRITE PURGE: %9llx, %6x+%6x => %6x, grp %d\n",
1471 		    wia->write_data_off, except_size, data_size, written, group );
1472       }
1473       break;
1474 
1475       //----------------------------------------------------------------------
1476 
1477       case WD_COMPR_BZIP2:
1478  #ifdef NO_BZIP2
1479 	return ERROR0(ERR_NOT_IMPLEMENTED,
1480 			"No WIA/BZIP2 support for this release! Sorry!\n");
1481  #else
1482       {
1483 	ASSERT(sf->f.fp);
1484 	enumError err = SeekF(&sf->f,wia->write_data_off);
1485 	if (err)
1486 	    return err;
1487 
1488 	BZIP2_t bz;
1489 	err = EncBZIP2_Open(&bz,&sf->f,opt_compr_level);
1490 	if (err)
1491 	    return err;
1492 
1493 	err = EncBZIP2_Write(&bz,except,except_size);
1494 	if (err)
1495 	    return err;
1496 
1497 	err = EncBZIP2_Write(&bz,data_ptr,data_size);
1498 	if (err)
1499 	    return err;
1500 
1501 	err = EncBZIP2_Close(&bz,&written);
1502 	if (err)
1503 	    return err;
1504 
1505 	noPRINT(">> WRITE BZIP2: %9llx, %6x+%6x => %6x, grp %d\n",
1506 		    wia->write_data_off, except_size, data_size, written, group );
1507 
1508 	sf->f.max_off = wia->write_data_off + written;
1509       }
1510       break;
1511  #endif // !NO_BZIP2
1512 
1513       //----------------------------------------------------------------------
1514 
1515       case WD_COMPR_LZMA:
1516       case WD_COMPR_LZMA2:
1517       {
1518 	enumError err = SeekF(&sf->f,wia->write_data_off);
1519 	if (err)
1520 	    return err;
1521 
1522 	DataArea_t area[3], *ap = area;
1523 	if (except_size)
1524 	{
1525 	    ap->data = (u8*)except;
1526 	    ap->size = except_size;
1527 	    ap++;
1528 	}
1529 	if (data_size)
1530 	{
1531 	    ap->data = data_ptr;
1532 	    ap->size = data_size;
1533 	    ap++;
1534 	}
1535 	ap->data = 0;
1536 
1537 	DataList_t list;
1538 	SetupDataList(&list,area);
1539 
1540 	err = wia->disc.compression == WD_COMPR_LZMA
1541 		? EncLZMA_List2File (0,sf,opt_compr_level,false,true,&list,&written)
1542 		: EncLZMA2_List2File(0,sf,opt_compr_level,false,true,&list,&written);
1543 	if (err)
1544 	    return err;
1545 
1546 	noPRINT(">> WRITE LZMA: %9llx, %6x+%6x => %6x, grp %d\n",
1547 		    wia->write_data_off, except_size, data_size, written, group );
1548       }
1549       break;
1550 
1551       //----------------------------------------------------------------------
1552 
1553       // no default case defined
1554       //	=> compiler checks the existence of all enum values
1555 
1556       case WD_COMPR__N:
1557 	ASSERT(0);
1558     }
1559 
1560 
1561     if ( group >= 0 && group < wia->group_used )
1562     {
1563 	wia_group_t * grp = wia->group + group;
1564 	grp->data_off4 = htonl( written ? wia->write_data_off >> 2 : 0 );
1565 	grp->data_size = htonl( written );
1566     }
1567 
1568     wia->write_data_off += written + 3 & ~3;
1569     if ( sf->f.bytes_written > wia->disc.chunk_size )
1570 	sf->progress_trigger++;
1571 
1572     if (write_count)
1573 	*write_count = written;
1574 
1575     return ERR_OK;
1576 }
1577 
1578 ///////////////////////////////////////////////////////////////////////////////
1579 ///////////////////////////////////////////////////////////////////////////////
1580 
write_part_data(struct SuperFile_t * sf)1581 static enumError write_part_data
1582 (
1583     struct SuperFile_t	* sf		// destination file
1584 )
1585 {
1586     DASSERT(sf);
1587     DASSERT(sf->wia);
1588 
1589     wia_controller_t * wia = sf->wia;
1590     DASSERT( wia->gdata_group >= 0 && wia->gdata_group < wia->group_used );
1591     DASSERT( wia->gdata_part  >= 0 && wia->gdata_part  < wia->disc.n_part );
1592 
1593 
1594     //----- decrypt and split data
1595 
1596     wd_disc_t * wdisc = wia->wdisc;
1597     ASSERT(wdisc);
1598     ASSERT( wia->gdata_part < wdisc->n_part );
1599     wd_part_t * wpart = wdisc->part + wia->gdata_part;
1600 
1601  #if WATCH_GROUP >= 0 && defined(TEST)
1602     if ( wia->gdata_group == WATCH_GROUP )
1603     {
1604 	PRINT("##### WATCH GROUP #%u #####\n",WATCH_GROUP);
1605 	FILE * f = fopen("pool/write.all.dump","wb");
1606 	if (f)
1607 	{
1608 	    HexDump(f,0,0,9,16,wia->gdata,wia->chunk_size);
1609 	    fclose(f);
1610 	}
1611     }
1612  #endif
1613 
1614     u8 * hashtab0 = tempbuf + tempbuf_size - WII_GROUP_HASH_SIZE * wia->chunk_groups;
1615     if ( wpart->is_encrypted )
1616 	wd_decrypt_sectors(0,&wia->akey,
1617 			wia->gdata,wia->gdata,hashtab0,wia->chunk_sectors);
1618     else
1619 	wd_split_sectors(wia->gdata,wia->gdata,hashtab0,wia->chunk_sectors);
1620 
1621  #if WATCH_GROUP >= 0 && defined(TEST)
1622     if ( wia->gdata_group == WATCH_GROUP )
1623     {
1624 	FILE * f = fopen("pool/write.split.dump","wb");
1625 	if (f)
1626 	{
1627 	    HexDump(f,0,0,9,16,wia->gdata,WII_GROUP_DATA_SIZE*wia->chunk_groups);
1628 	    fclose(f);
1629 	}
1630 
1631 	f = fopen("pool/write.hash.dump","wb");
1632 	if (f)
1633 	{
1634 	    int g;
1635 	    for ( g = 0; g < wia->chunk_groups; g++ )
1636 	    {
1637 		HexDump(f,0,0,9,16,hashtab0+WII_GROUP_HASH_SIZE*g,WII_GROUP_HASH_SIZE);
1638 		fprintf(f,"---\f\n");
1639 	    }
1640 	    fclose(f);
1641 	}
1642     }
1643  #endif
1644 
1645 
1646     //----- setup exceptions
1647 
1648     u8 * gdata = wia->gdata;
1649     u8 * hashtab1 = hashtab0;
1650     wia_except_list_t * except_list = (wia_except_list_t*)tempbuf;
1651 
1652     int g;
1653     for ( g = 0;
1654 	  g < wia->chunk_groups;
1655 	  g++, gdata += WII_GROUP_DATA_SIZE, hashtab1 += WII_GROUP_HASH_SIZE )
1656     {
1657 	u8 hashtab2[WII_GROUP_HASH_SIZE];
1658 	wd_calc_group_hashes(gdata,hashtab2,0,0);
1659 
1660      #if WATCH_GROUP >= 0 && defined(TEST)
1661 	if ( wia->gdata_group == WATCH_GROUP && g == WATCH_SUB_GROUP )
1662 	{
1663 	    FILE * f = fopen("pool/write.calc.dump","wb");
1664 	    if (f)
1665 	    {
1666 		HexDump(f,0,0,9,16,hashtab2,WII_GROUP_HASH_SIZE);
1667 		fclose(f);
1668 	    }
1669 	}
1670      #endif
1671 
1672 	int is;
1673 	wia_exception_t * except = except_list->exception;
1674 	noPRINT("** exc=%p,%p, gdata=%p, hash=%p\n",
1675 		except_list, except, gdata, hashtab1 );
1676 	for ( is = 0; is < WII_GROUP_SECTORS; is++ )
1677 	{
1678 	    wd_part_sector_t * sector1
1679 		= (wd_part_sector_t*)( hashtab1 + is * WII_SECTOR_HASH_SIZE );
1680 	    wd_part_sector_t * sector2
1681 		= (wd_part_sector_t*)( hashtab2 + is * WII_SECTOR_HASH_SIZE );
1682 
1683 	    int ih;
1684 	    u8 * h1 = sector1->h0[0];
1685 	    u8 * h2 = sector2->h0[0];
1686 	    for ( ih = 0; ih < WII_N_ELEMENTS_H0; ih++ )
1687 	    {
1688 		if (memcmp(h1,h2,WII_HASH_SIZE))
1689 		{
1690 		    TRACE("%5u.%02u.H0.%02u -> %04zx,%04zx\n",
1691 				wia->gdata_group, is, ih,
1692 				h1 - hashtab1,  h2 - hashtab2 );
1693 		    except->offset = htons(h1-hashtab1);
1694 		    memcpy(except->hash,h1,sizeof(except->hash));
1695 		    except++;
1696 		}
1697 		h1 += WII_HASH_SIZE;
1698 		h2 += WII_HASH_SIZE;
1699 	    }
1700 
1701 	    h1 = sector1->h1[0];
1702 	    h2 = sector2->h1[0];
1703 	    for ( ih = 0; ih < WII_N_ELEMENTS_H1; ih++ )
1704 	    {
1705 		if (memcmp(h1,h2,WII_HASH_SIZE))
1706 		{
1707 		    TRACE("%5u.%02u.H1.%u  -> %04zx,%04zx\n",
1708 				wia->gdata_group, is, ih,
1709 				h1 - hashtab1,  h2 - hashtab2 );
1710 		    except->offset = htons(h1-hashtab1);
1711 		    memcpy(except->hash,h1,sizeof(except->hash));
1712 		    except++;
1713 		}
1714 		h1 += WII_HASH_SIZE;
1715 		h2 += WII_HASH_SIZE;
1716 	    }
1717 
1718 	    h1 = sector1->h2[0];
1719 	    h2 = sector2->h2[0];
1720 	    for ( ih = 0; ih < WII_N_ELEMENTS_H2; ih++ )
1721 	    {
1722 		if (memcmp(h1,h2,WII_HASH_SIZE))
1723 		{
1724 		    TRACE("%5u.%02u.H2.%u  -> %04zx,%04zx\n",
1725 				wia->gdata_group, is, ih,
1726 				h1 - hashtab1,  h2 - hashtab2 );
1727 		    except->offset = htons(h1-hashtab1);
1728 		    memcpy(except->hash,h1,sizeof(except->hash));
1729 		    except++;
1730 		}
1731 		h1 += WII_HASH_SIZE;
1732 		h2 += WII_HASH_SIZE;
1733 	    }
1734 	}
1735 	except_list->n_exceptions = htons( except - except_list->exception );
1736 	memset(except,0,sizeof(*except)); // no garbage data
1737 	noPRINT_IF( except > except_list->exception,
1738 			" + %zu excpetions in group %u.%u\n",
1739 			except - except_list->exception,
1740 			wia->gdata_group, g );
1741 
1742      #if WATCH_GROUP >= 0 && defined(TEST)
1743 	if ( wia->gdata_group == WATCH_GROUP && g == WATCH_SUB_GROUP
1744 		&& except > except_list->exception )
1745 	{
1746 	    FILE * f = fopen("pool/write.except.dump","wb");
1747 	    if (f)
1748 	    {
1749 		const size_t sz = sizeof(wia_exception_t);
1750 		HexDump(f,0,0,9,sz,except_list,sizeof(except_list));
1751 		HexDump(f,0,0,9,sz,except_list->exception,
1752 				(except - except_list->exception) * sz );
1753 		fclose(f);
1754 	    }
1755 	}
1756      #endif
1757 
1758 	except_list = (wia_except_list_t*)except;
1759 	DASSERT( (u8*)except_list < hashtab0 );
1760     }
1761     noPRINT("## exc=%p,%p, gdata=%p, hash=%p\n",
1762 		except_list, except_list, gdata, hashtab1 );
1763 
1764 
1765     //----- write data
1766 
1767     return write_data( sf, (wia_except_list_t*)tempbuf, wia->gdata,
1768 			wia->gdata_used / WII_SECTOR_SIZE * WII_SECTOR_DATA_SIZE,
1769 			wia->gdata_group, 0 );
1770 }
1771 
1772 ///////////////////////////////////////////////////////////////////////////////
1773 
write_cached_gdata(struct SuperFile_t * sf,int new_part)1774 static enumError write_cached_gdata
1775 (
1776     struct SuperFile_t	* sf,		// destination file
1777     int			new_part	// >=0: index of new partition
1778 )
1779 {
1780     DASSERT(sf);
1781     DASSERT(sf->wia);
1782     wia_controller_t * wia = sf->wia;
1783 
1784     enumError err = ERR_OK;
1785     if ( wia->gdata_group >= 0 && wia->gdata_group < wia->group_used )
1786     {
1787 	if ( wia->gdata_part < 0 || wia->gdata_part >= wia->disc.n_part )
1788 	{
1789 	    err = write_data(sf, 0, wia->gdata, wia->gdata_used, wia->gdata_group, 0 );
1790 	}
1791 	else
1792 	{
1793 	    err = write_part_data(sf);
1794 	}
1795     }
1796 
1797     // setup empty gdata
1798 
1799     wia->gdata_group = -1;
1800 
1801     if ( new_part < 0 )
1802     {
1803 	memset(wia->gdata,0,wia->gdata_size);
1804 	wia->gdata_part  = -1;
1805     }
1806     else
1807     {
1808 	DASSERT( new_part < wia->disc.n_part );
1809 	if ( wia->gdata_part != new_part )
1810 	{
1811 	    if (!empty_decrypted_sector_initialized)
1812 	    {
1813 		PRINT("SETUP empty_decrypted_sector\n");
1814 		empty_decrypted_sector_initialized = true;
1815 
1816 		wd_part_sector_t * empty = &empty_decrypted_sector;
1817 		memset(empty,0,sizeof(empty_decrypted_sector));
1818 
1819 		int i;
1820 		SHA1(empty->data[0],WII_H0_DATA_SIZE,empty->h0[0]);
1821 		for ( i = 1; i < WII_N_ELEMENTS_H0; i++ )
1822 		    memcpy(empty->h0[i],empty->h0[0],WII_HASH_SIZE);
1823 
1824 		SHA1(empty->h0[0],sizeof(empty->h0),empty->h1[0]);
1825 		for ( i = 1; i < WII_N_ELEMENTS_H1; i++ )
1826 		    memcpy(empty->h1[i],empty->h1[0],WII_HASH_SIZE);
1827 
1828 		SHA1(empty->h1[0],sizeof(empty->h1),empty->h2[0]);
1829 		for ( i = 1; i < WII_N_ELEMENTS_H2; i++ )
1830 		    memcpy(empty->h2[i],empty->h2[0],WII_HASH_SIZE);
1831 	    }
1832 
1833 	    wia->gdata_part = new_part;
1834 	    wd_aes_set_key(&wia->akey,wia->part[new_part].part_key);
1835 
1836 	    if ( wia->wdisc && !wia->wdisc->part[new_part].is_encrypted )
1837 		memcpy(&wia->empty_sector,&empty_decrypted_sector,sizeof(wia->empty_sector));
1838 	    else
1839 		wd_encrypt_sectors(0,&wia->akey,
1840 			&empty_decrypted_sector,0,&wia->empty_sector,1);
1841 	}
1842 
1843 	int i;
1844 	u8 * dest = wia->gdata;
1845 	for ( i = 0; i < wia->chunk_sectors; i++, dest += WII_SECTOR_SIZE )
1846 	    memcpy( dest, &wia->empty_sector, WII_SECTOR_SIZE );
1847     }
1848 
1849     return err;
1850 }
1851 
1852 //
1853 ///////////////////////////////////////////////////////////////////////////////
1854 ///////////////			    WriteWIA()			///////////////
1855 ///////////////////////////////////////////////////////////////////////////////
1856 
WriteWIA(struct SuperFile_t * sf,off_t off,const void * buf,size_t count)1857 enumError WriteWIA
1858 (
1859     struct SuperFile_t	* sf,		// destination file
1860     off_t		off,		// file offset
1861     const void		* buf,		// source buffer
1862     size_t		count		// number of bytes to write
1863 )
1864 {
1865     ASSERT(sf);
1866     ASSERT(sf->wia);
1867     ASSERT(sf->wia->is_writing);
1868 
1869     TRACE("#W# -----\n");
1870     TRACE(TRACE_RDWR_FORMAT, "#W# WriteWIA()",
1871 		GetFD(&sf->f), GetFP(&sf->f),
1872 		(u64)off, (u64)off+count, count,
1873 		off < sf->max_virt_off ? " <" : "" );
1874     TRACE(" - off = %llx,%llx\n",(u64)sf->f.file_off,(u64)sf->f.max_off);
1875 
1876     if (SIGINT_level>1)
1877 	return ERR_INTERRUPT;
1878 
1879     wia_controller_t * wia = sf->wia;
1880     const u64 off2 = off + count;
1881     const wd_memmap_item_t * item = wia->memmap.item;
1882     const wd_memmap_item_t * item_end = item + wia->memmap.used;
1883 
1884     for ( ; item < item_end && item->offset < off2; item++ )
1885     {
1886       const u64 end = item->offset + item->size;
1887       noPRINT("> off=%llx..%llx, item=%llx..%llx\n", (u64)off, off2, item->offset, end );
1888       if ( item->offset < off2 && end > off )
1889       {
1890 	u64 overlap1 = item->offset > off ? item->offset : off;
1891 	const u64 overlap2 = end < off2 ? end : off2;
1892 	noPRINT("   -> %llx..%llx\n",overlap1,overlap2);
1893 
1894 	switch (item->mode)
1895 	{
1896 	 case WIA_MM_HEADER_DATA:
1897 	 case WIA_MM_CACHED_DATA:
1898 	    DASSERT(item->data);
1899 	    noPRINT("> COPY DATA: %9llx .. %9llx\n",overlap1,overlap2);
1900 	    memcpy(	(u8*)item->data + (overlap1-item->offset),
1901 		    (ccp)buf + (overlap1-off),
1902 		    overlap2 - overlap1 );
1903 	    break;
1904 
1905 	 case WIA_MM_GROWING:
1906 	    return ERROR0(ERR_INTERNAL,0);
1907 	    break; // [[2do]]
1908 
1909 	    // ... fall through ...
1910 
1911 	 case WIA_MM_RAW_GDATA:
1912 	    {
1913 		DASSERT( item->index >= 0 && item->index < wia->raw_data_used );
1914 		wia_raw_data_t * rdata = wia->raw_data + item->index;
1915 		while ( overlap1 < overlap2 )
1916 		{
1917 		    // align content on WII_SECTOR_SIZE!
1918 
1919 		    const int base_sector = item->offset / WII_SECTOR_SIZE;
1920 		    const int sector      = overlap1 / WII_SECTOR_SIZE - base_sector;
1921 		    const int base_group  = sector / wia->chunk_sectors;
1922 		    const int group       = base_group + ntohl(rdata->group_index);
1923 
1924 		    u64 base_off = base_sector * (u64)WII_SECTOR_SIZE
1925 				 + base_group  * (u64)wia->chunk_size;
1926 		    u64 end_off  = base_off + wia->chunk_size;
1927 		    if ( end_off > end )
1928 			 end_off = end;
1929 
1930 		    noPRINT("\tWIA_MM_RAW_GDATA: s=%d,%d, g=%d,%d/%d, off=%llx..%llx/%llx\n",
1931 			    base_sector, sector,
1932 			    base_group, group, wia->group_used,
1933 			    base_off, end_off, end );
1934 		    DASSERT( base_group < ntohl(rdata->n_groups) );
1935 		    DASSERT( group >= 0 && group < wia->group_used );
1936 
1937 		    if ( group != wia->gdata_group )
1938 		    {
1939 			enumError err = write_cached_gdata(sf,-1);
1940 			wia->gdata_group = group;
1941 			wia->gdata_used  = end_off - base_off;
1942 			noPRINT("----- SETUP RAW%4u GROUP %4u/%4u>%4u, off=%9llx, size=%6x\n",
1943 				item->index, base_group, ntohl(rdata->n_groups), group,
1944 				base_off, wia->gdata_used );
1945 			if (err)
1946 			    return err;
1947 		    }
1948 
1949 		    if ( end_off > overlap2 )
1950 			 end_off = overlap2;
1951 
1952 		    noPRINT("> COLLECT RAW DATA:"
1953 			    " %llx .. %llx -> %llx + %llx, base = %9llx + %6x\n",
1954 				overlap1, end_off,
1955 				overlap1 - base_off, end_off - overlap1,
1956 				base_off, wia->gdata_used );
1957 		    memcpy( wia->gdata + ( overlap1 - base_off ),
1958 			    (ccp)buf + (overlap1-off),
1959 			    end_off - overlap1 );
1960 		    overlap1 = end_off;
1961 		}
1962 	    }
1963 	    break;
1964 
1965 	 case WIA_MM_PART_GDATA_0:
1966 	 case WIA_MM_PART_GDATA_1:
1967 	    {
1968 		DASSERT( item->index >= 0 && item->index < wia->disc.n_part );
1969 		wia_part_t * part = wia->part + item->index;
1970 		wia_part_data_t * pd = part->pd + ( item->mode - WIA_MM_PART_GDATA_0 );
1971 
1972 		while ( overlap1 < overlap2 )
1973 		{
1974 		    const int base_group = ( overlap1 - item->offset ) / wia->chunk_size;
1975 		    u64 base_off = item->offset + base_group * (u64)wia->chunk_size;
1976 		    u64 end_off  = base_off + wia->chunk_size;
1977 		    if ( end_off > end )
1978 			 end_off = end;
1979 
1980 		    const int group = base_group + pd->group_index;
1981 
1982 		    if ( group != wia->gdata_group || item->index != wia->gdata_part )
1983 		    {
1984 			noPRINT("----- SETUP PART%3u GROUP %4u/%4u>%4u, off=%9llx, size=%6x\n",
1985 				item->index,
1986 				group - pd->group_index, pd->n_groups, group,
1987 				base_off, wia->gdata_used );
1988 			DASSERT( group >= 0 && group < wia->group_used );
1989 			DASSERT( base_group >= 0 && base_group < pd->n_groups );
1990 
1991 			enumError err = write_cached_gdata(sf,item->index);
1992 			if (err)
1993 			    return err;
1994 			DASSERT( wia->gdata_part == item->index );
1995 
1996 			wia->gdata_group = group;
1997 			wia->gdata_used  = end_off - base_off;
1998 		    }
1999 
2000 		    if ( end_off > overlap2 )
2001 			 end_off = overlap2;
2002 
2003 		    noPRINT("> COLLECT PART DATA:"
2004 			    " %llx .. %llx -> %llx + %llx, base = %9llx + %6x\n",
2005 				overlap1, end_off,
2006 				overlap1 - base_off, end_off - overlap1,
2007 				base_off, wia->gdata_used );
2008 		    memcpy( wia->gdata + ( overlap1 - base_off ),
2009 			    (ccp)buf + (overlap1-off),
2010 			    end_off - overlap1 );
2011 		    overlap1 = end_off;
2012 		}
2013 	    }
2014 	    break;
2015 
2016 	  default:
2017 	    if (!item->size)
2018 		break;
2019 	    PRINT("mode=%x, off=%llx, size=%llx\n",item->mode,item->offset,item->size);
2020 	    return ERROR0(ERR_INTERNAL,0);
2021 	}
2022       }
2023     }
2024 
2025     return ERR_OK;
2026 }
2027 
2028 ///////////////////////////////////////////////////////////////////////////////
2029 
WriteSparseWIA(struct SuperFile_t * sf,off_t off,const void * buf,size_t count)2030 enumError WriteSparseWIA
2031 (
2032     struct SuperFile_t	* sf,		// destination file
2033     off_t		off,		// file offset
2034     const void		* buf,		// source buffer
2035     size_t		count		// number of bytes to write
2036 )
2037 {
2038     return off + count < WII_PART_OFF
2039 		? WriteWIA(sf,off,buf,count)
2040 		: SparseHelper(sf,off,buf,count,WriteWIA,WIA_MIN_HOLE_SIZE);
2041 }
2042 
2043 ///////////////////////////////////////////////////////////////////////////////
2044 
WriteZeroWIA(struct SuperFile_t * sf,off_t off,size_t count)2045 enumError WriteZeroWIA
2046 (
2047     struct SuperFile_t	* sf,		// destination file
2048     off_t		off,		// file offset
2049     size_t		count		// number of bytes to write
2050 )
2051 {
2052     ASSERT(sf);
2053     ASSERT(sf->wia);
2054 
2055     TRACE("#W# -----\n");
2056     TRACE(TRACE_RDWR_FORMAT, "#W# WriteZeroWIA()",
2057 		GetFD(&sf->f), GetFP(&sf->f), (u64)off, (u64)off+count, count,
2058 		off < sf->max_virt_off ? " <" : "" );
2059     TRACE(" - off = %llx,%llx,%llx\n",
2060 		(u64)sf->f.file_off, (u64)sf->f.max_off,
2061 		(u64)sf->max_virt_off);
2062 
2063     // [wia]
2064     return ERROR0(ERR_NOT_IMPLEMENTED,"WIA is not supported yet.\n");
2065 }
2066 
2067 ///////////////////////////////////////////////////////////////////////////////
2068 
FlushWIA(struct SuperFile_t * sf)2069 enumError FlushWIA
2070 (
2071     struct SuperFile_t	* sf		// destination file
2072 )
2073 {
2074     ASSERT(sf);
2075     ASSERT(sf->wia);
2076 
2077     enumError err = ERR_OK;
2078     wia_controller_t * wia = sf->wia;
2079     if (wia->is_writing)
2080     {
2081 	err = write_cached_gdata(sf,-1);
2082 	if (!err)
2083 	    err = FlushFile(sf);
2084     }
2085 
2086     return err;
2087 }
2088 
2089 //
2090 ///////////////////////////////////////////////////////////////////////////////
2091 ///////////////			setup write WIA			///////////////
2092 ///////////////////////////////////////////////////////////////////////////////
2093 
need_raw_data(wia_controller_t * wia,u32 grow_size,u64 data_offset,u64 data_size,u32 * return_n_sect)2094 static wia_raw_data_t * need_raw_data
2095 (
2096     wia_controller_t	* wia,		// valid pointer
2097     u32			grow_size,	// if field is full grow # elements
2098     u64			data_offset,	// offset of data
2099     u64			data_size,	// size of data
2100     u32			* return_n_sect	// not NULL && data_size>0: return n_sect
2101 )
2102 {
2103     DASSERT(wia);
2104     DASSERT( grow_size > 0 );
2105     if ( wia->raw_data_used == wia->raw_data_size )
2106     {
2107 	wia->raw_data_size += grow_size;
2108 	noPRINT("ALLOC %u RAW_DATA\n",wia->raw_data_size);
2109 	wia->raw_data
2110 	    = REALLOC( wia->raw_data, wia->raw_data_size * sizeof(*wia->raw_data) );
2111     }
2112 
2113     wia_raw_data_t * rdata = wia->raw_data + wia->raw_data_used++;
2114     memset(rdata,0,sizeof(*rdata));
2115 
2116     if (data_size)
2117     {
2118 	const u32 sect1  = data_offset / WII_SECTOR_SIZE;
2119 	const u32 sect2	 = ( data_offset + data_size + WII_SECTOR_SIZE - 1 ) / WII_SECTOR_SIZE;
2120 	const u32 n_sect = sect2 - sect1;
2121 	const u32 n_grp  = ( n_sect + wia->chunk_sectors - 1 ) / wia->chunk_sectors;
2122 
2123 	rdata->raw_data_off	= hton64(data_offset);
2124 	rdata->raw_data_size	= hton64(data_size);
2125 	rdata->group_index	= htonl(wia->group_used);
2126 	rdata->n_groups		= htonl(n_grp);
2127 	wia->group_used		+= n_grp;
2128 
2129 	if (return_n_sect)
2130 	    *return_n_sect = n_sect;
2131     }
2132 
2133     return rdata;
2134 }
2135 
2136 ///////////////////////////////////////////////////////////////////////////////
2137 
FinishSetupWriteWIA(struct SuperFile_t * sf)2138 static enumError FinishSetupWriteWIA
2139 (
2140     struct SuperFile_t	* sf		// file to setup
2141 )
2142 {
2143     DASSERT(sf);
2144     DASSERT(sf->wia);
2145 
2146     wia_controller_t * wia = sf->wia;
2147     wia_disc_t * disc = &wia->disc;
2148 
2149 
2150     //----- setup raw data area
2151 
2152     wd_memmap_item_t * it;
2153 
2154     it = wd_insert_memmap(&wia->memmap,WIA_MM_HEADER_DATA,0,sizeof(disc->dhead));
2155     DASSERT(it);
2156     it->data = disc->dhead;
2157     snprintf(it->info,sizeof(it->info),"Disc header");
2158 
2159     it = wia->memmap.item + wia->memmap.used - 1;
2160     u64 fsize = it->offset + it->size;
2161     if ( fsize < wia->fhead.iso_file_size )
2162 	 fsize = wia->fhead.iso_file_size;
2163     it = wd_insert_memmap(&wia->memmap,WIA_MM_EOF,fsize,0);
2164     DASSERT(it);
2165     snprintf(it->info,sizeof(it->info),"--- end of file ---");
2166 
2167     if ( fsize < WIA_MAX_SUPPORTED_ISO_SIZE )
2168     {
2169 	it = wd_insert_memmap(&wia->memmap,WIA_MM_GROWING,fsize,
2170 				WIA_MAX_SUPPORTED_ISO_SIZE-fsize);
2171 	DASSERT(it);
2172 	snprintf(it->info,sizeof(it->info),"additional space");
2173     }
2174 
2175     u64 last_off = 0;
2176     for(;;)
2177     {
2178 	bool dirty = false;
2179 	const wd_memmap_item_t * item = wia->memmap.item;
2180 	const wd_memmap_item_t * item_end = item + wia->memmap.used;
2181 	for ( ; item < item_end; item++ )
2182 	{
2183 	    if ( last_off < item->offset )
2184 	    {
2185 		u64 size = item->offset - last_off;
2186 		if ( last_off < WII_PART_OFF )
2187 		{
2188 		    // small chunk to allow fast access to disc header
2189 		    const u32 max_size = WII_PART_OFF - last_off;
2190 		    if ( size > max_size )
2191 			 size = max_size;
2192 		}
2193 		u32 n_sect = 0;
2194 		wia_raw_data_t * rdata
2195 		    = need_raw_data( wia, 0x20, last_off, size, &n_sect );
2196 
2197 		it = wd_insert_memmap(&wia->memmap,WIA_MM_RAW_GDATA,last_off,size);
2198 		DASSERT(it);
2199 		it->index = wia->raw_data_used - 1;
2200 		const u32 n_groups = ntohl(rdata->n_groups);
2201 		snprintf(it->info,sizeof(it->info),
2202 			    "RAW #%u, %u sector%s, %u chunk%s, %s",
2203 			    it->index,
2204 			    n_sect, n_sect == 1 ? "" : "s",
2205 			    n_groups, n_groups == 1 ? "" : "s",
2206 			    wd_print_size_1024(0,0,size,false) );
2207 
2208 		dirty = true;
2209 		break;
2210 	    }
2211 	    last_off = item->offset + item->size;
2212 	}
2213 	if (!dirty)
2214 	    break;
2215     }
2216     wia->growing = need_raw_data(wia,1,0,0,0);
2217     wia->memory_usage += wia->raw_data_size * sizeof(*wia->raw_data);
2218     sf->progress_add_total += wia->raw_data_size * sizeof(*wia->raw_data);
2219 
2220 
2221     //----- setup group area
2222 
2223     if (wia->group_used)
2224     {
2225 	wia->group_size = wia->group_used;
2226 	PRINT("ALLOC %u GROUPS\n",wia->group_size);
2227 	wia->group = CALLOC(wia->group_size,sizeof(*wia->group));
2228 	wia->memory_usage += wia->group_size * sizeof(*wia->group);
2229 	sf->progress_add_total += wia->group_size * sizeof(*wia->group);
2230     }
2231 
2232 
2233     //----- logging
2234 
2235     if ( verbose > 1 )
2236 	printf("  Compression mode: %s (method %s, level %u, chunk size %u MiB, mem ~%u MiB)\n",
2237 		wd_print_compression(0,0,disc->compression,
2238 				disc->compr_level,disc->chunk_size,2),
2239 		wd_get_compression_name(disc->compression,"?"),
2240 		disc->compr_level, disc->chunk_size / MiB,
2241 		( wia->memory_usage + MiB/2 ) / MiB );
2242 
2243     if ( logging > 0 )
2244     {
2245 	printf("\nWIA memory map:\n\n");
2246 	wd_print_memmap(stdout,3,&wia->memmap);
2247 	putchar('\n');
2248     }
2249 
2250 
2251     //----- finish setup
2252 
2253     wia->write_data_off	= sizeof(wia_file_head_t)
2254 			+ sizeof(wia_disc_t)
2255 			+ sizeof(wia_part_t) * disc->n_part;
2256     sf->progress_add_total += wia->write_data_off + sizeof(wia_part_t) * disc->n_part;
2257 
2258     wia->is_valid = true;
2259     SetupIOD(sf,OFT_WIA,OFT_WIA);
2260 
2261     //----- preallocate disc space
2262 
2263     if ( disc->compression >= WD_COMPR__FIRST_REAL )
2264     {
2265 	if ( sf->src && !sf->raw_mode )
2266 	{
2267 	    wd_disc_t * disc = OpenDiscSF(sf->src,false,true);
2268 	    if (disc)
2269 		fsize = wd_count_used_disc_size(disc,1,0);
2270 	}
2271 	PreallocateF(&sf->f,0,fsize);
2272     }
2273 
2274     return ERR_OK;
2275 }
2276 
2277 ///////////////////////////////////////////////////////////////////////////////
2278 
setup_dynamic_mem(void * param,struct wd_memmap_t * mm,struct wd_memmap_item_t * item)2279 static void setup_dynamic_mem
2280 (
2281     void			* param,	// user defined parameter
2282     struct wd_memmap_t		* mm,		// valid pointer to patch object
2283     struct wd_memmap_item_t	* item		// valid pointer to inserted item
2284 )
2285 {
2286     if ( item->mode == WIA_MM_CACHED_DATA )
2287     {
2288 	PRINT("ALLOC PART HEADER #%u, size=%llx\n",item->index,item->size);
2289 	item->data = CALLOC(1,item->size);
2290 	item->data_alloced = true;
2291 
2292 	wia_controller_t * wia = param;
2293 	DASSERT(wia);
2294 	item->index = wia->raw_data_used;
2295 
2296      #if HAVE_ASSERT
2297 	wia_raw_data_t * rdata = need_raw_data(wia,0x20,item->offset,item->size,0);
2298 	ASSERT(rdata);
2299 	ASSERT( ntohl(rdata->n_groups) == 1 ); // [[2do]] really needed?
2300      #endif
2301     }
2302 }
2303 
2304 ///////////////////////////////////////////////////////////////////////////////
2305 
SetupWriteWIA(struct SuperFile_t * sf,u64 src_file_size)2306 enumError SetupWriteWIA
2307 (
2308     struct SuperFile_t	* sf,		// file to setup
2309     u64			src_file_size	// NULL or source file size
2310 )
2311 {
2312     ASSERT(sf);
2313     PRINT("#W# SetupWriteWIA(%p,%llx) src=%p, file=%d/%p, oft=%x, wia=%p, v=%s/%s\n",
2314 		sf, src_file_size,
2315 		sf->src, GetFD(&sf->f), GetFP(&sf->f),
2316 		sf->iod.oft, sf->wia,
2317 		PrintVersionWIA(0,0,WIA_VERSION_COMPATIBLE),
2318 		PrintVersionWIA(0,0,WIA_VERSION) );
2319 
2320     if (sf->wia)
2321 	return ERROR0(ERR_INTERNAL,0);
2322 
2323     sf->progress_trigger = sf->progress_trigger_init = 0;
2324 
2325 
2326     //----- setup controller
2327 
2328     wia_controller_t * wia = CALLOC(1,sizeof(*wia));
2329     sf->wia = wia;
2330     wia->is_writing = true;
2331     wia->gdata_group = wia->gdata_part = -1;  // reset gdata
2332 
2333     AllocBufferWIA(wia, opt_compr_chunk_size
2334 			? opt_compr_chunk_size : opt_chunk_size, true, false );
2335 
2336 
2337     //----- setup file header
2338 
2339     wia_file_head_t *fhead = &wia->fhead;
2340     memcpy(fhead->magic,WIA_MAGIC,sizeof(fhead->magic));
2341     fhead->magic[3]++; // magic is invalid now
2342     fhead->version		= WIA_VERSION;
2343     fhead->version_compatible	= WIA_VERSION_COMPATIBLE;
2344     fhead->iso_file_size	= src_file_size ? src_file_size
2345 					: sf->src ? sf->src->file_size : 0;
2346 
2347     //----- setup disc info && compression
2348 
2349     wia_disc_t *disc = &wia->disc;
2350     disc->disc_type	= WD_DT_UNKNOWN;
2351     disc->compression	= opt_compr_method;
2352     disc->chunk_size	= wia->chunk_size;
2353 
2354     switch(opt_compr_method)
2355     {
2356 	case WD_COMPR__N:
2357 	case WD_COMPR_NONE:
2358 	case WD_COMPR_PURGE:
2359 	    // nothing to do
2360 	    break;
2361 
2362 	case WD_COMPR_BZIP2:
2363 	 #ifdef NO_BZIP2
2364 	    return ERROR0(ERR_NOT_IMPLEMENTED,
2365 			"No bzip2 support for this release! Sorry!\n");
2366 	 #else
2367 	    disc->compr_level = CalcCompressionLevelBZIP2(opt_compr_level);
2368 	    wia->memory_usage += CalcMemoryUsageBZIP2(opt_compr_level,true);
2369 	 #endif
2370 	    PRINT("OPEN STREAM\n");
2371 	    OpenStreamFile(&sf->f);
2372 	    break;
2373 
2374 	case WD_COMPR_LZMA:
2375 	    {
2376 		EncLZMA_t lzma;
2377 		enumError err = EncLZMA_Open(&lzma,sf->f.fname,opt_compr_level,false);
2378 		if (err)
2379 		    return err;
2380 		disc->compr_level = lzma.compr_level;
2381 		wia->memory_usage += CalcMemoryUsageLZMA(lzma.compr_level,true);
2382 		const size_t len = lzma.enc_props_len < sizeof(disc->compr_data)
2383 				 ? lzma.enc_props_len : sizeof(disc->compr_data);
2384 		disc->compr_data_len = len;
2385 		memcpy(disc->compr_data,lzma.enc_props,len);
2386 		EncLZMA_Close(&lzma);
2387 	    }
2388 	    break;
2389 
2390 	case WD_COMPR_LZMA2:
2391 	    {
2392 		EncLZMA_t lzma;
2393 		enumError err = EncLZMA2_Open(&lzma,sf->f.fname,opt_compr_level,false);
2394 		if (err)
2395 		    return err;
2396 		disc->compr_level = lzma.compr_level;
2397 		const size_t len = lzma.enc_props_len < sizeof(disc->compr_data)
2398 				 ? lzma.enc_props_len : sizeof(disc->compr_data);
2399 		disc->compr_data_len = len;
2400 		wia->memory_usage += CalcMemoryUsageLZMA2(lzma.compr_level,true);
2401 		memcpy(disc->compr_data,lzma.enc_props,len);
2402 		EncLZMA2_Close(&lzma);
2403 	    }
2404 	    break;
2405     }
2406 
2407 
2408     //----- check source disc type
2409 
2410     if (!sf->src)
2411 	return FinishSetupWriteWIA(sf);
2412 
2413     wd_disc_t * wdisc = OpenDiscSF(sf->src,true,false);
2414     if (!wdisc)
2415 	return FinishSetupWriteWIA(sf);
2416     wia->wdisc = wd_dup_disc(wdisc);
2417     sf->source_size = wd_count_used_disc_blocks(wdisc,1,0) * (u64)WII_SECTOR_SIZE;
2418 
2419     disc->disc_type = wdisc->disc_type;
2420     if ( disc->disc_type == WD_DT_GAMECUBE )
2421 	return FinishSetupWriteWIA(sf);
2422 
2423     if (wdisc->have_overlays)
2424     {
2425 	if ( verbose >= -1 )
2426 	    ERROR0(ERR_WARNING,
2427 		"Wii disc contains overlayed partitions!\n"
2428 		"=> Create WIA in non effective raw mode: %s\n",
2429 		sf->f.fname );
2430 	return FinishSetupWriteWIA(sf);
2431     }
2432 
2433 
2434     int ip;
2435     for ( ip = 0; ip < wdisc->n_part; ip++ )
2436     {
2437 	wd_part_t * wpart = wdisc->part + ip;
2438 	wd_load_part(wpart,true,true,false);
2439 	noPRINT("SETUP PARTITION #%u: %s\n",
2440 		ip, wd_print_part_name(0,0,wpart->part_type,WD_PNAME_NUM_INFO) );
2441 	if (!wpart->is_valid)
2442 	{
2443 	    if ( verbose >= -1 )
2444 		ERROR0(ERR_WARNING,
2445 			"Wii disc contains invalid partitions!\n"
2446 			"=> Create WIA in non effective raw mode: %s\n",
2447 			sf->f.fname );
2448 	    return FinishSetupWriteWIA(sf);
2449 	}
2450     }
2451 
2452 
2453     //----- setup wii partitions
2454 
2455     disc->n_part = wdisc->n_part;
2456     memcpy(&disc->dhead,&wdisc->dhead,sizeof(disc->dhead));
2457 
2458     wia_part_t * part = CALLOC(disc->n_part,sizeof(wia_part_t));
2459     wia->part = part;
2460 
2461     for ( ip = 0; ip < wdisc->n_part; ip++, part++ )
2462     {
2463 	wd_part_t * wpart	= wdisc->part + ip;
2464 	memcpy(part->part_key,wpart->key,sizeof(part->part_key));
2465 
2466 	wia_part_data_t * pd	= part->pd;
2467 	pd->first_sector	= wpart->data_sector;
2468 	if ( pd->first_sector < WII_PART_OFF / WII_SECTOR_SIZE )
2469 	     pd->first_sector = WII_PART_OFF / WII_SECTOR_SIZE;
2470 	pd->n_sectors		= wpart->end_mgr_sector - pd->first_sector;
2471 	pd->n_groups		= ( pd->n_sectors + wia->chunk_sectors - 1 )
2472 				/ wia->chunk_sectors;
2473 	pd->group_index		= wia->group_used;
2474 	wia->group_used		+= pd->n_groups;
2475 
2476 
2477 	pd++;
2478 	pd->first_sector	= wpart->end_mgr_sector;
2479 	pd->n_sectors		= wpart->end_sector - pd->first_sector;
2480 	pd->n_groups		= ( pd->n_sectors + wia->chunk_sectors - 1 )
2481 				/ wia->chunk_sectors;
2482 	pd->group_index		= wia->group_used;
2483 	wia->group_used		+= pd->n_groups;
2484 
2485 	noTRACE("PT %u, sect = %x,%x,%x\n",
2486 		ip, pd->first_sector, pd->n_sectors, pd->n_groups );
2487     }
2488 
2489     wd_insert_memmap_disc_part(&wia->memmap,wdisc,setup_dynamic_mem,wia,
2490 			WIA_MM_CACHED_DATA,
2491 			WIA_MM_PART_GDATA_0, WIA_MM_PART_GDATA_1,
2492 			WIA_MM_IGNORE, WIA_MM_IGNORE );
2493 
2494 
2495     //----- finish setup
2496 
2497     return FinishSetupWriteWIA(sf);
2498 }
2499 
2500 //
2501 ///////////////////////////////////////////////////////////////////////////////
2502 ///////////////			term write WIA			///////////////
2503 ///////////////////////////////////////////////////////////////////////////////
2504 
TermWriteWIA(struct SuperFile_t * sf)2505 enumError TermWriteWIA
2506 (
2507     struct SuperFile_t	* sf		// file to terminate
2508 )
2509 {
2510     ASSERT(sf);
2511     ASSERT(sf->wia);
2512     PRINT("#W# TermWriteWIA(%p)\n",sf);
2513 
2514     sf->progress_trigger = sf->progress_trigger_init = 1;
2515 
2516     wia_controller_t * wia = sf->wia;
2517     wia_disc_t *disc = &wia->disc;
2518 
2519 
2520     //----- write chached gdata
2521 
2522     enumError err = write_cached_gdata(sf,-1);
2523     if (err)
2524 	return err;
2525 
2526 
2527     //----- write cached data
2528 
2529     wd_memmap_item_t *it, *it_end = wia->memmap.item + wia->memmap.used;
2530     for ( it = wia->memmap.item; it < it_end; it++ )
2531 	if ( it->mode == WIA_MM_CACHED_DATA )
2532 	{
2533 	    DASSERT( it->index < wia->raw_data_used );
2534 	    wia_raw_data_t * rdata = wia->raw_data + it->index;
2535 	    ASSERT( ntohl(rdata->n_groups) == 1 );
2536 	    DASSERT( ntohl(rdata->group_index) < wia->group_used );
2537 	    err = write_data(sf, 0, it->data,it->size, ntohl(rdata->group_index), 0 );
2538 	    if (err)
2539 		return err;
2540 	}
2541 
2542 
2543     //----- write raw data table
2544 
2545     DASSERT( wia->raw_data_used > 0 );
2546     if (!wia->growing->n_groups)
2547 	wia->raw_data_used--;
2548 
2549     if (wia->raw_data_used)
2550     {
2551 	DASSERT(wia->raw_data);
2552 	disc->n_raw_data	= wia->raw_data_used;
2553 	disc->raw_data_off	= wia->write_data_off;
2554 	const u32 raw_data_len	= wia->raw_data_used * sizeof(wia_raw_data_t);
2555 	err = write_data( sf, 0, wia->raw_data, raw_data_len, -1, &disc->raw_data_size );
2556 	PRINT("** RAW DATA TABLE: n=%d, off=%llx, size=%x\n",
2557 			disc->n_raw_data, disc->raw_data_off, disc->raw_data_size );
2558 	if (err)
2559 	    return err;
2560     }
2561 
2562 
2563     //----- write group table
2564 
2565     if (wia->group_used)
2566     {
2567 	DASSERT(wia->group);
2568 	disc->n_groups	= wia->group_used;
2569 	disc->group_off	= wia->write_data_off;
2570 	const u32 group_len	= wia->group_used * sizeof(wia_group_t);
2571 	err = write_data( sf, 0, wia->group, group_len, -1, &disc->group_size );
2572 	PRINT("** GROUP TABLE: n=%d, off=%llx, size=%x\n",
2573 			disc->n_groups, disc->group_off, disc->group_size );
2574 	if (err)
2575 	    return err;
2576     }
2577 
2578 
2579     //----- calc part header
2580 
2581     int ip;
2582     for ( ip = 0; ip < disc->n_part; ip++ )
2583 	wia_hton_part(wia->part+ip,0);
2584 
2585     const u32 total_part_size = sizeof(wia_part_t) * disc->n_part;
2586     const u64 part_off = sizeof(wia_file_head_t) + sizeof(wia_disc_t);
2587 
2588 
2589     //----- calc disc info
2590 
2591     disc->part_t_size		= sizeof(wia_part_t);
2592     disc->part_off		= part_off;
2593     SHA1((u8*)wia->part,total_part_size,disc->part_hash);
2594 
2595     wia_hton_disc(disc,disc);
2596 
2597 
2598     //----- calc file header
2599 
2600     wia_file_head_t *fhead	= &wia->fhead;
2601     memcpy(fhead->magic,WIA_MAGIC,sizeof(fhead->magic));
2602     fhead->version		= WIA_VERSION;
2603     fhead->version_compatible	= WIA_VERSION_COMPATIBLE;
2604     fhead->disc_size		= sizeof(wia_disc_t);
2605     fhead->wia_file_size	= sf->f.max_off;
2606 
2607     SHA1((u8*)disc,sizeof(*disc),fhead->disc_hash);
2608     wia_hton_file_head(fhead,fhead);
2609 
2610     SHA1((u8*)fhead, sizeof(*fhead)-sizeof(fhead->file_head_hash),
2611 		fhead->file_head_hash );
2612 
2613 
2614     //----- write data
2615 
2616     err = WriteAtF(&sf->f,0,fhead,sizeof(*fhead));
2617     if (err)
2618 	return err;
2619 
2620     WriteAtF(&sf->f,sizeof(*fhead),disc,sizeof(*disc));
2621     if (err)
2622 	return err;
2623 
2624     WriteAtF(&sf->f,part_off,wia->part,total_part_size);
2625     if (err)
2626 	return err;
2627 
2628 
2629     // convert back to local endian
2630 
2631     wia_ntoh_file_head(fhead,fhead);
2632     wia_ntoh_disc(disc,disc);
2633     for ( ip = 0; ip < disc->n_part; ip++ )
2634 	wia_ntoh_part(wia->part+ip,0);
2635 
2636     return ERR_OK;
2637 }
2638 
2639 //
2640 ///////////////////////////////////////////////////////////////////////////////
2641 ///////////////			endian conversions		///////////////
2642 ///////////////////////////////////////////////////////////////////////////////
2643 
wia_ntoh_file_head(wia_file_head_t * dest,const wia_file_head_t * src)2644 void wia_ntoh_file_head ( wia_file_head_t * dest, const wia_file_head_t * src )
2645 {
2646     DASSERT(dest);
2647 
2648     if (!src)
2649 	src = dest;
2650     else if ( dest != src )
2651 	memcpy(dest,src,sizeof(*dest));
2652 
2653     dest->version		= ntohl (src->version);
2654     dest->version_compatible	= ntohl (src->version_compatible);
2655 
2656     dest->disc_size		= ntohl (src->disc_size);
2657 
2658     dest->iso_file_size		= ntoh64(src->iso_file_size);
2659     dest->wia_file_size		= ntoh64(src->wia_file_size);
2660 }
2661 
2662 ///////////////////////////////////////////////////////////////////////////////
2663 
wia_hton_file_head(wia_file_head_t * dest,const wia_file_head_t * src)2664 void wia_hton_file_head ( wia_file_head_t * dest, const wia_file_head_t * src )
2665 {
2666     DASSERT(dest);
2667 
2668     if (!src)
2669 	src = dest;
2670     else if ( dest != src )
2671 	memcpy(dest,src,sizeof(*dest));
2672 
2673     dest->version		= htonl (src->version);
2674     dest->version_compatible	= htonl (src->version_compatible);
2675 
2676     dest->disc_size		= htonl (src->disc_size);
2677 
2678     dest->iso_file_size		= hton64(src->iso_file_size);
2679     dest->wia_file_size		= hton64(src->wia_file_size);
2680 }
2681 
2682 ///////////////////////////////////////////////////////////////////////////////
2683 ///////////////////////////////////////////////////////////////////////////////
2684 
wia_ntoh_disc(wia_disc_t * dest,const wia_disc_t * src)2685 void wia_ntoh_disc ( wia_disc_t * dest, const wia_disc_t * src )
2686 {
2687     DASSERT(dest);
2688 
2689     if (!src)
2690 	src = dest;
2691     else if ( dest != src )
2692 	memcpy(dest,src,sizeof(*dest));
2693 
2694     dest->disc_type		= ntohl (src->disc_type);
2695     dest->compression		= ntohl (src->compression);
2696     dest->compr_level		= ntohl (src->compr_level);
2697     dest->chunk_size		= ntohl (src->chunk_size);
2698 
2699     dest->n_part		= ntohl (src->n_part);
2700     dest->part_t_size		= ntohl (src->part_t_size);
2701     dest->part_off		= ntoh64(src->part_off);
2702 
2703     dest->n_raw_data		= ntohl (src->n_raw_data);
2704     dest->raw_data_off		= ntoh64(src->raw_data_off);
2705     dest->raw_data_size		= ntohl (src->raw_data_size);
2706 
2707     dest->n_groups		= ntohl (src->n_groups);
2708     dest->group_off		= ntoh64(src->group_off);
2709     dest->group_size		= ntohl (src->group_size);
2710 }
2711 
2712 ///////////////////////////////////////////////////////////////////////////////
2713 
wia_hton_disc(wia_disc_t * dest,const wia_disc_t * src)2714 void wia_hton_disc ( wia_disc_t * dest, const wia_disc_t * src )
2715 {
2716     DASSERT(dest);
2717 
2718     if (!src)
2719 	src = dest;
2720     else if ( dest != src )
2721 	memcpy(dest,src,sizeof(*dest));
2722 
2723     dest->disc_type		= htonl (src->disc_type);
2724     dest->compression		= htonl (src->compression);
2725     dest->compr_level		= htonl (src->compr_level);
2726     dest->chunk_size		= htonl (src->chunk_size);
2727 
2728     dest->n_part		= htonl (src->n_part);
2729     dest->part_t_size		= htonl (src->part_t_size);
2730     dest->part_off		= hton64(src->part_off);
2731 
2732     dest->n_raw_data		= htonl (src->n_raw_data);
2733     dest->raw_data_off		= hton64(src->raw_data_off);
2734     dest->raw_data_size		= htonl (src->raw_data_size);
2735 
2736     dest->n_groups		= htonl (src->n_groups);
2737     dest->group_off		= hton64(src->group_off);
2738     dest->group_size		= htonl (src->group_size);
2739 }
2740 
2741 ///////////////////////////////////////////////////////////////////////////////
2742 ///////////////////////////////////////////////////////////////////////////////
2743 
wia_ntoh_part(wia_part_t * dest,const wia_part_t * src)2744 void wia_ntoh_part ( wia_part_t * dest, const wia_part_t * src )
2745 {
2746     DASSERT(dest);
2747 
2748     if (!src)
2749 	src = dest;
2750     else if ( dest != src )
2751 	memcpy(dest,src,sizeof(*dest));
2752 
2753     int id;
2754     const wia_part_data_t * src_pd = src->pd;
2755     wia_part_data_t * dest_pd = dest->pd;
2756 
2757     for ( id = 0; id < sizeof(src->pd)/sizeof(src->pd[0]); id++, src_pd++, dest_pd++ )
2758     {
2759 	dest_pd->first_sector	= ntohl (src_pd->first_sector);
2760 	dest_pd->n_sectors	= ntohl (src_pd->n_sectors);
2761 
2762 	dest_pd->group_index	= ntohl (src_pd->group_index);
2763 	dest_pd->n_groups	= ntohl (src_pd->n_groups);
2764     }
2765 }
2766 
2767 ///////////////////////////////////////////////////////////////////////////////
2768 
wia_hton_part(wia_part_t * dest,const wia_part_t * src)2769 void wia_hton_part ( wia_part_t * dest, const wia_part_t * src )
2770 {
2771     DASSERT(dest);
2772 
2773     if (!src)
2774 	src = dest;
2775     else if ( dest != src )
2776 	memcpy(dest,src,sizeof(*dest));
2777 
2778     int id;
2779     const wia_part_data_t * src_pd = src->pd;
2780     wia_part_data_t * dest_pd = dest->pd;
2781 
2782     for ( id = 0; id < sizeof(src->pd)/sizeof(src->pd[0]); id++, src_pd++, dest_pd++ )
2783     {
2784 	dest_pd->first_sector	= htonl (src_pd->first_sector);
2785 	dest_pd->n_sectors	= htonl (src_pd->n_sectors);
2786 
2787 	dest_pd->group_index	= htonl (src_pd->group_index);
2788 	dest_pd->n_groups	= htonl (src_pd->n_groups);
2789     }
2790 }
2791 
2792 ///////////////////////////////////////////////////////////////////////////////
2793 ///////////////////////////////////////////////////////////////////////////////
2794 
wia_ntoh_raw_data(wia_raw_data_t * dest,const wia_raw_data_t * src)2795 void wia_ntoh_raw_data ( wia_raw_data_t * dest, const wia_raw_data_t * src )
2796 {
2797     DASSERT(dest);
2798 
2799     if (!src)
2800 	src = dest;
2801     else if ( dest != src )
2802 	memcpy(dest,src,sizeof(*dest));
2803 
2804     dest->raw_data_off		= ntoh64(src->raw_data_off);
2805     dest->raw_data_size		= ntoh64(src->raw_data_size);
2806 
2807     dest->group_index		= ntohl (src->group_index);
2808     dest->n_groups		= ntohl (src->n_groups);
2809 }
2810 
2811 ///////////////////////////////////////////////////////////////////////////////
2812 
wia_hton_raw_data(wia_raw_data_t * dest,const wia_raw_data_t * src)2813 void wia_hton_raw_data ( wia_raw_data_t * dest, const wia_raw_data_t * src )
2814 {
2815     DASSERT(dest);
2816 
2817     if (!src)
2818 	src = dest;
2819     else if ( dest != src )
2820 	memcpy(dest,src,sizeof(*dest));
2821 
2822     dest->raw_data_off		= hton64(src->raw_data_off);
2823     dest->raw_data_size		= hton64(src->raw_data_size);
2824 
2825     dest->group_index		= htonl (src->group_index);
2826     dest->n_groups		= htonl (src->n_groups);
2827 }
2828 
2829 //
2830 ///////////////////////////////////////////////////////////////////////////////
2831 ///////////////			    E N D			///////////////
2832 ///////////////////////////////////////////////////////////////////////////////
2833 
2834