static boolean buf_src_fill_input_buffer(j_decompress_ptr cinfo) { static JOCTET mybuffer[4]; buf_src_mgr *src = (buf_src_mgr *)cinfo->src; // Consume the entire buffer, even if bytes are still in bytes_in_buffer buffer_consume(src->buf, buffer_len(src->buf)); if (!buffer_check_load(src->buf, src->fp, 1, BUF_SIZE)) goto eof; cinfo->src->next_input_byte = (JOCTET *)buffer_ptr(src->buf); cinfo->src->bytes_in_buffer = buffer_len(src->buf); goto ok; eof: // Insert a fake EOI marker if we can't read enough data LOG_DEBUG(" EOF filling input buffer, returning EOI marker\n"); mybuffer[0] = (JOCTET)0xFF; mybuffer[1] = (JOCTET)JPEG_EOI; cinfo->src->next_input_byte = mybuffer; cinfo->src->bytes_in_buffer = 2; ok: return TRUE; }
static void image_png_read_buf(png_structp png_ptr, png_bytep data, png_size_t len) { PNGData *p = (PNGData *)png_get_io_ptr(png_ptr); //LOG_DEBUG("PNG read_buf wants %ld bytes, %d in buffer\n", len, buffer_len(p->buf)); if (!buffer_check_load(p->buf, p->fp, len, BUF_SIZE)) goto eof; memcpy(data, buffer_ptr(p->buf), len); buffer_consume(p->buf, len); goto ok; eof: png_error(png_ptr, "Not enough PNG data"); ok: return; }
static void _parse_wav(ScanData s, Buffer *buf) { uint32_t offset = 12; s->type_name = "wav"; mediascan_add_StreamData(s, 1); while ( offset < s->size - 8 ) { char chunk_id[5]; uint32_t chunk_size; // Verify we have at least 8 bytes if ( !buffer_check_load(buf, s->fp, 8, BLOCK_SIZE) ) { return; } strncpy( chunk_id, (char *)buffer_ptr(buf), 4 ); chunk_id[4] = '\0'; buffer_consume(buf, 4); chunk_size = buffer_get_int_le(buf); // Adjust for padding if ( chunk_size % 2 ) { chunk_size++; } offset += 8; LOG_DEBUG("%s size %d\n", chunk_id, chunk_size); // Seek past data, everything else we parse // XXX: Are there other large chunks we should ignore? if ( !strcmp( chunk_id, "data" ) ) { s->audio_offset = offset; s->audio_size = chunk_size; // Calculate duration, unless we already know it (i.e. from 'fact') if ( !s->duration_ms ) { if (s->bitrate) { s->duration_ms = (chunk_size / (s->bitrate / 8.)) * 1000; } } // sanity check size, this is inside the data chunk code // to support setting audio_offset even when the data size is wrong if (chunk_size > s->size - offset) { LOG_DEBUG("data size > file_size, skipping\n"); return; } // Seek past data if there are more chunks after it if ( s->size > offset + chunk_size ) { fseek(s->fp, offset + chunk_size, SEEK_SET); } buffer_clear(buf); } else if ( !strcmp( chunk_id, "id3 " ) || !strcmp( chunk_id, "ID3 " ) || !strcmp( chunk_id, "ID32" ) ) { // Read header to verify version unsigned char *bptr = buffer_ptr(buf); if ( (bptr[0] == 'I' && bptr[1] == 'D' && bptr[2] == '3') && bptr[3] < 0xff && bptr[4] < 0xff && bptr[6] < 0x80 && bptr[7] < 0x80 && bptr[8] < 0x80 && bptr[9] < 0x80 ) { // Start parsing ID3 from offset //parse_id3(infile, file, info, tags, offset, file_size); } // Seek past ID3 and clear buffer fseek(s->fp, offset + chunk_size, SEEK_SET); buffer_clear(buf); } else { // sanity check size if (chunk_size > s->size - offset) { LOG_DEBUG("chunk_size > file_size, skipping\n"); return; } // Make sure we have enough data if ( !buffer_check_load(buf, s->fp, chunk_size, BLOCK_SIZE) ) { return; } if ( !strcmp( chunk_id, "fmt " ) ) { _parse_wav_fmt(s, buf, chunk_size); } else if ( !strcmp( chunk_id, "LIST" ) ) { //_parse_wav_list(buf, chunk_size, tags); } else if ( !strcmp( chunk_id, "PEAK" ) ) { _parse_wav_peak(s, buf, chunk_size, 0); } else if ( !strcmp( chunk_id, "fact" ) ) { // A 4-byte fact chunk in a non-PCM wav is the number of samples // Use it to calculate duration if ( chunk_size == 4 ) { uint32_t num_samples = buffer_get_int_le(buf); if (s->streams[0].samplerate) { s->duration_ms = (num_samples * 1000) / s->streams[0].samplerate; } } else { // Unknown, skip it buffer_consume(buf, chunk_size); } } else { if ( !strcmp(chunk_id, "SAUR") // Wavosour data chunk || !strcmp(chunk_id, "otom") // Wavosaur? || !strcmp(chunk_id, "PAD ") // Padding ) { // Known chunks to skip } else { // Warn about unknown chunks so we can investigate them LOG_DEBUG("Unhandled WAV chunk %s size %d (skipped)\n", chunk_id, chunk_size); } buffer_consume(buf, chunk_size); } } offset += chunk_size; } }
int wav_scan(ScanData s) { int ret = 1; Buffer buf; uint32_t chunk_size; buffer_init(&buf, BLOCK_SIZE); if ( !buffer_check_load(&buf, s->fp, 12, BLOCK_SIZE) ) { ret = 0; goto out; } if ( !strncmp( (char *)buffer_ptr(&buf), "RIFF", 4 ) ) { // We've got a RIFF file buffer_consume(&buf, 4); chunk_size = buffer_get_int_le(&buf); // Check format if ( strncmp( (char *)buffer_ptr(&buf), "WAVE", 4 ) ) { LOG_ERROR("Invalid WAV file: missing WAVE header: %s\n", s->path); ret = 0; goto out; } buffer_consume(&buf, 4); _parse_wav(s, &buf); } else if ( !strncmp( (char *)buffer_ptr(&buf), "FORM", 4 ) ) { // We've got an AIFF file char *bptr; buffer_consume(&buf, 4); chunk_size = buffer_get_int(&buf); // Check format bptr = buffer_ptr(&buf); if ( bptr[0] == 'A' && bptr[1] == 'I' && bptr[2] == 'F' && (bptr[3] == 'F' || bptr[3] == 'C') ) { buffer_consume(&buf, 4); //_parse_aiff(s, &buf); } else { LOG_ERROR("Invalid AIFF file: missing AIFF header: %s\n", s->path); ret = 0; goto out; } } else { LOG_ERROR("Invalid WAV file: missing RIFF header: %s\n", s->path); ret = 0; goto out; } out: buffer_free(&buf); return ret; }