uint32 hio_read24b(HIO_HANDLE *h) { if (HIO_HANDLE_TYPE(h) == HIO_HANDLE_TYPE_FILE) { return read24b(h->f); } else { ptrdiff_t can_read = CAN_READ(h); if (can_read >= 3) { uint32 n = readmem24b(h->start + h->pos); h->pos += 3; return n; } else { h->pos += can_read; return EOF; } } }
static int decrunch_pp(FILE *f, FILE *fo) { uint8 *packed /*, *unpacked */; int plen, unplen; struct stat st; if (fo == NULL) goto err; if (fstat(fileno(f), &st) < 0) goto err; plen = st.st_size; //counter = 0; /* Amiga longwords are only on even addresses. * The pp20 data format has the length stored in a longword * after the packed data, so I guess a file that is not even * is probl not a valid pp20 file. Thanks for Don Adan for * reminding me on this! - mld */ if ((plen != (plen / 2) * 2)) { /*fprintf(stderr, "filesize not even\n");*/ goto err; } packed = malloc(plen); if (packed == NULL) { /*fprintf(stderr, "can't allocate memory for packed data\n");*/ goto err; } if (fread(packed, 1, plen, f) != plen) { goto err1; } /* Hmmh... original pp20 only support efficiency from 9 9 9 9 up to 9 10 12 13, afaik * but the xfd detection code says this... *sigh* * * move.l 4(a0),d0 * cmp.b #9,d0 * blo.b .Exit * and.l #$f0f0f0f0,d0 * bne.s .Exit */ if (((packed[4] < 9) || (packed[5] < 9) || (packed[6] < 9) || (packed[7] < 9))) { /*fprintf(stderr, "invalid efficiency\n");*/ goto err1; } if (((readmem24b(packed +4) * 256 + packed[7]) & 0xf0f0f0f0) != 0 ) { /*fprintf(stderr, "invalid efficiency(?)\n");*/ goto err1; } unplen = readmem24b(packed + plen - 4); if (!unplen) { /*fprintf(stderr, "not a powerpacked file\n");*/ goto err1; } if (ppdepack (packed, plen, fo) == -1) { /*fprintf(stderr, "error while decrunching data...");*/ goto err1; } free (packed); return 0; err1: free(packed); err: return -1; }
static int ppdepack(uint8 *data, size_t len, FILE *fo) { /* PP FORMAT: * 1 longword identifier 'PP20' or 'PX20' * [1 word checksum (if 'PX20') $ssss] * 1 longword efficiency $eeeeeeee * X longwords crunched file $cccccccc,$cccccccc,... * 1 longword decrunch info 'decrlen' << 8 | '8 bits other info' */ int success=0; uint8 *output /*, crypted*/; uint32 outlen; if (len < 16) { /*fprintf(stderr, "File is too short to be a PP file (%u bytes)\n", len);*/ return -1; } if (data[0]=='P' && data[1]=='P' && data[2]=='2' && data[3]=='0') { if (len & 0x03) { /*fprintf(stderr, "File length is not a multiple of 4\n");*/ return -1; } /*crypted = 0;*/ } #if 0 else if (data[0]=='P' && data[1]=='X' && data[2]=='2' && data[3]=='0') { if ((len-2) & 0x03) { /*fprintf(stderr, "(file length - 2) is not a multiple of 4\n");*/ return -1; } crypted = 1; } #endif else { /*fprintf(stderr, "File does not have the PP signature\n");*/ return -1; } outlen = readmem24b(data + len - 4); /* fprintf(stderr, "decrunched length = %u bytes\n", outlen); */ output = (uint8 *) malloc(outlen); if (output == NULL) { /*fprintf(stderr, "out of memory!\n");*/ return -1; } /* if (crypted == 0) { */ /*fprintf(stderr, "not encrypted, decrunching anyway\n"); */ if (ppDecrunch(&data[8], output, &data[4], len-12, outlen, data[len-1])) { /* fprintf(stderr, "Decrunch successful! "); */ savefile(fo, (void *) output, outlen); } else { success=-1; } /*} else { success=-1; }*/ free(output); return success; }