/* these are for internal state related to Ogg decoding */
ogg_stream_state stream_state;
ogg_sync_state sync_state;
+ unsigned version_major, version_minor;
FLAC__bool need_serial_number;
FLAC__bool end_of_stream;
FLAC__bool have_working_page; /* only if true will the following vars be valid */
OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0,
OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM,
OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC,
+ OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC,
+ OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION,
OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT,
OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR,
OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR
#include <string.h> /* for memcpy() */
#include "FLAC/assert.h"
#include "private/ogg_decoder_aspect.h"
+#include "private/ogg_mapping.h"
#ifdef max
#undef max
if(ogg_sync_init(&aspect->sync_state) != 0)
return false;
+ aspect->version_major = ~(0u);
+ aspect->version_minor = ~(0u);
+
aspect->need_serial_number = aspect->use_first_serial_number;
aspect->end_of_stream = false;
const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
if (ret > 0) {
aspect->have_working_packet = true;
+ /* if it is packet 0, check for magic and a supported Ogg FLAC mapping version */
+ if (aspect->working_packet.packetno == 0) {
+ const unsigned header_length = OggFLAC__MAPPING_MAGIC_LENGTH + OggFLAC__MAPPING_VERSION_MAJOR_LENGTH + OggFLAC__MAPPING_VERSION_MINOR_LENGTH;
+ if (aspect->working_packet.bytes < (long)header_length)
+ return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+ if (memcmp(aspect->working_packet.packet, OggFLAC__MAPPING_MAGIC, OggFLAC__MAPPING_MAGIC_LENGTH))
+ return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+ aspect->version_major = (unsigned)aspect->working_packet.packet[OggFLAC__MAPPING_MAGIC_LENGTH];
+ aspect->version_minor = (unsigned)aspect->working_packet.packet[OggFLAC__MAPPING_MAGIC_LENGTH+OggFLAC__MAPPING_VERSION_MAJOR_LENGTH];
+ if (aspect->version_major != 1)
+ return OggFLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
+ aspect->working_packet.packet += header_length;
+ aspect->working_packet.bytes -= header_length;
+ }
}
else if (ret == 0) {
aspect->have_working_page = false;
#include <string.h> /* for memset() */
#include "FLAC/assert.h"
#include "private/ogg_encoder_aspect.h"
+#include "private/ogg_mapping.h"
+
+static const FLAC__byte OggFLAC__MAPPING_VERSION_MAJOR = 1;
+static const FLAC__byte OggFLAC__MAPPING_VERSION_MINOR = 0;
/***********************************************************************
*
* The basic FLAC -> Ogg mapping goes like this:
*
* - 'fLaC' magic and STREAMINFO block get combined into the first
- * packet
- * - the first packet is flushed to the first page
- * - each subsequent metadata block goes into its own packet
- * - each metadata packet is flushed to page (this is not required,
+ * packet. The packet is prefixed with 'FLAC' magic and the 2
+ * byte Ogg FLAC mapping version number.
+ * - The first packet is flushed to the first page.
+ * - Each subsequent metadata block goes into its own packet.
+ * - Each metadata packet is flushed to page (this is not required,
* the mapping only requires that a flush must occur after all
- * metadata is written)
- * - each subsequent FLAC audio frame goes into its own packet.
+ * metadata is written).
+ * - Each subsequent FLAC audio frame goes into its own packet.
*
* WATCHOUT:
* This depends on the behavior of FLAC__StreamEncoder that we get a
packet.granulepos = aspect->samples_written + samples;
if(aspect->is_first_packet) {
- FLAC__byte newbuffer[FLAC__STREAM_SYNC_LENGTH + FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+ FLAC__byte newbuffer[
+ OggFLAC__MAPPING_MAGIC_LENGTH +
+ OggFLAC__MAPPING_VERSION_MAJOR_LENGTH +
+ OggFLAC__MAPPING_VERSION_MINOR_LENGTH +
+ FLAC__STREAM_SYNC_LENGTH +
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ FLAC__STREAM_METADATA_STREAMINFO_LENGTH
+ ];
+ FLAC__byte *b = newbuffer;
if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) {
/*
* If we get here, our assumption about the way write callbacks happen
FLAC__ASSERT(0);
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
- memcpy(newbuffer, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH);
- memcpy(newbuffer + FLAC__STREAM_SYNC_LENGTH, buffer, bytes);
+ /* add 'FLAC' mapping magic */
+ memcpy(b, OggFLAC__MAPPING_MAGIC, OggFLAC__MAPPING_MAGIC_LENGTH);
+ b += OggFLAC__MAPPING_MAGIC_LENGTH;
+ /* add Ogg FLAC mapping major version number */
+ memcpy(b, &OggFLAC__MAPPING_VERSION_MAJOR, OggFLAC__MAPPING_VERSION_MAJOR_LENGTH);
+ b += OggFLAC__MAPPING_VERSION_MAJOR_LENGTH;
+ /* add Ogg FLAC mapping minor version number */
+ memcpy(b, &OggFLAC__MAPPING_VERSION_MINOR, OggFLAC__MAPPING_VERSION_MINOR_LENGTH);
+ b += OggFLAC__MAPPING_VERSION_MINOR_LENGTH;
+ /* add native FLAC 'fLaC' magic */
+ memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH);
+ b += FLAC__STREAM_SYNC_LENGTH;
+ /* add STREAMINFO */
+ memcpy(b, buffer, bytes);
+ FLAC__ASSERT(b + bytes - newbuffer == sizeof(newbuffer));
packet.packet = (unsigned char *)newbuffer;
packet.bytes = sizeof(newbuffer);