|
| 1 | +/* <z64.me> adapted from aPLib's depack.c */ |
| 2 | + |
| 3 | +/* |
| 4 | + * aPLib compression library - the smaller the better :) |
| 5 | + * |
| 6 | + * C depacker |
| 7 | + * |
| 8 | + * Copyright (c) 1998-2014 Joergen Ibsen |
| 9 | + * All Rights Reserved |
| 10 | + * |
| 11 | + * http://www.ibsensoftware.com/ |
| 12 | + */ |
| 13 | + |
| 14 | +#include "private.h" |
| 15 | + |
| 16 | +struct decoder |
| 17 | +{ |
| 18 | + unsigned char buf[1024]; /* intermediate buffer for loading */ |
| 19 | + unsigned char *buf_end; /* pointer that exists for the sole * |
| 20 | + * purpose of getting size of `buf` */ |
| 21 | + unsigned char *pstart; /* offset of next read from rom */ |
| 22 | + unsigned int remaining; /* remaining size of file */ |
| 23 | + unsigned char *buf_limit; /* points to end of scannable area * |
| 24 | + * of buf; this prevents yaz parser * |
| 25 | + * from overflowing */ |
| 26 | +#if MAJORA |
| 27 | + unsigned char *dst_end; /* end of decompressed block */ |
| 28 | +#endif |
| 29 | +}; |
| 30 | + |
| 31 | +/* internal data structure */ |
| 32 | +struct APDSTATE { |
| 33 | + unsigned char *source; |
| 34 | + unsigned char *destination; |
| 35 | + unsigned int tag; |
| 36 | + unsigned int bitcount; |
| 37 | +}; |
| 38 | + |
| 39 | +static struct decoder dec; |
| 40 | + |
| 41 | +static void *refill(unsigned char *ip) |
| 42 | +{ |
| 43 | + unsigned offset; |
| 44 | + unsigned size; |
| 45 | + |
| 46 | + /* intermediate buffer is not yet due for a refill */ |
| 47 | + if (ip < dec.buf_end - 8) |
| 48 | + return ip; |
| 49 | + |
| 50 | + /* the number 8 is used throughout to ensure * |
| 51 | + * dma transfers are always 8 byte aligned */ |
| 52 | + offset = dec.buf_end - ip; |
| 53 | + size = sizeof(dec.buf) - 8; |
| 54 | + |
| 55 | + /* the last eight bytes wrap around */ |
| 56 | + Bcopy(dec.buf_end - 8, dec.buf, 8); |
| 57 | + |
| 58 | + /* transfer data from rom */ |
| 59 | + DMARomToRam(dec.pstart, dec.buf + 8, size); |
| 60 | + dec.pstart += size; |
| 61 | + |
| 62 | + return dec.buf + (8 - offset); |
| 63 | +} |
| 64 | + |
| 65 | +static unsigned int aP_getbit(struct APDSTATE *ud) |
| 66 | +{ |
| 67 | + unsigned int bit; |
| 68 | + |
| 69 | + /* check if tag is empty */ |
| 70 | + if (!ud->bitcount--) { |
| 71 | + /* load next tag */ |
| 72 | + ud->tag = *ud->source++; |
| 73 | + ud->bitcount = 7; |
| 74 | + } |
| 75 | + |
| 76 | + /* shift bit out of tag */ |
| 77 | + bit = (ud->tag >> 7) & 0x01; |
| 78 | + ud->tag <<= 1; |
| 79 | + |
| 80 | + return bit; |
| 81 | +} |
| 82 | + |
| 83 | +static unsigned int aP_getgamma(struct APDSTATE *ud) |
| 84 | +{ |
| 85 | + unsigned int result = 1; |
| 86 | + |
| 87 | + /* input gamma2-encoded bits */ |
| 88 | + do { |
| 89 | + result = (result << 1) + aP_getbit(ud); |
| 90 | + } while (aP_getbit(ud)); |
| 91 | + |
| 92 | + return result; |
| 93 | +} |
| 94 | + |
| 95 | +static inline void *aP_depack(void *source, unsigned char *destination) |
| 96 | +{ |
| 97 | + struct APDSTATE ud; |
| 98 | + unsigned int offs, len, R0, LWM; |
| 99 | + int done; |
| 100 | + int i; |
| 101 | + |
| 102 | + ud.source = source; |
| 103 | + ud.bitcount = 0; |
| 104 | + |
| 105 | + R0 = (unsigned int) -1; |
| 106 | + LWM = 0; |
| 107 | + done = 0; |
| 108 | + |
| 109 | + /* initial buffer fill */ |
| 110 | + ud.source = refill(ud.source); |
| 111 | + |
| 112 | + /* skip header */ |
| 113 | + ud.source += 8; |
| 114 | + |
| 115 | + /* first byte verbatim */ |
| 116 | + *destination++ = *ud.source++; |
| 117 | + |
| 118 | + /* main decompression loop */ |
| 119 | + while (!done) { |
| 120 | + ud.source = refill(ud.source); |
| 121 | + if (aP_getbit(&ud)) { |
| 122 | + if (aP_getbit(&ud)) { |
| 123 | + if (aP_getbit(&ud)) { |
| 124 | + offs = 0; |
| 125 | + |
| 126 | + for (i = 4; i; i--) { |
| 127 | + offs = (offs << 1) + aP_getbit(&ud); |
| 128 | + } |
| 129 | + |
| 130 | + if (offs) { |
| 131 | + *destination = *(destination - offs); |
| 132 | + destination++; |
| 133 | + } |
| 134 | + else { |
| 135 | + *destination++ = 0x00; |
| 136 | + } |
| 137 | + |
| 138 | + LWM = 0; |
| 139 | + } |
| 140 | + else { |
| 141 | + offs = *ud.source++; |
| 142 | + |
| 143 | + len = 2 + (offs & 0x0001); |
| 144 | + |
| 145 | + offs >>= 1; |
| 146 | + |
| 147 | + if (offs) { |
| 148 | + for (; len; len--) { |
| 149 | + *destination = *(destination - offs); |
| 150 | + destination++; |
| 151 | + } |
| 152 | + } |
| 153 | + else { |
| 154 | + done = 1; |
| 155 | + } |
| 156 | + |
| 157 | + R0 = offs; |
| 158 | + LWM = 1; |
| 159 | + } |
| 160 | + } |
| 161 | + else { |
| 162 | + offs = aP_getgamma(&ud); |
| 163 | + |
| 164 | + if ((LWM == 0) && (offs == 2)) { |
| 165 | + offs = R0; |
| 166 | + |
| 167 | + len = aP_getgamma(&ud); |
| 168 | + |
| 169 | + for (; len; len--) { |
| 170 | + *destination = *(destination - offs); |
| 171 | + destination++; |
| 172 | + } |
| 173 | + } |
| 174 | + else { |
| 175 | + if (LWM == 0) { |
| 176 | + offs -= 3; |
| 177 | + } |
| 178 | + else { |
| 179 | + offs -= 2; |
| 180 | + } |
| 181 | + |
| 182 | + offs <<= 8; |
| 183 | + offs += *ud.source++; |
| 184 | + |
| 185 | + len = aP_getgamma(&ud); |
| 186 | + |
| 187 | + if (offs >= 32000) { |
| 188 | + len++; |
| 189 | + } |
| 190 | + if (offs >= 1280) { |
| 191 | + len++; |
| 192 | + } |
| 193 | + if (offs < 128) { |
| 194 | + len += 2; |
| 195 | + } |
| 196 | + |
| 197 | + for (; len; len--) { |
| 198 | + *destination = *(destination - offs); |
| 199 | + destination++; |
| 200 | + } |
| 201 | + |
| 202 | + R0 = offs; |
| 203 | + } |
| 204 | + |
| 205 | + LWM = 1; |
| 206 | + } |
| 207 | + } |
| 208 | + else { |
| 209 | + *destination++ = *ud.source++; |
| 210 | + LWM = 0; |
| 211 | + } |
| 212 | + } |
| 213 | + |
| 214 | + return destination; |
| 215 | +} |
| 216 | + |
| 217 | +/* main driver */ |
| 218 | +void apldec(void *src, void *dst, unsigned sz) |
| 219 | +{ |
| 220 | + dec.pstart = src; |
| 221 | + dec.buf_end = dec.buf + sizeof(dec.buf); |
| 222 | + dst = aP_depack(dec.buf_end, dst); |
| 223 | + (void)sz; /* unused parameter */ |
| 224 | +#if MAJORA |
| 225 | + dec.dst_end = dst; |
| 226 | + dec.buf_end = 0; |
| 227 | +#endif |
| 228 | +} |
| 229 | + |
0 commit comments