static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb)

{

    WVContext *wc = ctx->priv_data;

    int ret;

    int rate, bpp, chan;

    uint32_t chmask, flags;



    wc->pos = avio_tell(pb);



    /* don't return bogus packets with the ape tag data */

    if (wc->apetag_start && wc->pos >= wc->apetag_start)

        return AVERROR_EOF;



    ret = avio_read(pb, wc->block_header, WV_HEADER_SIZE);

    if (ret != WV_HEADER_SIZE)

        return (ret < 0) ? ret : AVERROR_EOF;



    ret = ff_wv_parse_header(&wc->header, wc->block_header);

    if (ret < 0) {

        av_log(ctx, AV_LOG_ERROR, "Invalid block header.\n");

        return ret;

    }



    if (wc->header.version < 0x402 || wc->header.version > 0x410) {

        av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", wc->header.version);

        return AVERROR_PATCHWELCOME;

    }



    /* Blocks with zero samples don't contain actual audio information

     * and should be ignored */

    if (!wc->header.samples)

        return 0;

    // parse flags

    flags  = wc->header.flags;

    bpp    = ((flags & 3) + 1) << 3;

    chan   = 1 + !(flags & WV_MONO);

    chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;

    rate   = wv_rates[(flags >> 23) & 0xF];

    wc->multichannel = !(wc->header.initial && wc->header.final);

    if (wc->multichannel) {

        chan   = wc->chan;

        chmask = wc->chmask;

    }

    if ((rate == -1 || !chan) && !wc->block_parsed) {

        int64_t block_end = avio_tell(pb) + wc->header.blocksize;

        if (!pb->seekable) {

            av_log(ctx, AV_LOG_ERROR,

                   "Cannot determine additional parameters\n");

            return AVERROR_INVALIDDATA;

        }

        while (avio_tell(pb) < block_end) {

            int id, size;

            id   = avio_r8(pb);

            size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb);

            size <<= 1;

            if (id & 0x40)

                size--;

            switch (id & 0x3F) {

            case 0xD:

                if (size <= 1) {

                    av_log(ctx, AV_LOG_ERROR,

                           "Insufficient channel information\n");

                    return AVERROR_INVALIDDATA;

                }

                chan = avio_r8(pb);

                switch (size - 2) {

                case 0:

                    chmask = avio_r8(pb);

                    break;

                case 1:

                    chmask = avio_rl16(pb);

                    break;

                case 2:

                    chmask = avio_rl24(pb);

                    break;

                case 3:

                    chmask = avio_rl32(pb);

                    break;

                case 5:

                    avio_skip(pb, 1);

                    chan  |= (avio_r8(pb) & 0xF) << 8;

                    chmask = avio_rl24(pb);

                    break;

                default:

                    av_log(ctx, AV_LOG_ERROR,

                           "Invalid channel info size %d\n", size);

                    return AVERROR_INVALIDDATA;

                }

                break;

            case 0x27:

                rate = avio_rl24(pb);

                break;

            default:

                avio_skip(pb, size);

            }

            if (id & 0x40)

                avio_skip(pb, 1);

        }

        if (rate == -1) {

            av_log(ctx, AV_LOG_ERROR,

                   "Cannot determine custom sampling rate\n");

            return AVERROR_INVALIDDATA;

        }

        avio_seek(pb, block_end - wc->header.blocksize, SEEK_SET);

    }

    if (!wc->bpp)

        wc->bpp    = bpp;

    if (!wc->chan)

        wc->chan   = chan;

    if (!wc->chmask)

        wc->chmask = chmask;

    if (!wc->rate)

        wc->rate   = rate;



    if (flags && bpp != wc->bpp) {

        av_log(ctx, AV_LOG_ERROR,

               "Bits per sample differ, this block: %i, header block: %i\n",

               bpp, wc->bpp);

        return AVERROR_INVALIDDATA;

    }

    if (flags && !wc->multichannel && chan != wc->chan) {

        av_log(ctx, AV_LOG_ERROR,

               "Channels differ, this block: %i, header block: %i\n",

               chan, wc->chan);

        return AVERROR_INVALIDDATA;

    }

    if (flags && rate != -1 && rate != wc->rate) {

        av_log(ctx, AV_LOG_ERROR,

               "Sampling rate differ, this block: %i, header block: %i\n",

               rate, wc->rate);

        return AVERROR_INVALIDDATA;

    }

    return 0;

}

static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb)

{

    WVContext *wc = ctx->priv_data;

    int ret;

    int rate, bpp, chan;

    uint32_t chmask, flags;



    wc->pos = avio_tell(pb);



    

    if (wc->apetag_start && wc->pos >= wc->apetag_start)

        return AVERROR_EOF;



    ret = avio_read(pb, wc->block_header, WV_HEADER_SIZE);

    if (ret != WV_HEADER_SIZE)

        return (ret < 0) ? ret : AVERROR_EOF;



    ret = ff_wv_parse_header(&wc->header, wc->block_header);

    if (ret < 0) {

        av_log(ctx, AV_LOG_ERROR, "Invalid block header.\n");

        return ret;

    }



    if (wc->header.version < 0x402 || wc->header.version > 0x410) {

        av_log(ctx, AV_LOG_ERROR, "Unsupported version %03X\n", wc->header.version);

        return AVERROR_PATCHWELCOME;

    }



    



    if (!wc->header.samples)

        return 0;

    

    flags  = wc->header.flags;

    bpp    = ((flags & 3) + 1) << 3;

    chan   = 1 + !(flags & WV_MONO);

    chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;

    rate   = wv_rates[(flags >> 23) & 0xF];

    wc->multichannel = !(wc->header.initial && wc->header.final);

    if (wc->multichannel) {

        chan   = wc->chan;

        chmask = wc->chmask;

    }

    if ((rate == -1 || !chan) && !wc->block_parsed) {

        int64_t block_end = avio_tell(pb) + wc->header.blocksize;

        if (!pb->seekable) {

            av_log(ctx, AV_LOG_ERROR,

                   "Cannot determine additional parameters\n");

            return AVERROR_INVALIDDATA;

        }

        while (avio_tell(pb) < block_end) {

            int id, size;

            id   = avio_r8(pb);

            size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb);

            size <<= 1;

            if (id & 0x40)

                size--;

            switch (id & 0x3F) {

            case 0xD:

                if (size <= 1) {

                    av_log(ctx, AV_LOG_ERROR,

                           "Insufficient channel information\n");

                    return AVERROR_INVALIDDATA;

                }

                chan = avio_r8(pb);

                switch (size - 2) {

                case 0:

                    chmask = avio_r8(pb);

                    break;

                case 1:

                    chmask = avio_rl16(pb);

                    break;

                case 2:

                    chmask = avio_rl24(pb);

                    break;

                case 3:

                    chmask = avio_rl32(pb);

                    break;

                case 5:

                    avio_skip(pb, 1);

                    chan  |= (avio_r8(pb) & 0xF) << 8;

                    chmask = avio_rl24(pb);

                    break;

                default:

                    av_log(ctx, AV_LOG_ERROR,

                           "Invalid channel info size %d\n", size);

                    return AVERROR_INVALIDDATA;

                }

                break;

            case 0x27:

                rate = avio_rl24(pb);

                break;

            default:

                avio_skip(pb, size);

            }

            if (id & 0x40)

                avio_skip(pb, 1);

        }

        if (rate == -1) {

            av_log(ctx, AV_LOG_ERROR,

                   "Cannot determine custom sampling rate\n");

            return AVERROR_INVALIDDATA;

        }

        avio_seek(pb, block_end - wc->header.blocksize, SEEK_SET);

    }

    if (!wc->bpp)

        wc->bpp    = bpp;

    if (!wc->chan)

        wc->chan   = chan;

    if (!wc->chmask)

        wc->chmask = chmask;

    if (!wc->rate)

        wc->rate   = rate;



    if (flags && bpp != wc->bpp) {

        av_log(ctx, AV_LOG_ERROR,

               "Bits per sample differ, this block: %i, header block: %i\n",

               bpp, wc->bpp);

        return AVERROR_INVALIDDATA;

    }

    if (flags && !wc->multichannel && chan != wc->chan) {

        av_log(ctx, AV_LOG_ERROR,

               "Channels differ, this block: %i, header block: %i\n",

               chan, wc->chan);

        return AVERROR_INVALIDDATA;

    }

    if (flags && rate != -1 && rate != wc->rate) {

        av_log(ctx, AV_LOG_ERROR,

               "Sampling rate differ, this block: %i, header block: %i\n",

               rate, wc->rate);

        return AVERROR_INVALIDDATA;

    }

    return 0;

}

static int FUNC_0(AVFormatContext *VAR_0, AVIOContext *VAR_1)

{

    WVContext *wc = VAR_0->priv_data;

    int VAR_2;

    int VAR_3, VAR_4, VAR_5;

    uint32_t chmask, flags;



    wc->pos = avio_tell(VAR_1);



    

    if (wc->apetag_start && wc->pos >= wc->apetag_start)

        return AVERROR_EOF;



    VAR_2 = avio_read(VAR_1, wc->block_header, WV_HEADER_SIZE);

    if (VAR_2 != WV_HEADER_SIZE)

        return (VAR_2 < 0) ? VAR_2 : AVERROR_EOF;



    VAR_2 = ff_wv_parse_header(&wc->header, wc->block_header);

    if (VAR_2 < 0) {

        av_log(VAR_0, AV_LOG_ERROR, "Invalid block header.\n");

        return VAR_2;

    }



    if (wc->header.version < 0x402 || wc->header.version > 0x410) {

        av_log(VAR_0, AV_LOG_ERROR, "Unsupported version %03X\n", wc->header.version);

        return AVERROR_PATCHWELCOME;

    }



    



    if (!wc->header.samples)

        return 0;

    

    flags  = wc->header.flags;

    VAR_4    = ((flags & 3) + 1) << 3;

    VAR_5   = 1 + !(flags & WV_MONO);

    chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;

    VAR_3   = wv_rates[(flags >> 23) & 0xF];

    wc->multichannel = !(wc->header.initial && wc->header.final);

    if (wc->multichannel) {

        VAR_5   = wc->VAR_5;

        chmask = wc->chmask;

    }

    if ((VAR_3 == -1 || !VAR_5) && !wc->block_parsed) {

        int64_t block_end = avio_tell(VAR_1) + wc->header.blocksize;

        if (!VAR_1->seekable) {

            av_log(VAR_0, AV_LOG_ERROR,

                   "Cannot determine additional parameters\n");

            return AVERROR_INVALIDDATA;

        }

        while (avio_tell(VAR_1) < block_end) {

            int VAR_6, VAR_7;

            VAR_6   = avio_r8(VAR_1);

            VAR_7 = (VAR_6 & 0x80) ? avio_rl24(VAR_1) : avio_r8(VAR_1);

            VAR_7 <<= 1;

            if (VAR_6 & 0x40)

                VAR_7--;

            switch (VAR_6 & 0x3F) {

            case 0xD:

                if (VAR_7 <= 1) {

                    av_log(VAR_0, AV_LOG_ERROR,

                           "Insufficient channel information\n");

                    return AVERROR_INVALIDDATA;

                }

                VAR_5 = avio_r8(VAR_1);

                switch (VAR_7 - 2) {

                case 0:

                    chmask = avio_r8(VAR_1);

                    break;

                case 1:

                    chmask = avio_rl16(VAR_1);

                    break;

                case 2:

                    chmask = avio_rl24(VAR_1);

                    break;

                case 3:

                    chmask = avio_rl32(VAR_1);

                    break;

                case 5:

                    avio_skip(VAR_1, 1);

                    VAR_5  |= (avio_r8(VAR_1) & 0xF) << 8;

                    chmask = avio_rl24(VAR_1);

                    break;

                default:

                    av_log(VAR_0, AV_LOG_ERROR,

                           "Invalid channel info VAR_7 %d\n", VAR_7);

                    return AVERROR_INVALIDDATA;

                }

                break;

            case 0x27:

                VAR_3 = avio_rl24(VAR_1);

                break;

            default:

                avio_skip(VAR_1, VAR_7);

            }

            if (VAR_6 & 0x40)

                avio_skip(VAR_1, 1);

        }

        if (VAR_3 == -1) {

            av_log(VAR_0, AV_LOG_ERROR,

                   "Cannot determine custom sampling VAR_3\n");

            return AVERROR_INVALIDDATA;

        }

        avio_seek(VAR_1, block_end - wc->header.blocksize, SEEK_SET);

    }

    if (!wc->VAR_4)

        wc->VAR_4    = VAR_4;

    if (!wc->VAR_5)

        wc->VAR_5   = VAR_5;

    if (!wc->chmask)

        wc->chmask = chmask;

    if (!wc->VAR_3)

        wc->VAR_3   = VAR_3;



    if (flags && VAR_4 != wc->VAR_4) {

        av_log(VAR_0, AV_LOG_ERROR,

               "Bits per sample differ, this block: %i, header block: %i\n",

               VAR_4, wc->VAR_4);

        return AVERROR_INVALIDDATA;

    }

    if (flags && !wc->multichannel && VAR_5 != wc->VAR_5) {

        av_log(VAR_0, AV_LOG_ERROR,

               "Channels differ, this block: %i, header block: %i\n",

               VAR_5, wc->VAR_5);

        return AVERROR_INVALIDDATA;

    }

    if (flags && VAR_3 != -1 && VAR_3 != wc->VAR_3) {

        av_log(VAR_0, AV_LOG_ERROR,

               "Sampling VAR_3 differ, this block: %i, header block: %i\n",

               VAR_3, wc->VAR_3);

        return AVERROR_INVALIDDATA;

    }

    return 0;

}

static int FUNC_0(AVFormatContext *VAR_0, AVIOContext *VAR_1)
{ WVContext *wc = VAR_0->priv_data; int VAR_2; int VAR_3, VAR_4, VAR_5; uint32_t chmask, flags; wc->pos = avio_tell(VAR_1); if (wc->apetag_start && wc->pos >= wc->apetag_start)
return AVERROR_EOF; VAR_2 = avio_read(VAR_1, wc->block_header, WV_HEADER_SIZE); if (VAR_2 != WV_HEADER_SIZE)
return (VAR_2 < 0) ? VAR_2 : AVERROR_EOF; VAR_2 = ff_wv_parse_header(&wc->header, wc->block_header); if (VAR_2 < 0) { av_log(VAR_0, AV_LOG_ERROR, "Invalid block header.\n"); return VAR_2; } if (wc->header.version < 0x402 || wc->header.version > 0x410) { av_log(VAR_0, AV_LOG_ERROR, "Unsupported version %03X\n", wc->header.version); return AVERROR_PATCHWELCOME; } if (!wc->header.samples)
return 0; flags  = wc->header.flags; VAR_4    = ((flags & 3) + 1) << 3; VAR_5   = 1 + !(flags & WV_MONO); chmask = flags & WV_MONO ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; VAR_3   = wv_rates[(flags >> 23) & 0xF]; wc->multichannel = !(wc->header.initial && wc->header.final); if (wc->multichannel) { VAR_5   = wc->VAR_5; chmask = wc->chmask; } if ((VAR_3 == -1 || !VAR_5) && !wc->block_parsed) { int64_t block_end = avio_tell(VAR_1) + wc->header.blocksize; if (!VAR_1->seekable) { av_log(VAR_0, AV_LOG_ERROR,
"Cannot determine additional parameters\n"); return AVERROR_INVALIDDATA; } while (avio_tell(VAR_1) < block_end) { int VAR_6, VAR_7; VAR_6   = avio_r8(VAR_1); VAR_7 = (VAR_6 & 0x80) ? avio_rl24(VAR_1) : avio_r8(VAR_1); VAR_7 <<= 1; if (VAR_6 & 0x40)
VAR_7--; switch (VAR_6 & 0x3F) { case 0xD:
if (VAR_7 <= 1) { av_log(VAR_0, AV_LOG_ERROR,
"Insufficient channel information\n"); return AVERROR_INVALIDDATA; } VAR_5 = avio_r8(VAR_1); switch (VAR_7 - 2) { case 0:
chmask = avio_r8(VAR_1); break; case 1:
chmask = avio_rl16(VAR_1); break; case 2:
chmask = avio_rl24(VAR_1); break; case 3:
chmask = avio_rl32(VAR_1); break; case 5:
avio_skip(VAR_1, 1); VAR_5  |= (avio_r8(VAR_1) & 0xF) << 8; chmask = avio_rl24(VAR_1); break; default:
av_log(VAR_0, AV_LOG_ERROR,
"Invalid channel info VAR_7 %d\n", VAR_7); return AVERROR_INVALIDDATA; } break; case 0x27:
VAR_3 = avio_rl24(VAR_1); break; default:
avio_skip(VAR_1, VAR_7); } if (VAR_6 & 0x40)
avio_skip(VAR_1, 1); } if (VAR_3 == -1) { av_log(VAR_0, AV_LOG_ERROR,
"Cannot determine custom sampling VAR_3\n"); return AVERROR_INVALIDDATA; } avio_seek(VAR_1, block_end - wc->header.blocksize, SEEK_SET); } if (!wc->VAR_4)
wc->VAR_4    = VAR_4; if (!wc->VAR_5)
wc->VAR_5   = VAR_5; if (!wc->chmask)
wc->chmask = chmask; if (!wc->VAR_3)
wc->VAR_3   = VAR_3; if (flags && VAR_4 != wc->VAR_4) { av_log(VAR_0, AV_LOG_ERROR,
"Bits per sample differ, this block: %i, header block: %i\n",
VAR_4, wc->VAR_4); return AVERROR_INVALIDDATA; } if (flags && !wc->multichannel && VAR_5 != wc->VAR_5) { av_log(VAR_0, AV_LOG_ERROR,
"Channels differ, this block: %i, header block: %i\n",
VAR_5, wc->VAR_5); return AVERROR_INVALIDDATA; } if (flags && VAR_3 != -1 && VAR_3 != wc->VAR_3) { av_log(VAR_0, AV_LOG_ERROR,
"Sampling VAR_3 differ, this block: %i, header block: %i\n",
VAR_3, wc->VAR_3); return AVERROR_INVALIDDATA; } return 0; }