static void ape_parse_tag(AVFormatContext *s)
{
    ByteIOContext *pb = s->pb;
    int file_size = url_fsize(pb);
    uint32_t val, fields, tag_bytes;
    uint8_t buf[8];
    int i;
    if (file_size < APE_TAG_FOOTER_BYTES)
        return;
    url_fseek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET);
    get_buffer(pb, buf, 8);
    if (strncmp(buf, "APETAGEX", 8)) {
        av_log(NULL, AV_LOG_ERROR, "Invalid APE Tags\n");
        return;
    }
    val = get_le32(pb);
    if (val > APE_TAG_VERSION) {
        av_log(NULL, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION);
        return;
    }
    tag_bytes = get_le32(pb);
    if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) {
        av_log(NULL, AV_LOG_ERROR, "Tag size is way too big\n");
        return;
    }
    fields = get_le32(pb);
    if (fields > 65536) {
        av_log(NULL, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields);
        return;
    }
    val = get_le32(pb);
    if (val & APE_TAG_FLAG_IS_HEADER) {
        av_log(NULL, AV_LOG_ERROR, "APE Tag is a header\n");
        return;
    }
    if (val & APE_TAG_FLAG_CONTAINS_HEADER)
        tag_bytes += 2*APE_TAG_FOOTER_BYTES;
    url_fseek(pb, file_size - tag_bytes, SEEK_SET);
    for (i=0; i<fields; i++)
        ape_tag_read_field(s);
#if ENABLE_DEBUG
    av_log(NULL, AV_LOG_DEBUG, "\nAPE Tags:\n\n");
    av_log(NULL, AV_LOG_DEBUG, "title     = %s\n", s->title);
    av_log(NULL, AV_LOG_DEBUG, "author    = %s\n", s->author);
    av_log(NULL, AV_LOG_DEBUG, "copyright = %s\n", s->copyright);
    av_log(NULL, AV_LOG_DEBUG, "comment   = %s\n", s->comment);
    av_log(NULL, AV_LOG_DEBUG, "album     = %s\n", s->album);
    av_log(NULL, AV_LOG_DEBUG, "year      = %d\n", s->year);
    av_log(NULL, AV_LOG_DEBUG, "track     = %d\n", s->track);
    av_log(NULL, AV_LOG_DEBUG, "genre     = %s\n", s->genre);
#endif
}
['static void ape_parse_tag(AVFormatContext *s)\n{\n    ByteIOContext *pb = s->pb;\n    int file_size = url_fsize(pb);\n    uint32_t val, fields, tag_bytes;\n    uint8_t buf[8];\n    int i;\n    if (file_size < APE_TAG_FOOTER_BYTES)\n        return;\n    url_fseek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET);\n    get_buffer(pb, buf, 8);\n    if (strncmp(buf, "APETAGEX", 8)) {\n        av_log(NULL, AV_LOG_ERROR, "Invalid APE Tags\\n");\n        return;\n    }\n    val = get_le32(pb);\n    if (val > APE_TAG_VERSION) {\n        av_log(NULL, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\\n", APE_TAG_VERSION);\n        return;\n    }\n    tag_bytes = get_le32(pb);\n    if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) {\n        av_log(NULL, AV_LOG_ERROR, "Tag size is way too big\\n");\n        return;\n    }\n    fields = get_le32(pb);\n    if (fields > 65536) {\n        av_log(NULL, AV_LOG_ERROR, "Too many tag fields (%d)\\n", fields);\n        return;\n    }\n    val = get_le32(pb);\n    if (val & APE_TAG_FLAG_IS_HEADER) {\n        av_log(NULL, AV_LOG_ERROR, "APE Tag is a header\\n");\n        return;\n    }\n    if (val & APE_TAG_FLAG_CONTAINS_HEADER)\n        tag_bytes += 2*APE_TAG_FOOTER_BYTES;\n    url_fseek(pb, file_size - tag_bytes, SEEK_SET);\n    for (i=0; i<fields; i++)\n        ape_tag_read_field(s);\n#if ENABLE_DEBUG\n    av_log(NULL, AV_LOG_DEBUG, "\\nAPE Tags:\\n\\n");\n    av_log(NULL, AV_LOG_DEBUG, "title     = %s\\n", s->title);\n    av_log(NULL, AV_LOG_DEBUG, "author    = %s\\n", s->author);\n    av_log(NULL, AV_LOG_DEBUG, "copyright = %s\\n", s->copyright);\n    av_log(NULL, AV_LOG_DEBUG, "comment   = %s\\n", s->comment);\n    av_log(NULL, AV_LOG_DEBUG, "album     = %s\\n", s->album);\n    av_log(NULL, AV_LOG_DEBUG, "year      = %d\\n", s->year);\n    av_log(NULL, AV_LOG_DEBUG, "track     = %d\\n", s->track);\n    av_log(NULL, AV_LOG_DEBUG, "genre     = %s\\n", s->genre);\n#endif\n}', 'offset_t url_fsize(ByteIOContext *s)\n{\n    offset_t size;\n    if(!s)\n        return AVERROR(EINVAL);\n    if (!s->seek)\n        return AVERROR(EPIPE);\n    size = s->seek(s->opaque, 0, AVSEEK_SIZE);\n    if(size<0){\n        if ((size = s->seek(s->opaque, -1, SEEK_END)) < 0)\n            return size;\n        size++;\n        s->seek(s->opaque, s->pos, SEEK_SET);\n    }\n    return size;\n}', 'unsigned int get_le32(ByteIOContext *s)\n{\n    unsigned int val;\n    val = get_le16(s);\n    val |= get_le16(s) << 16;\n    return val;\n}', 'unsigned int get_le16(ByteIOContext *s)\n{\n    unsigned int val;\n    val = get_byte(s);\n    val |= get_byte(s) << 8;\n    return val;\n}', 'int get_byte(ByteIOContext *s)\n{\n    if (s->buf_ptr < s->buf_end) {\n        return *s->buf_ptr++;\n    } else {\n        fill_buffer(s);\n        if (s->buf_ptr < s->buf_end)\n            return *s->buf_ptr++;\n        else\n            return 0;\n    }\n}']