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