mirror of
https://github.com/holub/mame
synced 2025-05-21 05:08:54 +03:00
NOTE: With the change, all existing CHD diff files are invalid.
Updated CHD format to version 4. Checksums are now computed and stored separately for raw data and metadata, and metadata is now checksummed by default. We will need to go through all existing CHDs, run a chdman -update on them, and update the SHA1s stored in the drivers to accommodate this (MD5s should be removed). Updated chdman to support a generic metadata addition system: chdman -addmeta <chdfile> <tag> [<index>] <sourcefile> The <sourcefile> is examined and if it appears to be strictly text, any EOFs and trailing EOLs are stripped, and the result is NULL- terminated to match the behavior of existing metadata. Updated chdman to report and fix errors in the raw and metadata SHA1s. Changed the CHD verify interfaces to pass back a structure containing all the necessary data for verification and fixing.
This commit is contained in:
parent
b91848413d
commit
21b5f27224
@ -225,6 +225,7 @@ static UINT32 crcmap_find_hunk(chd_file *chd, UINT32 hunknum, UINT32 crc, const
|
||||
static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
|
||||
static chd_error metadata_set_previous_next(chd_file *chd, UINT64 prevoffset, UINT64 nextoffset);
|
||||
static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length);
|
||||
static chd_error metadata_compute_hash(chd_file *chd, UINT8 *finalsha1);
|
||||
|
||||
/* zlib compression codec */
|
||||
static chd_error zlib_codec_init(chd_file *chd);
|
||||
@ -431,6 +432,20 @@ INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbyte
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
compute_overall_sum - compute an overall
|
||||
checksum from the raw + meta hashes
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE void compute_overall_sum(UINT8 *sha1, const UINT8 *rawsha1, const UINT8 *metasha1)
|
||||
{
|
||||
int hashindex;
|
||||
|
||||
for (hashindex = 0; hashindex < CHD_SHA1_BYTES; hashindex++)
|
||||
sha1[hashindex] = rawsha1[hashindex] ^ metasha1[hashindex];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
queue_async_operation - queue a new work
|
||||
item
|
||||
@ -519,7 +534,7 @@ chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes
|
||||
|
||||
/* build the header */
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.length = CHD_V3_HEADER_SIZE;
|
||||
header.length = CHD_V4_HEADER_SIZE;
|
||||
header.version = CHD_HEADER_VERSION;
|
||||
header.flags = CHDFLAGS_IS_WRITEABLE;
|
||||
header.compression = compression;
|
||||
@ -1217,16 +1232,15 @@ chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, cons
|
||||
core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
|
||||
count = core_fwrite(chd->file, inputbuf, inputlen);
|
||||
if (count != inputlen)
|
||||
return CHDERR_WRITE_ERROR;
|
||||
{
|
||||
err = CHDERR_WRITE_ERROR;
|
||||
goto update;
|
||||
}
|
||||
|
||||
/* if the lengths don't match, we need to update the length in our header */
|
||||
if (inputlen != metaentry.length)
|
||||
{
|
||||
err = metadata_set_length(chd, metaentry.offset, inputlen);
|
||||
if (err != CHDERR_NONE)
|
||||
return err;
|
||||
}
|
||||
return CHDERR_NONE;
|
||||
goto update;
|
||||
}
|
||||
|
||||
/* if we already have an entry, unlink it */
|
||||
@ -1234,7 +1248,7 @@ chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, cons
|
||||
{
|
||||
err = metadata_set_previous_next(chd, metaentry.prev, metaentry.next);
|
||||
if (err != CHDERR_NONE)
|
||||
return err;
|
||||
goto update;
|
||||
}
|
||||
|
||||
/* now build us a new entry */
|
||||
@ -1247,20 +1261,31 @@ chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, cons
|
||||
core_fseek(chd->file, offset, SEEK_SET);
|
||||
count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
|
||||
if (count != sizeof(raw_meta_header))
|
||||
return CHDERR_WRITE_ERROR;
|
||||
{
|
||||
err = CHDERR_WRITE_ERROR;
|
||||
goto update;
|
||||
}
|
||||
|
||||
/* follow that with the data */
|
||||
core_fseek(chd->file, offset + METADATA_HEADER_SIZE, SEEK_SET);
|
||||
count = core_fwrite(chd->file, inputbuf, inputlen);
|
||||
if (count != inputlen)
|
||||
return CHDERR_WRITE_ERROR;
|
||||
{
|
||||
err = CHDERR_WRITE_ERROR;
|
||||
goto update;
|
||||
}
|
||||
|
||||
/* set the previous entry to point to us */
|
||||
err = metadata_set_previous_next(chd, metaentry.prev, offset);
|
||||
if (err != CHDERR_NONE)
|
||||
return err;
|
||||
|
||||
return CHDERR_NONE;
|
||||
update:
|
||||
/* update the hash */
|
||||
if (metadata_compute_hash(chd, chd->header.metasha1) == CHDERR_NONE)
|
||||
{
|
||||
compute_overall_sum(chd->header.sha1, chd->header.rawsha1, chd->header.metasha1);
|
||||
err = header_write(chd->file, &chd->header);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@ -1288,6 +1313,15 @@ chd_error chd_clone_metadata(chd_file *source, chd_file *dest)
|
||||
break;
|
||||
}
|
||||
|
||||
/* promote certain bits of metadata to checksummed for older CHDs */
|
||||
if (source->header.version <= 3 &&
|
||||
(metatag == HARD_DISK_METADATA_TAG || metatag == CDROM_OLD_METADATA_TAG ||
|
||||
metatag == CDROM_TRACK_METADATA_TAG || metatag == AV_METADATA_TAG ||
|
||||
metatag == AV_LD_METADATA_TAG))
|
||||
{
|
||||
metaflags |= CHD_MDFLAGS_CHECKSUM;
|
||||
}
|
||||
|
||||
/* if that fit, just write it back from the temporary buffer */
|
||||
if (metasize <= sizeof(metabuffer))
|
||||
{
|
||||
@ -1439,7 +1473,8 @@ chd_error chd_compress_finish(chd_file *chd)
|
||||
/* compute the final MD5/SHA1 values */
|
||||
MD5Final(chd->header.md5, &chd->compmd5);
|
||||
sha1_final(&chd->compsha1);
|
||||
sha1_digest(&chd->compsha1, SHA1_DIGEST_SIZE, chd->header.sha1);
|
||||
sha1_digest(&chd->compsha1, SHA1_DIGEST_SIZE, chd->header.rawsha1);
|
||||
compute_overall_sum(chd->header.sha1, chd->header.rawsha1, chd->header.metasha1);
|
||||
|
||||
/* turn off the writeable flag and re-write the header */
|
||||
chd->header.flags &= ~CHDFLAGS_IS_WRITEABLE;
|
||||
@ -1527,22 +1562,24 @@ chd_error chd_verify_hunk(chd_file *chd)
|
||||
the CHD
|
||||
-------------------------------------------------*/
|
||||
|
||||
chd_error chd_verify_finish(chd_file *chd, UINT8 *finalmd5, UINT8 *finalsha1)
|
||||
chd_error chd_verify_finish(chd_file *chd, chd_verify_result *result)
|
||||
{
|
||||
/* error if in the wrong state */
|
||||
if (!chd->verifying)
|
||||
return CHDERR_INVALID_STATE;
|
||||
|
||||
/* compute the final MD5 */
|
||||
if (finalmd5 != NULL)
|
||||
MD5Final(finalmd5, &chd->vermd5);
|
||||
MD5Final(result->md5, &chd->vermd5);
|
||||
|
||||
/* compute the final SHA1 */
|
||||
if (finalsha1 != NULL)
|
||||
{
|
||||
sha1_final(&chd->versha1);
|
||||
sha1_digest(&chd->versha1, SHA1_DIGEST_SIZE, finalsha1);
|
||||
}
|
||||
sha1_digest(&chd->versha1, SHA1_DIGEST_SIZE, result->rawsha1);
|
||||
|
||||
/* compute the metadata hash as well */
|
||||
metadata_compute_hash(chd, result->metasha1);
|
||||
|
||||
/* and the overall sum */
|
||||
compute_overall_sum(result->sha1, result->rawsha1, result->metasha1);
|
||||
|
||||
/* return an error */
|
||||
chd->verifying = FALSE;
|
||||
@ -1653,7 +1690,8 @@ static chd_error header_validate(const chd_header *header)
|
||||
/* require a valid length */
|
||||
if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
|
||||
(header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
|
||||
(header->version == 3 && header->length != CHD_V3_HEADER_SIZE))
|
||||
(header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
|
||||
(header->version == 4 && header->length != CHD_V4_HEADER_SIZE))
|
||||
return CHDERR_INVALID_PARAMETER;
|
||||
|
||||
/* require valid flags */
|
||||
@ -1706,11 +1744,11 @@ static chd_error header_read(core_file *file, chd_header *header)
|
||||
UINT32 count;
|
||||
|
||||
/* punt if NULL */
|
||||
if (!header)
|
||||
if (header == NULL)
|
||||
return CHDERR_INVALID_PARAMETER;
|
||||
|
||||
/* punt if invalid file */
|
||||
if (!file)
|
||||
if (file == NULL)
|
||||
return CHDERR_INVALID_FILE;
|
||||
|
||||
/* seek and read */
|
||||
@ -1735,14 +1773,13 @@ static chd_error header_read(core_file *file, chd_header *header)
|
||||
/* make sure the length is expected */
|
||||
if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
|
||||
(header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
|
||||
(header->version == 3 && header->length != CHD_V3_HEADER_SIZE))
|
||||
(header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
|
||||
(header->version == 4 && header->length != CHD_V4_HEADER_SIZE))
|
||||
return CHDERR_INVALID_DATA;
|
||||
|
||||
/* extract the common data */
|
||||
header->flags = get_bigendian_uint32(&rawheader[16]);
|
||||
header->compression = get_bigendian_uint32(&rawheader[20]);
|
||||
memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
|
||||
memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
|
||||
|
||||
/* extract the V1/V2-specific data */
|
||||
if (header->version < 3)
|
||||
@ -1753,20 +1790,37 @@ static chd_error header_read(core_file *file, chd_header *header)
|
||||
header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
|
||||
header->obsolete_heads = get_bigendian_uint32(&rawheader[36]);
|
||||
header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]);
|
||||
memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
|
||||
memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
|
||||
header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
|
||||
header->hunkbytes = seclen * header->obsolete_hunksize;
|
||||
header->metaoffset = 0;
|
||||
}
|
||||
|
||||
/* extract the V3-specific data */
|
||||
else if (header->version == 3)
|
||||
{
|
||||
header->totalhunks = get_bigendian_uint32(&rawheader[24]);
|
||||
header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
|
||||
header->metaoffset = get_bigendian_uint64(&rawheader[36]);
|
||||
memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
|
||||
memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
|
||||
header->hunkbytes = get_bigendian_uint32(&rawheader[76]);
|
||||
memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
|
||||
memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
|
||||
}
|
||||
|
||||
/* extract the V4-specific data */
|
||||
else
|
||||
{
|
||||
header->totalhunks = get_bigendian_uint32(&rawheader[24]);
|
||||
header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
|
||||
header->metaoffset = get_bigendian_uint64(&rawheader[36]);
|
||||
header->hunkbytes = get_bigendian_uint32(&rawheader[76]);
|
||||
memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
|
||||
memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
|
||||
header->hunkbytes = get_bigendian_uint32(&rawheader[44]);
|
||||
memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
|
||||
memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
|
||||
memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
|
||||
memcpy(header->metasha1, &rawheader[108], CHD_SHA1_BYTES);
|
||||
}
|
||||
|
||||
/* guess it worked */
|
||||
@ -1785,38 +1839,38 @@ static chd_error header_write(core_file *file, const chd_header *header)
|
||||
UINT32 count;
|
||||
|
||||
/* punt if NULL */
|
||||
if (!header)
|
||||
if (header == NULL)
|
||||
return CHDERR_INVALID_PARAMETER;
|
||||
|
||||
/* punt if invalid file */
|
||||
if (!file)
|
||||
if (file == NULL)
|
||||
return CHDERR_INVALID_FILE;
|
||||
|
||||
/* only support writing modern headers */
|
||||
if (header->version != 3)
|
||||
if (header->version != 4)
|
||||
return CHDERR_INVALID_PARAMETER;
|
||||
|
||||
/* assemble the data */
|
||||
memset(rawheader, 0, sizeof(rawheader));
|
||||
memcpy(rawheader, "MComprHD", 8);
|
||||
|
||||
put_bigendian_uint32(&rawheader[8], CHD_V3_HEADER_SIZE);
|
||||
put_bigendian_uint32(&rawheader[8], CHD_V4_HEADER_SIZE);
|
||||
put_bigendian_uint32(&rawheader[12], header->version);
|
||||
put_bigendian_uint32(&rawheader[16], header->flags);
|
||||
put_bigendian_uint32(&rawheader[20], header->compression);
|
||||
put_bigendian_uint32(&rawheader[24], header->totalhunks);
|
||||
put_bigendian_uint64(&rawheader[28], header->logicalbytes);
|
||||
put_bigendian_uint64(&rawheader[36], header->metaoffset);
|
||||
memcpy(&rawheader[44], header->md5, CHD_MD5_BYTES);
|
||||
memcpy(&rawheader[60], header->parentmd5, CHD_MD5_BYTES);
|
||||
put_bigendian_uint32(&rawheader[76], header->hunkbytes);
|
||||
memcpy(&rawheader[80], header->sha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[100], header->parentsha1, CHD_SHA1_BYTES);
|
||||
put_bigendian_uint32(&rawheader[44], header->hunkbytes);
|
||||
memcpy(&rawheader[48], header->sha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[68], header->parentsha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[88], header->rawsha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[108], header->metasha1, CHD_SHA1_BYTES);
|
||||
|
||||
/* seek and write */
|
||||
core_fseek(file, 0, SEEK_SET);
|
||||
count = core_fwrite(file, rawheader, CHD_V3_HEADER_SIZE);
|
||||
if (count != CHD_V3_HEADER_SIZE)
|
||||
count = core_fwrite(file, rawheader, CHD_V4_HEADER_SIZE);
|
||||
if (count != CHD_V4_HEADER_SIZE)
|
||||
return CHDERR_WRITE_ERROR;
|
||||
|
||||
return CHDERR_NONE;
|
||||
@ -2373,7 +2427,7 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai
|
||||
metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
|
||||
metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
|
||||
|
||||
/* checksum is encoded as the high bit of length */
|
||||
/* flags are encoded in the high byte of length */
|
||||
metaentry->flags = metaentry->length >> 24;
|
||||
metaentry->length &= 0x00ffffff;
|
||||
|
||||
@ -2467,6 +2521,89 @@ static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
metadata_compute_hash - compute the SHA1
|
||||
hash of all metadata that requests it
|
||||
-------------------------------------------------*/
|
||||
|
||||
static chd_error metadata_compute_hash(chd_file *chd, UINT8 *finalsha1)
|
||||
{
|
||||
UINT32 metatag, metasize, metaindex;
|
||||
UINT8 metabuffer[1024];
|
||||
struct sha1_ctx sha1;
|
||||
UINT8 metaflags;
|
||||
chd_error err;
|
||||
int count = 0;
|
||||
|
||||
/* only works for V4 and above */
|
||||
if (chd->header.version < 4)
|
||||
{
|
||||
memset(finalsha1, 0, SHA1_DIGEST_SIZE);
|
||||
return CHDERR_NONE;
|
||||
}
|
||||
|
||||
/* initialize the hash computation */
|
||||
sha1_init(&sha1);
|
||||
|
||||
/* iterate over the metadata */
|
||||
for (metaindex = 0; ; metaindex++)
|
||||
{
|
||||
/* fetch the next piece of metadata */
|
||||
err = chd_get_metadata(chd, CHDMETATAG_WILDCARD, metaindex, metabuffer, sizeof(metabuffer), &metasize, &metatag, &metaflags);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
if (err == CHDERR_METADATA_NOT_FOUND)
|
||||
err = CHDERR_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if this entry doesn't participate, continue */
|
||||
if (!(metaflags & CHD_MDFLAGS_CHECKSUM))
|
||||
continue;
|
||||
count++;
|
||||
|
||||
/* if that fit, compute the sum from the temporary buffer */
|
||||
if (metasize <= sizeof(metabuffer))
|
||||
sha1_update(&sha1, metasize, metabuffer);
|
||||
|
||||
/* otherwise, allocate a bigger temporary buffer */
|
||||
else
|
||||
{
|
||||
UINT8 *allocbuffer = (UINT8 *)malloc(metasize);
|
||||
if (allocbuffer == NULL)
|
||||
{
|
||||
err = CHDERR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* re-read the whole thing */
|
||||
err = chd_get_metadata(chd, CHDMETATAG_WILDCARD, metaindex, allocbuffer, metasize, &metasize, &metatag, &metaflags);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
free(allocbuffer);
|
||||
break;
|
||||
}
|
||||
|
||||
/* compute the sum over that */
|
||||
sha1_update(&sha1, metasize, allocbuffer);
|
||||
free(allocbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* finish the sum */
|
||||
if (err == CHDERR_NONE)
|
||||
{
|
||||
sha1_final(&sha1);
|
||||
sha1_digest(&sha1, SHA1_DIGEST_SIZE, finalsha1);
|
||||
|
||||
/* special case: if no entries, zero the sum */
|
||||
if (count == 0)
|
||||
memset(finalsha1, 0, SHA1_DIGEST_SIZE);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
ZLIB COMPRESSION CODEC
|
||||
|
@ -105,11 +105,12 @@
|
||||
***************************************************************************/
|
||||
|
||||
/* header information */
|
||||
#define CHD_HEADER_VERSION 3
|
||||
#define CHD_HEADER_VERSION 4
|
||||
#define CHD_V1_HEADER_SIZE 76
|
||||
#define CHD_V2_HEADER_SIZE 80
|
||||
#define CHD_V3_HEADER_SIZE 120
|
||||
#define CHD_MAX_HEADER_SIZE CHD_V3_HEADER_SIZE
|
||||
#define CHD_V4_HEADER_SIZE 128
|
||||
#define CHD_MAX_HEADER_SIZE CHD_V4_HEADER_SIZE
|
||||
|
||||
/* checksumming information */
|
||||
#define CHD_MD5_BYTES 16
|
||||
@ -213,10 +214,12 @@ struct _chd_header
|
||||
UINT32 totalhunks; /* total # of hunks represented */
|
||||
UINT64 logicalbytes; /* logical size of the data */
|
||||
UINT64 metaoffset; /* offset in file of first metadata */
|
||||
UINT8 md5[CHD_MD5_BYTES]; /* MD5 checksum of raw data */
|
||||
UINT8 parentmd5[CHD_MD5_BYTES]; /* MD5 checksum of parent file */
|
||||
UINT8 sha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
|
||||
UINT8 parentsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of parent file */
|
||||
UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */
|
||||
UINT8 parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */
|
||||
UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */
|
||||
UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
|
||||
UINT8 metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */
|
||||
UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */
|
||||
|
||||
UINT32 obsolete_cylinders; /* obsolete field -- do not use! */
|
||||
UINT32 obsolete_sectors; /* obsolete field -- do not use! */
|
||||
@ -225,6 +228,17 @@ struct _chd_header
|
||||
};
|
||||
|
||||
|
||||
/* structure for returning information about a verification pass */
|
||||
typedef struct _chd_verify_result chd_verify_result;
|
||||
struct _chd_verify_result
|
||||
{
|
||||
UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */
|
||||
UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */
|
||||
UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
|
||||
UINT8 metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
@ -323,7 +337,7 @@ chd_error chd_verify_begin(chd_file *chd);
|
||||
chd_error chd_verify_hunk(chd_file *chd);
|
||||
|
||||
/* finish verifying a CHD, returning the computed MD5 and SHA1 */
|
||||
chd_error chd_verify_finish(chd_file *chd, UINT8 *finalmd5, UINT8 *finalsha1);
|
||||
chd_error chd_verify_finish(chd_file *chd, chd_verify_result *result);
|
||||
|
||||
|
||||
|
||||
|
@ -166,6 +166,7 @@ static int usage(void)
|
||||
printf(" or: chdman -diff parent.chd compare.chd diff.chd\n");
|
||||
printf(" or: chdman -setchs inout.chd cylinders heads sectors\n");
|
||||
printf(" or: chdman -fixavdata inout.chd\n");
|
||||
printf(" or: chdman -addmeta inout.chd tag [index] sourcefile\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -309,7 +310,7 @@ static int do_createhd(int argc, char *argv[], int param)
|
||||
|
||||
/* write the metadata */
|
||||
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
|
||||
err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
|
||||
err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
|
||||
@ -480,7 +481,7 @@ static int do_createcd(int argc, char *argv[], int param)
|
||||
sprintf(metadata, CDROM_TRACK_METADATA_FORMAT, i + 1, cdrom_get_type_string(&toc.tracks[i]),
|
||||
cdrom_get_subtype_string(&toc.tracks[i]), toc.tracks[i].frames);
|
||||
|
||||
err = chd_set_metadata(chd, CDROM_TRACK_METADATA_TAG, i, metadata, strlen(metadata) + 1, 0);
|
||||
err = chd_set_metadata(chd, CDROM_TRACK_METADATA_TAG, i, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error adding CD-ROM metadata: %s\n", chd_error_string(err));
|
||||
@ -902,7 +903,7 @@ static int do_createav(int argc, char *argv[], int param)
|
||||
|
||||
/* write the metadata */
|
||||
sprintf(metadata, AV_METADATA_FORMAT, fps_times_1million / 1000000, fps_times_1million % 1000000, width, height, interlaced, channels, rate);
|
||||
err = chd_set_metadata(chd, AV_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
|
||||
err = chd_set_metadata(chd, AV_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error adding AV metadata: %s\n", chd_error_string(err));
|
||||
@ -959,7 +960,7 @@ static int do_createav(int argc, char *argv[], int param)
|
||||
/* write the final metadata */
|
||||
if (ldframedata != NULL)
|
||||
{
|
||||
err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES, 0);
|
||||
err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
|
||||
@ -1048,7 +1049,7 @@ static int do_createblankhd(int argc, char *argv[], int param)
|
||||
|
||||
/* write the metadata */
|
||||
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
|
||||
err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
|
||||
err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
|
||||
@ -1636,7 +1637,7 @@ cleanup:
|
||||
|
||||
static int do_verify(int argc, char *argv[], int param)
|
||||
{
|
||||
UINT8 actualmd5[CHD_MD5_BYTES], actualsha1[CHD_SHA1_BYTES];
|
||||
chd_verify_result verify;
|
||||
const char *inputfile;
|
||||
chd_file *chd = NULL;
|
||||
chd_header header;
|
||||
@ -1681,7 +1682,7 @@ static int do_verify(int argc, char *argv[], int param)
|
||||
|
||||
/* finish it */
|
||||
if (err == CHDERR_NONE)
|
||||
err = chd_verify_finish(chd, actualmd5, actualsha1);
|
||||
err = chd_verify_finish(chd, &verify);
|
||||
}
|
||||
|
||||
/* handle errors */
|
||||
@ -1695,7 +1696,9 @@ static int do_verify(int argc, char *argv[], int param)
|
||||
}
|
||||
|
||||
/* verify the MD5 */
|
||||
if (memcmp(header.md5, actualmd5, sizeof(header.md5)) == 0)
|
||||
if (header.version <= 3)
|
||||
{
|
||||
if (memcmp(header.md5, verify.md5, sizeof(header.md5)) == 0)
|
||||
printf("MD5 verification successful!\n");
|
||||
else
|
||||
{
|
||||
@ -1705,21 +1708,22 @@ static int do_verify(int argc, char *argv[], int param)
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " actual MD5 = ");
|
||||
for (i = 0; i < CHD_MD5_BYTES; i++)
|
||||
fprintf(stderr, "%02x", actualmd5[i]);
|
||||
fprintf(stderr, "%02x", verify.md5[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* fix it */
|
||||
if (param)
|
||||
{
|
||||
memcpy(header.md5, actualmd5, sizeof(header.md5));
|
||||
memcpy(header.md5, verify.md5, sizeof(header.md5));
|
||||
fixed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* verify the SHA1 */
|
||||
if (header.version >= 3)
|
||||
{
|
||||
if (memcmp(header.sha1, actualsha1, sizeof(header.sha1)) == 0)
|
||||
if (memcmp(header.sha1, verify.sha1, sizeof(header.sha1)) == 0)
|
||||
printf("SHA1 verification successful!\n");
|
||||
else
|
||||
{
|
||||
@ -1729,15 +1733,57 @@ static int do_verify(int argc, char *argv[], int param)
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " actual SHA1 = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", actualsha1[i]);
|
||||
fprintf(stderr, "%02x", verify.sha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* fix it */
|
||||
if (param)
|
||||
{
|
||||
memcpy(header.sha1, actualsha1, sizeof(header.sha1));
|
||||
memcpy(header.sha1, verify.sha1, sizeof(header.sha1));
|
||||
fixed = TRUE;
|
||||
}
|
||||
|
||||
/* verify the raw SHA1 */
|
||||
if (header.version >= 4)
|
||||
{
|
||||
if (memcmp(header.rawsha1, verify.rawsha1, sizeof(header.rawsha1)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Error: raw SHA1 in header = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", header.rawsha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " actual raw SHA1 = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", verify.rawsha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* fix it */
|
||||
if (param)
|
||||
{
|
||||
memcpy(header.rawsha1, verify.rawsha1, sizeof(header.rawsha1));
|
||||
fixed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(header.rawsha1, verify.metasha1, sizeof(header.metasha1)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Error: metadata SHA1 in header = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", header.metasha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " actual metadata SHA1 = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", verify.metasha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* fix it */
|
||||
if (param)
|
||||
{
|
||||
memcpy(header.metasha1, verify.metasha1, sizeof(header.metasha1));
|
||||
fixed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1967,7 +2013,7 @@ static int do_fixavdata(int argc, char *argv[], int param)
|
||||
}
|
||||
|
||||
/* write new metadata */
|
||||
err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, 0);
|
||||
err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
|
||||
@ -2036,7 +2082,7 @@ static int do_info(int argc, char *argv[], int param)
|
||||
printf("Hunk Size: %d bytes\n", header.hunkbytes);
|
||||
printf("Total Hunks: %d\n", header.totalhunks);
|
||||
printf("Logical size: %s bytes\n", big_int_string(header.logicalbytes));
|
||||
if (!(header.flags & CHDFLAGS_IS_WRITEABLE))
|
||||
if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version <= 3)
|
||||
printf("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
header.md5[0], header.md5[1], header.md5[2], header.md5[3],
|
||||
header.md5[4], header.md5[5], header.md5[6], header.md5[7],
|
||||
@ -2049,6 +2095,21 @@ static int do_info(int argc, char *argv[], int param)
|
||||
header.sha1[8], header.sha1[9], header.sha1[10], header.sha1[11],
|
||||
header.sha1[12], header.sha1[13], header.sha1[14], header.sha1[15],
|
||||
header.sha1[16], header.sha1[17], header.sha1[18], header.sha1[19]);
|
||||
if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version >= 4)
|
||||
{
|
||||
printf("Raw SHA1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
header.rawsha1[0], header.rawsha1[1], header.rawsha1[2], header.rawsha1[3],
|
||||
header.rawsha1[4], header.rawsha1[5], header.rawsha1[6], header.rawsha1[7],
|
||||
header.rawsha1[8], header.rawsha1[9], header.rawsha1[10], header.rawsha1[11],
|
||||
header.rawsha1[12], header.rawsha1[13], header.rawsha1[14], header.rawsha1[15],
|
||||
header.rawsha1[16], header.rawsha1[17], header.rawsha1[18], header.rawsha1[19]);
|
||||
printf("Metadata SHA1:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
header.metasha1[0], header.metasha1[1], header.metasha1[2], header.metasha1[3],
|
||||
header.metasha1[4], header.metasha1[5], header.metasha1[6], header.metasha1[7],
|
||||
header.metasha1[8], header.metasha1[9], header.metasha1[10], header.metasha1[11],
|
||||
header.metasha1[12], header.metasha1[13], header.metasha1[14], header.metasha1[15],
|
||||
header.metasha1[16], header.metasha1[17], header.metasha1[18], header.metasha1[19]);
|
||||
}
|
||||
if (header.flags & CHDFLAGS_HAS_PARENT)
|
||||
{
|
||||
printf("Parent MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
@ -2494,7 +2555,7 @@ static int do_setchs(int argc, char *argv[], int param)
|
||||
|
||||
/* write our own */
|
||||
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cyls, hds, secs, oldsecsize);
|
||||
err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
|
||||
err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err));
|
||||
@ -2540,6 +2601,186 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
do_addmeta - add metadata to a CHD from a
|
||||
file
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int do_addmeta(int argc, char *argv[], int param)
|
||||
{
|
||||
const char *inoutfile, *srcfile, *tagstring;
|
||||
UINT8 was_readonly = FALSE;
|
||||
core_file *sourcefile = NULL;
|
||||
UINT8 *metadata = NULL;
|
||||
chd_file *chd = NULL;
|
||||
chd_header header;
|
||||
file_error filerr;
|
||||
UINT32 metalength;
|
||||
UINT32 metaindex;
|
||||
UINT32 metatag;
|
||||
UINT32 chindex;
|
||||
chd_error err;
|
||||
int istext;
|
||||
|
||||
/* require 5 or 6 args total */
|
||||
if (argc != 5 && argc != 6)
|
||||
return usage();
|
||||
|
||||
/* extract the data */
|
||||
inoutfile = argv[2];
|
||||
tagstring = argv[3];
|
||||
if (argc == 5)
|
||||
{
|
||||
metaindex = 0;
|
||||
srcfile = argv[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
metaindex = atoi(argv[4]);
|
||||
srcfile = argv[5];
|
||||
}
|
||||
|
||||
/* verify the tag */
|
||||
if (strlen(tagstring) > 4)
|
||||
{
|
||||
fprintf(stderr, "Invalid tag '%s'; must be 4 characters or less\n", tagstring);
|
||||
return CHDERR_INVALID_PARAMETER;
|
||||
}
|
||||
metatag = ((tagstring[0] == 0) ? ' ' : tagstring[0]) << 24;
|
||||
metatag |= ((tagstring[1] == 0) ? ' ' : tagstring[1]) << 16;
|
||||
metatag |= ((tagstring[2] == 0) ? ' ' : tagstring[2]) << 8;
|
||||
metatag |= ((tagstring[3] == 0) ? ' ' : tagstring[3]) << 0;
|
||||
|
||||
/* print some info */
|
||||
printf("Input file: %s\n", inoutfile);
|
||||
printf("Tag: '%c%c%c%c'\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff);
|
||||
printf("Index: %d\n", metaindex);
|
||||
printf("Source file: %s\n", srcfile);
|
||||
|
||||
/* open the file read-only and get the header */
|
||||
err = chd_open(inoutfile, CHD_OPEN_READ, NULL, &chd);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error opening CHD file '%s' read-only: %s\n", inoutfile, chd_error_string(err));
|
||||
goto cleanup;
|
||||
}
|
||||
header = *chd_get_header(chd);
|
||||
chd_close(chd);
|
||||
chd = NULL;
|
||||
|
||||
/* if the drive is not writeable, note that, and make it so */
|
||||
if (!(header.flags & CHDFLAGS_IS_WRITEABLE))
|
||||
{
|
||||
was_readonly = TRUE;
|
||||
header.flags |= CHDFLAGS_IS_WRITEABLE;
|
||||
|
||||
/* write the new header */
|
||||
err = chd_set_header(inoutfile, &header);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error making CHD file writeable: %s\n", chd_error_string(err));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* open the file read/write */
|
||||
err = chd_open(inoutfile, CHD_OPEN_READWRITE, NULL, &chd);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error opening CHD file '%s' read/write: %s\n", inoutfile, chd_error_string(err));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* attempt to open the source file */
|
||||
filerr = core_fopen(srcfile, OPEN_FLAG_READ, &sourcefile);
|
||||
if (filerr != FILERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error opening source file '%s'\n", srcfile);
|
||||
err = CHDERR_FILE_NOT_FOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* allocate memory */
|
||||
metalength = core_fsize(sourcefile);
|
||||
if (metalength == 0 || metalength >= 16 * 1024 * 1024)
|
||||
{
|
||||
fprintf(stderr, "Source file '%s' is either 0-length or too large (must be under 16MB)\n", srcfile);
|
||||
err = CHDERR_INVALID_PARAMETER;
|
||||
goto cleanup;
|
||||
}
|
||||
metadata = malloc(metalength + 1);
|
||||
if (metadata == NULL)
|
||||
{
|
||||
fprintf(stderr, "Out of memory allocating source file buffer\n");
|
||||
err = CHDERR_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* read in the data */
|
||||
if (core_fread(sourcefile, metadata, metalength) != metalength)
|
||||
{
|
||||
fprintf(stderr, "Error reading source file\n");
|
||||
err = CHDERR_READ_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* analyze the data */
|
||||
istext = FALSE;
|
||||
for (chindex = 0; chindex < metalength; chindex++)
|
||||
if (metadata[chindex] != 0x0d && metadata[chindex] != 0x0a && metadata[chindex] != 0x09 &&
|
||||
(metadata[chindex] < ' ' || metadata[chindex] >= 0x7f))
|
||||
break;
|
||||
|
||||
/* if it's text, strip any trailing Ctrl-Z and CR/LF and add a trailing NULL */
|
||||
if (chindex == metalength || (chindex == metalength - 1 && metadata[chindex] == 0x1a))
|
||||
{
|
||||
istext = TRUE;
|
||||
metalength = chindex + 1;
|
||||
metadata[metalength - 1] = 0;
|
||||
while (metalength > 0 && (metadata[metalength - 2] == 0x0a || metadata[metalength - 2] == 0x0d || metadata[metalength - 2] == 0x1a))
|
||||
metadata[--metalength] = 0;
|
||||
}
|
||||
|
||||
/* write the new metadata */
|
||||
err = chd_set_metadata(chd, metatag, metaindex, metadata, metalength, CHD_MDFLAGS_CHECKSUM);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err));
|
||||
goto cleanup;
|
||||
}
|
||||
header = *chd_get_header(chd);
|
||||
|
||||
/* close the file */
|
||||
chd_close(chd);
|
||||
chd = NULL;
|
||||
|
||||
/* restore the read-only state */
|
||||
if (was_readonly)
|
||||
{
|
||||
header.flags &= ~CHDFLAGS_IS_WRITEABLE;
|
||||
err = chd_set_header(inoutfile, &header);
|
||||
if (err != CHDERR_NONE)
|
||||
fprintf(stderr, "Error writing new header to CHD file: %s\n", chd_error_string(err));
|
||||
}
|
||||
if (err == CHDERR_NONE)
|
||||
printf("Metadata added successfully as %s\n", istext ? "text" : "binary");
|
||||
|
||||
cleanup:
|
||||
if (metadata != NULL)
|
||||
free(metadata);
|
||||
if (sourcefile != NULL)
|
||||
core_fclose(sourcefile);
|
||||
if (chd != NULL)
|
||||
chd_close(chd);
|
||||
if (err != CHDERR_NONE && was_readonly)
|
||||
{
|
||||
header.flags &= ~CHDFLAGS_IS_WRITEABLE;
|
||||
chd_set_header(inoutfile, &header);
|
||||
}
|
||||
return (err != CHDERR_NONE);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
chdman_compress_file - compress a regular
|
||||
file via the compression interfaces
|
||||
@ -2713,17 +2954,16 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
|
||||
if (verifyerr == CHDERR_NONE && source_offset >= source_header->logicalbytes)
|
||||
{
|
||||
static const UINT8 empty_checksum[CHD_SHA1_BYTES] = { 0 };
|
||||
UINT8 md5[CHD_MD5_BYTES];
|
||||
UINT8 sha1[CHD_SHA1_BYTES];
|
||||
chd_verify_result verify;
|
||||
int i;
|
||||
|
||||
/* get the final values */
|
||||
err = chd_verify_finish(source, md5, sha1);
|
||||
err = chd_verify_finish(source, &verify);
|
||||
|
||||
/* check the MD5 */
|
||||
if (memcmp(source_header->md5, empty_checksum, CHD_MD5_BYTES) != 0)
|
||||
{
|
||||
if (memcmp(source_header->md5, md5, CHD_MD5_BYTES) != 0)
|
||||
if (memcmp(source_header->md5, verify.md5, CHD_MD5_BYTES) != 0)
|
||||
{
|
||||
progress(TRUE, "WARNING: expected input MD5 = ");
|
||||
for (i = 0; i < CHD_MD5_BYTES; i++)
|
||||
@ -2732,7 +2972,7 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
|
||||
|
||||
progress(TRUE, " actual MD5 = ");
|
||||
for (i = 0; i < CHD_MD5_BYTES; i++)
|
||||
progress(TRUE, "%02x", md5[i]);
|
||||
progress(TRUE, "%02x", verify.md5[i]);
|
||||
progress(TRUE, "\n");
|
||||
}
|
||||
else
|
||||
@ -2742,7 +2982,7 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
|
||||
/* check the SHA1 */
|
||||
if (memcmp(source_header->sha1, empty_checksum, CHD_SHA1_BYTES) != 0)
|
||||
{
|
||||
if (memcmp(source_header->sha1, sha1, CHD_SHA1_BYTES) != 0)
|
||||
if (memcmp(source_header->sha1, verify.sha1, CHD_SHA1_BYTES) != 0)
|
||||
{
|
||||
progress(TRUE, "WARNING: expected input SHA1 = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
@ -2751,7 +2991,7 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
|
||||
|
||||
progress(TRUE, " actual SHA1 = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
progress(TRUE, "%02x", sha1[i]);
|
||||
progress(TRUE, "%02x", verify.sha1[i]);
|
||||
progress(TRUE, "\n");
|
||||
}
|
||||
else
|
||||
@ -2806,7 +3046,8 @@ int CLIB_DECL main(int argc, char **argv)
|
||||
{ "-merge", do_merge_update_chomp, OPERATION_MERGE },
|
||||
{ "-diff", do_diff, 0 },
|
||||
{ "-setchs", do_setchs, 0 },
|
||||
{ "-fixavdata", do_fixavdata, 0 }
|
||||
{ "-fixavdata", do_fixavdata, 0 },
|
||||
{ "-addmeta", do_addmeta, 0 },
|
||||
};
|
||||
extern char build_version[];
|
||||
int i;
|
||||
|
Loading…
Reference in New Issue
Block a user