2009-04-22 20:04:28 +02:00

647 lines
19 KiB
C

/*
dc.c - Dreamcast support for uCON64
Copyright (c) 2004 NoisyB <noisyb@gmx.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "misc/file.h"
#include "misc/misc.h"
#include "misc/property.h"
#include "misc/string.h"
#ifdef USE_ZLIB
#include "misc/archive.h"
#endif
#include "misc/getopt2.h" // st_getopt2_t
#include "ucon64.h"
#include "ucon64_misc.h"
#include "dc.h"
const st_getopt2_t dc_usage[] =
{
{
NULL, 0, 0, 0,
NULL, "Dreamcast" /* "1998 SEGA http://www.sega.com" */,
NULL
},
{
"dc", 0, 0, UCON64_DC,
NULL, "force recognition",
&ucon64_wf[WF_OBJ_DC_SWITCH]
},
#if 0
{
"vms", 1, 0, UCON64_VMS,
"SAV", "convert NES SAV file to a VMS file for use with NesterDC",
NULL
},
#endif
{
"scr", 0, 0, UCON64_SCR,
NULL, "scramble 1ST_READ.BIN for selfboot CDs",
&ucon64_wf[WF_OBJ_DC_DEFAULT]
},
{
"unscr", 0, 0, UCON64_UNSCR,
NULL, "unscramble 1ST_READ.BIN for non-selfboot CDs",
&ucon64_wf[WF_OBJ_DC_DEFAULT]
},
#if 0
{
"ip", 1, 0, UCON64_IP,
"FILE", "extract ip.bin FILE from IMAGE; " OPTION_LONG_S "rom=IMAGE",
NULL
},
#endif
{
"mkip", 0, 0, UCON64_MKIP,
NULL, "generate IP.BIN file with default values",
&ucon64_wf[WF_OBJ_DC_NO_ROM]
},
{
"parse", 1, 0, UCON64_PARSE,
"TEMPLATE", "parse TEMPLATE file into a IP.BIN;\n"
"creates an empty template when TEMPLATE does not exist",
&ucon64_wf[WF_OBJ_DC_NO_ROM]
},
{NULL, 0, 0, 0, NULL, NULL, NULL}
};
static int
calc_crc (const unsigned char *buf, int size)
{
int i, c, n = 0xffff;
for (i = 0; i < size; i++)
{
n ^= (buf[i] << 8);
for (c = 0; c < 8; c++)
if (n & 0x8000)
n = (n << 1) ^ 4129;
else
n = (n << 1);
}
return n & 0xffff;
}
static void
update_crc (char *ip)
{
int n = calc_crc ((unsigned char *) (ip + 0x40), 16);
char buf[5];
sprintf (buf, "%04X", n);
if (memcmp (buf, ip + 0x20, 4))
{
printf ("Setting CRC to %s (was %.4s)\n", buf, ip + 0x20);
memcpy (ip + 0x20, buf, 4);
}
}
static unsigned int seed;
static void
dc_srand (unsigned int n)
{
seed = n & 0xffff;
}
static unsigned int
dc_rand ()
{
seed = (seed * 2109 + 9273) & 0x7fff;
return (seed + 0xc000) & 0xffff;
}
#if 0
// header for SAV -> VMS conversion
static const uint8_t nstrsave_bin[1024] = {
0x4e, 0x45, 0x53, 0x52, 0x4f, 0x4d, 0x2e, 0x4e, // 0x8 (8)
0x45, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 (16)
0x4e, 0x65, 0x73, 0x74, 0x65, 0x72, 0x44, 0x43, // 0x18 (24)
0x20, 0x53, 0x61, 0x76, 0x65, 0x52, 0x61, 0x6d, // 0x20 (32)
0x20, 0x46, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x00, // 0x28 (40)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x30 (48)
0x2a, 0x2a, 0x2a, 0x4e, 0x65, 0x73, 0x74, 0x65, // 0x38 (56)
0x72, 0x44, 0x43, 0x2a, 0x2a, 0x2a, 0x00, 0x00, // 0x40 (64)
0x01, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x00, 0x00, // 0x48 (72)
0x80, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50 (80)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x58 (88)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60 (96)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x68 (104)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70 (112)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x78 (120)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x80 (128)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x88 (136)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x90 (144)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x98 (152)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa0 (160)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xa8 (168)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb0 (176)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xb8 (184)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0 (192)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc8 (200)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd0 (208)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xd8 (216)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xe0 (224)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xe8 (232)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf0 (240)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xf8 (248)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x100 (256)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x108 (264)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x110 (272)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x118 (280)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x120 (288)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x128 (296)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x130 (304)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x138 (312)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x140 (320)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x148 (328)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x150 (336)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x158 (344)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x160 (352)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x168 (360)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x170 (368)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x178 (376)
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x180 (384)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x188 (392)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x190 (400)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x198 (408)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1a0 (416)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1a8 (424)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1b0 (432)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1b8 (440)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1c0 (448)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1c8 (456)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1d0 (464)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1d8 (472)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1e0 (480)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1e8 (488)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1f0 (496)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x1f8 (504)
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, // 0x200 (512)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x208 (520)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x210 (528)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x218 (536)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x220 (544)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x228 (552)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x230 (560)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x238 (568)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x240 (576)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x248 (584)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x250 (592)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x258 (600)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x260 (608)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x268 (616)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x270 (624)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x278 (632)
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, // 0x280 (640)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x288 (648)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x290 (656)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x298 (664)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2a0 (672)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2a8 (680)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2b0 (688)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2b8 (696)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2c0 (704)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2c8 (712)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2d0 (720)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2d8 (728)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2e0 (736)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2e8 (744)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2f0 (752)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x2f8 (760)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x300 (768)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x308 (776)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x310 (784)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x318 (792)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x320 (800)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x328 (808)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x330 (816)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x338 (824)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x340 (832)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x348 (840)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x350 (848)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x358 (856)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x360 (864)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x368 (872)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x370 (880)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x378 (888)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x380 (896)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x388 (904)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x390 (912)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x398 (920)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3a0 (928)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3a8 (936)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3b0 (944)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3b8 (952)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3c0 (960)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3c8 (968)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3d0 (976)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3d8 (984)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3e0 (992)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3e8 (1000)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3f0 (1008)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x3f8 (1016)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x400 (1024)
};
#endif
int
dc_init (st_rominfo_t *rominfo)
{
int result = -1;
rominfo->console_usage = dc_usage[0].help;
return result;
}
static int
check_areasym (char *ptr, int len)
{
int i, a = 0;
for (i = 0; i < len; i++)
switch (ptr[i])
{
case 'J':
a |= (1<<0);
break;
case 'U':
a |= (1<<1);
break;
case 'E':
a |= (1<<2);
break;
case ' ':
break;
default:
fprintf (stderr, "ERROR: Unknown area symbol '%c'\n", ptr[i]);
return -1;
}
for (i = 0; i < len; i++)
if ((a & (1<<i)) == 0)
ptr[i] = ' ';
else
ptr[i] = "JUE"[i];
return 0;
}
typedef struct
{
char *name;
int pos;
int len;
int (*extra_check) (char *, int);
char *def;
char *comment;
} st_templ_t;
st_templ_t templ[] =
{
{"hardware_id", 0x0, 0x10, NULL, "SEGA SEGAKATANA", "Hardware ID (always \"SEGA SEGAKATANA\")"},
{"maker_id", 0x10, 0x10, NULL, "SEGA ENTERPRISES", "Maker ID (always \"SEGA ENTERPRISES\")"},
{"device_info", 0x20, 0x10, NULL, "0000 CD-ROM1/1", "Device Information"},
{"area_symbols", 0x30, 0x8, check_areasym, "JUE", "Area Symbols"},
{"peripherals", 0x38, 0x8, NULL, "E000F10", "Peripherals"},
{"product_no", 0x40, 0xa, NULL, "T0000", "Product number (\"HDR-nnnn\" etc.)"},
{"version", 0x4a, 0x6, NULL, "V1.000", "Product version"},
{"release_date", 0x50, 0x10, NULL, "20000627", "Release date (YYYYMMDD)"},
{"boot_filename", 0x60, 0x10, NULL, "1ST_READ.BIN", "Boot filename (usually \"1ST_READ.BIN\")"},
{"sw_maker_name", 0x70, 0x10, NULL, "YOUR NAME HERE", "Name of the company that produced the disc"},
{"game_title", 0x80, 0x80, NULL, "TITLE OF THE SOFTWARE", "Name of the software"},
{NULL, 0, 0, NULL, NULL, NULL}
};
static int
parse_templ (const char *templ_file, char *ip)
{
int filled_in[MAXBUFSIZE];
static char buf[MAXBUFSIZE];
int i;
memset (filled_in, 0, sizeof (filled_in));
for (i = 0; templ[i].name; i++)
{
char *p = buf;
get_property (templ_file, templ[i].name, p, templ[i].def);
strtriml (strtrimr (p));
if (!(*p))
continue;
memset (ip + templ[i].pos, ' ', templ[i].len);
if ((int) strlen (p) > templ[i].len)
{
fprintf (stderr, "ERROR: Data for field \"%s\" is too long... stripping to %d chars\n",
templ[i].name, templ[i].len);
p[templ[i].len] = 0;
}
memcpy (ip + templ[i].pos, p, strlen (p));
if (templ[i].extra_check)
if (templ[i].extra_check (ip + templ[i].pos, templ[i].len) == -1)
return -1;
filled_in[i] = 1;
}
for (i = 0; templ[i].name; i++)
if (!filled_in[i])
{
fprintf (stderr, "ERROR: Missing value for \"%s\"\n", templ[i].name);
return -1;
}
return 0;
}
int
dc_parse (const char *templ_file)
{
char ip[0x8000], dest_name[FILENAME_MAX];
if (access (templ_file, F_OK) == -1)
{
int i = 0;
printf ("Creating empty template file: \"%s\"\n", templ_file);
for (i = 0; templ[i].name; i++)
set_property (templ_file, templ[i].name, templ[i].def, templ[i].comment);
printf (ucon64_msg[WROTE], templ_file);
}
if (parse_templ (templ_file, ip) == -1)
return -1;
update_crc (ip);
strcpy (dest_name, "ip.bin");
ucon64_file_handler (dest_name, NULL, 0);
ucon64_fwrite (ip, 0, 0x8000, dest_name, "wb");
printf (ucon64_msg[WROTE], dest_name);
return 0;
}
int
dc_mkip (void)
{
dc_parse ("default");
return 0;
}
static int
load_chunk (FILE * fh, unsigned char *ptr, int32_t sz)
{
#define MAXCHUNK (2048*1024)
static int idx[MAXCHUNK / 32];
int32_t i;
/* Convert chunk size to number of slices */
sz /= 32;
/* Initialize index table with unity,
so that each slice gets loaded exactly once */
for (i = 0; i < sz; i++)
idx[i] = i;
for (i = sz - 1; i >= 0; --i)
{
/* Select a replacement index */
int x = (dc_rand () * i) >> 16;
/* Swap */
int tmp = idx[i];
idx[i] = idx[x];
idx[x] = tmp;
/* Load resulting slice */
if (fread (ptr + 32 * idx[i], 1, 32, fh) != 32)
return -1;
}
return 0;
}
static int
load_file (FILE * fh, unsigned char *ptr, uint32_t filesz)
{
uint32_t chunksz;
dc_srand (filesz);
/* Descramble 2 meg blocks for as long as possible, then
gradually reduce the window down to 32 bytes (1 slice) */
for (chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1)
while (filesz >= chunksz)
{
load_chunk (fh, ptr, chunksz);
filesz -= chunksz;
ptr += chunksz;
}
/* Load final incomplete slice */
if (filesz)
if (fread (ptr, 1, filesz, fh) != filesz)
return -1;
return 0;
}
static int
save_chunk (FILE * fh, unsigned char *ptr, int32_t sz)
{
static int idx[MAXCHUNK / 32];
int32_t i;
/* Convert chunk size to number of slices */
sz /= 32;
/* Initialize index table with unity,
so that each slice gets saved exactly once */
for (i = 0; i < sz; i++)
idx[i] = i;
for (i = sz - 1; i >= 0; --i)
{
/* Select a replacement index */
int x = (dc_rand () * i) >> 16;
/* Swap */
int tmp = idx[i];
idx[i] = idx[x];
idx[x] = tmp;
/* Save resulting slice */
if (fwrite (ptr + 32 * idx[i], 1, 32, fh) != 32)
return -1;
}
return 0;
}
static int
save_file (FILE * fh, unsigned char *ptr, uint32_t filesz)
{
uint32_t chunksz;
dc_srand (filesz);
/* Descramble 2 meg blocks for as long as possible, then
gradually reduce the window down to 32 bytes (1 slice) */
for (chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1)
while (filesz >= chunksz)
{
save_chunk (fh, ptr, chunksz);
filesz -= chunksz;
ptr += chunksz;
}
/* Save final incomplete slice */
if (filesz)
if (fwrite (ptr, 1, filesz, fh) != filesz)
return -1;
return 0;
}
static int
descramble (const char *src, char *dst)
{
unsigned char *ptr = NULL;
uint32_t sz = 0;
FILE *fh;
if (!(fh = fopen (src, "rb")))
return -1;
sz = fsizeof (src);
if (!(ptr = (unsigned char *) malloc (sz)))
return -1;
load_file (fh, ptr, sz);
fclose (fh);
if (!(fh = fopen (dst, "wb")))
return -1;
if (fwrite (ptr, 1, sz, fh) != sz)
return -1;
fclose (fh);
free (ptr);
return 0;
}
static int
scramble (const char *src, char *dst)
{
unsigned char *ptr = NULL;
uint32_t sz = 0;
FILE *fh;
if (!(fh = fopen (src, "rb")))
return -1;
sz = fsizeof (src);
if (!(ptr = (unsigned char *) malloc (sz)))
return -1;
if (fread (ptr, 1, sz, fh) != sz)
return -1;
fclose (fh);
if (!(fh == fopen (dst, "wb")))
return -1;
save_file (fh, ptr, sz);
fclose (fh);
free (ptr);
return 0;
}
int
dc_scramble (void)
{
char dest_name[FILENAME_MAX];
strcpy (dest_name, ucon64.rom);
ucon64_file_handler (dest_name, NULL, 0);
if (!scramble (ucon64.rom, dest_name))
printf (ucon64_msg[WROTE], dest_name);
else
fprintf (stderr, ucon64_msg[WRITE_ERROR], dest_name);
return 0;
}
int
dc_unscramble (void)
{
char dest_name[FILENAME_MAX];
strcpy (dest_name, ucon64.rom);
ucon64_file_handler (dest_name, NULL, 0);
if (!descramble (ucon64.rom, dest_name))
printf (ucon64_msg[WROTE], dest_name);
else
fprintf (stderr, ucon64_msg[WRITE_ERROR], dest_name);
return 0;
}