static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip, int chunk_id, int size, const uint8_t *data) { const uint8_t *eod = (data + size); uint32_t flag, mask; uint8_t *cb0, *cb1, *cb2, *cb3; unsigned int x, y; char *ip0, *ip1, *ip2, *ip3; flag = 0; mask = 0; for (y=strip->y1; y < strip->y2; y+=4) { /* take care of y dimension not being multiple of 4, such streams exist */ ip0 = ip1 = ip2 = ip3 = s->frame->data[0] + (s->palette_video?strip->x1:strip->x1*3) + (y * s->frame->linesize[0]); if(s->avctx->height - y > 1) { ip1 = ip0 + s->frame->linesize[0]; if(s->avctx->height - y > 2) { ip2 = ip1 + s->frame->linesize[0]; if(s->avctx->height - y > 3) { ip3 = ip2 + s->frame->linesize[0]; } } } /* to get the correct picture for not-multiple-of-4 cases let us fill * each block from the bottom up, thus possibly overwriting the top line * more than once but ending with the correct data in place * (instead of in-loop checking) */ for (x=strip->x1; x < strip->x2; x+=4) { if ((chunk_id & 0x01) && !(mask >>= 1)) { if ((data + 4) > eod) return AVERROR_INVALIDDATA; flag = AV_RB32 (data); data += 4; mask = 0x80000000; } if (!(chunk_id & 0x01) || (flag & mask)) { if (!(chunk_id & 0x02) && !(mask >>= 1)) { if ((data + 4) > eod) return AVERROR_INVALIDDATA; flag = AV_RB32 (data); data += 4; mask = 0x80000000; } if ((chunk_id & 0x02) || (~flag & mask)) { uint8_t *p; if (data >= eod) return AVERROR_INVALIDDATA; p = strip->v1_codebook[*data++]; if (s->palette_video) { ip3[0] = ip3[1] = ip2[0] = ip2[1] = p[6]; ip3[2] = ip3[3] = ip2[2] = ip2[3] = p[9]; ip1[0] = ip1[1] = ip0[0] = ip0[1] = p[0]; ip1[2] = ip1[3] = ip0[2] = ip0[3] = p[3]; } else { p += 6; memcpy(ip3 + 0, p, 3); memcpy(ip3 + 3, p, 3); memcpy(ip2 + 0, p, 3); memcpy(ip2 + 3, p, 3); p += 3; /* ... + 9 */ memcpy(ip3 + 6, p, 3); memcpy(ip3 + 9, p, 3); memcpy(ip2 + 6, p, 3); memcpy(ip2 + 9, p, 3); p -= 9; /* ... + 0 */ memcpy(ip1 + 0, p, 3); memcpy(ip1 + 3, p, 3); memcpy(ip0 + 0, p, 3); memcpy(ip0 + 3, p, 3); p += 3; /* ... + 3 */ memcpy(ip1 + 6, p, 3); memcpy(ip1 + 9, p, 3); memcpy(ip0 + 6, p, 3); memcpy(ip0 + 9, p, 3); } } else if (flag & mask) { if ((data + 4) > eod) return AVERROR_INVALIDDATA; cb0 = strip->v4_codebook[*data++]; cb1 = strip->v4_codebook[*data++]; cb2 = strip->v4_codebook[*data++]; cb3 = strip->v4_codebook[*data++]; if (s->palette_video) { uint8_t *p; p = ip3; *p++ = cb2[6]; *p++ = cb2[9]; *p++ = cb3[6]; *p = cb3[9]; p = ip2; *p++ = cb2[0]; *p++ = cb2[3]; *p++ = cb3[0]; *p = cb3[3]; p = ip1; *p++ = cb0[6]; *p++ = cb0[9]; *p++ = cb1[6]; *p = cb1[9]; p = ip0; *p++ = cb0[0]; *p++ = cb0[3]; *p++ = cb1[0]; *p = cb1[3]; } else { memcpy(ip3 + 0, cb2 + 6, 6); memcpy(ip3 + 6, cb3 + 6, 6); memcpy(ip2 + 0, cb2 + 0, 6); memcpy(ip2 + 6, cb3 + 0, 6); memcpy(ip1 + 0, cb0 + 6, 6); memcpy(ip1 + 6, cb1 + 6, 6); memcpy(ip0 + 0, cb0 + 0, 6); memcpy(ip0 + 6, cb1 + 0, 6); } } } if (s->palette_video) { ip0 += 4; ip1 += 4; ip2 += 4; ip3 += 4; } else { ip0 += 12; ip1 += 12; ip2 += 12; ip3 += 12; } } } return 0; }