/* KallistiOS ##version##
vmu_pkg.c
(c)2002 Dan Potter
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dc/vmu_pkg.h>
CVSID("$Id: vmu_pkg.c,v 1.3 2003/01/17 02:56:45 bardtx Exp $");
/*
VMU data files can be stored raw, but if you want to interact with the
rest of the DC world, it's much better to package them in a nice data
file format. This module takes care of that for you.
Thanks to Marcus Comstedt for this information.
*/
/* CRC calculation: calculates the CRC on a VMU file to be written out */
static int vmu_pkg_crc(const uint8 * buf, int size) {
int i, c, n;
for (i=0, n=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 int vmu_eyecatch_size(int eyecatch_type) {
switch(eyecatch_type) {
case VMUPKG_EC_NONE:
return 0;
case VMUPKG_EC_16BIT:
return 72 * 56 * 2;
case VMUPKG_EC_256COL:
return 512 + 72*56;
case VMUPKG_EC_16COL:
return 32 + 72*56/2;
default:
return -1;
}
}
/* Converts a vmu_pkg_t structure into an array of uint8's which may be
written to a VMU file via fs_vmu, or whatever. */
int vmu_pkg_build(vmu_pkg_t *src, uint8 ** dst, int * dst_size) {
uint8 *out;
int ec_size, out_size;
vmu_hdr_t *hdr;
/* First off, figure out how big it will be */
out_size = sizeof(vmu_hdr_t) + 512 * src->icon_cnt + src->data_len;
ec_size = vmu_eyecatch_size(src->eyecatch_type);
if (ec_size < 0) return -1;
out_size += ec_size;
*dst_size = out_size;
/* Allocate a return array */
out = *dst = malloc(out_size);
/* Setup some defaults */
memset(out, 0, out_size);
hdr = (vmu_hdr_t *)out;
memset(hdr->desc_short, 32, sizeof(hdr->desc_short));
memset(hdr->desc_long, 32, sizeof(hdr->desc_long));
/* Fill in the data from the pkg struct */
memcpy(hdr->desc_short, src->desc_short, strlen(src->desc_short));
memcpy(hdr->desc_long, src->desc_long, strlen(src->desc_long));
strcpy(hdr->app_id, src->app_id);
hdr->icon_cnt = src->icon_cnt;
hdr->icon_anim_speed = src->icon_anim_speed;
hdr->eyecatch_type = src->eyecatch_type;
hdr->crc = 0;
hdr->data_len = src->data_len;
memcpy(hdr->icon_pal, src->icon_pal, sizeof(src->icon_pal));
out += sizeof(vmu_hdr_t);
memcpy(out, src->icon_data, 512 * src->icon_cnt);
out += 512 * src->icon_cnt;
memcpy(out, src->eyecatch_data, ec_size);
out += ec_size;
memcpy(out, src->data, src->data_len);
out += src->data_len;
/* Verify the size */
assert( (out - *dst) == out_size );
out = *dst;
/* Calculate CRC */
hdr->crc = vmu_pkg_crc(out, out_size);
return 0;
}
/* Parse an array of uint8's (i.e. a VMU data file) into a
* vmu_pkg_t package structure. */
int vmu_pkg_parse(uint8 *data, vmu_pkg_t *pkg) {
uint16 crc, crc_save;
int ec_size, hdr_size, total_size, icon_size;
vmu_hdr_t *hdr;
hdr = (vmu_hdr_t *)data;
icon_size = 512 * hdr->icon_cnt;
ec_size = vmu_eyecatch_size(hdr->eyecatch_type);
hdr_size = sizeof(vmu_hdr_t) + icon_size + ec_size;
total_size = hdr->data_len + hdr_size;
/* Verify the CRC. Note: this writes a zero byte into data[].
* The byte is later restored in case data is an mmapped pointer to a
* writable file, and a new header is not generated by the user. */
crc_save = hdr->crc;
hdr->crc = 0;
crc = vmu_pkg_crc(data, total_size);
hdr->crc = crc_save;
if (crc_save != crc) {
dbglog(DBG_ERROR, "vmu_pkg_parse: expected CRC %04x, got %04x\n", crc_save, crc);
return -1;
}
/* Fill in pkg struct for caller. */
pkg->icon_cnt = hdr->icon_cnt;
pkg->icon_anim_speed = hdr->icon_anim_speed;
pkg->eyecatch_type = hdr->eyecatch_type;
pkg->data_len = hdr->data_len;
memcpy(pkg->icon_pal, hdr->icon_pal, sizeof(hdr->icon_pal));
pkg->icon_data = data + sizeof(vmu_hdr_t);
pkg->eyecatch_data = data + sizeof(vmu_hdr_t) + icon_size;
pkg->data = data + hdr_size;
/* Copy space and null-padded fields, keeping the padding,
* and ensure our representations are null-terminated. */
memcpy(pkg->desc_short, hdr->desc_short, sizeof(hdr->desc_short));
memcpy(pkg->desc_long, hdr->desc_long, sizeof(hdr->desc_long));
memcpy(pkg->app_id, hdr->app_id, sizeof(hdr->app_id));
*(pkg->desc_short + sizeof(hdr->desc_short)) = '\0';
*(pkg->desc_long + sizeof(hdr->desc_long)) = '\0';
*(pkg->app_id + sizeof(hdr->app_id)) = '\0';
return 0;
}