static void
flacdec_read_vorbis_comment(BitstreamReader *comment,
                            unsigned channel_count,
                            int *channel_mask)
{
    struct bs_buffer *line = buf_new();
    unsigned line_len;
    unsigned total_lines;
    const char mask_prefix[] =
        "WAVEFORMATEXTENSIBLE_CHANNEL_MASK=";

    if (!setjmp(*br_try(comment))) {
        /*skip over vendor string*/
        line_len = comment->read(comment, 32);
        comment->skip_bytes(comment, line_len);

        /*walk through all entries in the comment*/
        for (total_lines = comment->read(comment, 32);
             total_lines > 0;
             total_lines--) {
            const char *s;

            /*populate entry one character at a time
              (this avoids allocating a big chunk of space
               if the length field is something way too large)*/
            buf_reset(line);

            for (line_len = comment->read(comment, 32);
                 line_len > 0;
                 line_len--) {
                buf_putc(
                    toupper((int)comment->read(comment, 8)),
                    line);
            }
            buf_putc(0, line);  /*NULL terminator*/

            s = (const char *)buf_window_start(line);

            /*if line starts with mask prefix*/
            if (strstr(s, mask_prefix) == s) {
                /*convert rest of line to base-16 integer*/
                unsigned mask = (unsigned)strtoul(
                    s + strlen(mask_prefix), NULL, 16);
                /*and populate mask field if its number of channel bits
                  matches the stream's channel count*/
                if (channel_bits(mask) == channel_count) {
                    *channel_mask = mask;
                }
            }
        }
        br_etry(comment);
    } else {
        /*read error in VORBIS_COMMENT
          (probably invalid length field somewhere)*/
        br_etry(comment);
    }

    buf_close(line);
}
unsigned
buf_read(struct bs_buffer *stream, uint8_t *data, unsigned data_size)
{
    const buf_size_t to_read = MIN(data_size, buf_window_size(stream));
    memcpy(data, buf_window_start(stream), to_read);
    stream->window_start += to_read;
    return to_read;
}
void
buf_resize(struct bs_buffer *stream, unsigned additional_bytes)
{
    /*only perform resize if space actually needed*/
    if (additional_bytes > buf_unused_size(stream)) {
        if (stream->window_start > 0) {
            /*shift window down before extending buffer to add more space*/
            if (buf_window_size(stream)) {
                memmove(stream->data,
                        buf_window_start(stream),
                        buf_window_size(stream));
            }
            stream->window_end -= stream->window_start;
            stream->window_start = 0;
        }

        while (additional_bytes > buf_unused_size(stream)) {
            stream->data_size *= 2;
        }

        stream->data = realloc(stream->data, stream->data_size);
    }
}