diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h index 549546be..9641f91b 100644 --- a/include/FLAC++/metadata.h +++ b/include/FLAC++/metadata.h @@ -782,6 +782,80 @@ namespace FLAC { FLAC__uint32 calculate_cddb_id() const; }; + /** PICTURE metadata block. + * See format specification. + */ + class FLACPP_API Picture : public Prototype { + public: + Picture(); + + //@{ + /** Constructs a copy of the given object. This form + * always performs a deep copy. + */ + inline Picture(const Picture &object): Prototype(object) { } + inline Picture(const ::FLAC__StreamMetadata &object): Prototype(object) { } + inline Picture(const ::FLAC__StreamMetadata *object): Prototype(object) { } + //@} + + /** Constructs an object with copy control. See + * Prototype(::FLAC__StreamMetadata *object, bool copy). + */ + inline Picture(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { } + + ~Picture(); + + //@{ + /** Assign from another object. Always performs a deep copy. */ + inline Picture &operator=(const Picture &object) { Prototype::operator=(object); return *this; } + inline Picture &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; } + inline Picture &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; } + //@} + + /** Assigns an object with copy control. See + * Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy). + */ + inline Picture &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; } + + //@{ + /** Check for equality, performing a deep compare by following pointers. */ + inline bool operator==(const Picture &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); } + inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); } + //@} + + //@{ + /** Check for inequality, performing a deep compare by following pointers. */ + inline bool operator!=(const Picture &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); } + inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); } + //@} + + ::FLAC__StreamMetadata_Picture_Type get_type() const; + const char *get_mime_type() const; // NUL-terminated printable ASCII string + const FLAC__byte *get_description() const; // NUL-terminated UTF-8 string + FLAC__uint32 get_width() const; + FLAC__uint32 get_height() const; + FLAC__uint32 get_depth() const; + FLAC__uint32 get_data_length() const; + const FLAC__byte *get_data() const; + + void set_type(::FLAC__StreamMetadata_Picture_Type type); + + //! See FLAC__metadata_object_picture_set_mime_type() + bool set_mime_type(const char *string); // NUL-terminated printable ASCII string + + //! See FLAC__metadata_object_picture_set_description() + bool set_description(const FLAC__byte *string); // NUL-terminated UTF-8 string + + void set_width(FLAC__uint32 value) const; + void set_height(FLAC__uint32 value) const; + void set_depth(FLAC__uint32 value) const; + + //! See FLAC__metadata_object_picture_set_data() + bool set_data(const FLAC__byte *data, FLAC__uint32 data_length); + }; + /** Opaque metadata block for storing unknown types. * This should not be used unless you know what you are doing; * it is currently used only internally to support forward @@ -855,16 +929,16 @@ namespace FLAC { * \{ */ - //! See FLAC__metadata_get_streaminfo(). - FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo); + FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo); //< See FLAC__metadata_get_streaminfo(). - //! See FLAC__metadata_get_tags(). - FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags); - FLACPP_API bool get_tags(const char *filename, VorbisComment &tags); + FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags); //< See FLAC__metadata_get_tags(). + FLACPP_API bool get_tags(const char *filename, VorbisComment &tags); //< See FLAC__metadata_get_tags(). - //! See FLAC__metadata_get_cuesheet(). - FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet); - FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet); + FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet); //! See FLAC__metadata_get_cuesheet(). + FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet); //! See FLAC__metadata_get_cuesheet(). + + FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth); //! See FLAC__metadata_get_picture(). + FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth); //! See FLAC__metadata_get_picture(). /* \} */ diff --git a/include/FLAC/format.h b/include/FLAC/format.h index de9f6eae..6d09df69 100644 --- a/include/FLAC/format.h +++ b/include/FLAC/format.h @@ -478,7 +478,10 @@ typedef enum { FLAC__METADATA_TYPE_CUESHEET = 5, /**< CUESHEET block */ - FLAC__METADATA_TYPE_UNDEFINED = 6 + FLAC__METADATA_TYPE_PICTURE = 6, + /**< PICTURE block */ + + FLAC__METADATA_TYPE_UNDEFINED = 7 /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ } FLAC__MetadataType; @@ -678,7 +681,7 @@ typedef struct { /**< The number of lead-in samples. */ FLAC__bool is_cd; - /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false */ + /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */ unsigned num_tracks; /**< The number of tracks. */ @@ -695,6 +698,92 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */ +/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */ +typedef enum { + FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */ + FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */ + FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */ + FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */ + FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */ + FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */ + FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */ + FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */ + FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */ + FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */ + FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */ + FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */ + FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED +} FLAC__StreamMetadata_Picture_Type; + +/** Maps a FLAC__StreamMetadata_Picture_Type to a C string. + * + * Using a FLAC__StreamMetadata_Picture_Type as the index to this array + * will give the string equivalent. The contents should not be + * modified. + */ +extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[]; + +/** FLAC PICTURE structure. (See the + * format specification + * for the full description of each field.) + */ +typedef struct { + FLAC__StreamMetadata_Picture_Type type; + /**< The kind of picture stored. */ + + char *mime_type; + /**< Picture data's MIME type, in ASCII printable characters + * 0x20-0x7e, NUL terminated. For best compatibility with players, + * use picture data of MIME type \c image/jpeg or \c image/png. A + * MIME type of '-->' is also allowed, in which case the picture + * data should be a complete URL. In file storage, the MIME type is + * stored as a 32-bit length followed by the ASCII string with no NUL + * terminator, but is converted to a plain C string in this structure + * for convenience. + */ + + FLAC__byte *description; + /**< Picture's description in UTF-8, NUL terminated. In file storage, + * the description is stored as a 32-bit length followed by the UTF-8 + * string with no NUL terminator, but is converted to a plain C string + * in this structure for convenience. + */ + + FLAC__uint32 width; + /**< Picture's width in pixels. */ + + FLAC__uint32 height; + /**< Picture's height in pixels. */ + + FLAC__uint32 depth; + /**< Picture's color depth in bits-per-pixel. */ + + FLAC__uint32 data_length; + /**< Length of binary picture data in bytes. */ + + FLAC__byte *data; + /**< Binary picture data. */ + +} FLAC__StreamMetadata_Picture; + +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */ +extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */ + + /** Structure that is used when a metadata block of unknown type is loaded. * The contents are opaque. The structure is used only internally to * correctly handle unknown metadata. @@ -725,6 +814,7 @@ typedef struct { FLAC__StreamMetadata_SeekTable seek_table; FLAC__StreamMetadata_VorbisComment vorbis_comment; FLAC__StreamMetadata_CueSheet cue_sheet; + FLAC__StreamMetadata_Picture picture; FLAC__StreamMetadata_Unknown unknown; } data; /**< Polymorphic block data; use the \a type value to determine which @@ -852,6 +942,25 @@ FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *se */ FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); +/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ +/** Check picture data to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * PICTURE block. + * + * \param picture A pointer to existing picture data to be checked. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code picture != NULL \endcode + * \retval FLAC__bool + * \c false if picture data is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation); + /* \} */ #ifdef __cplusplus diff --git a/include/FLAC/metadata.h b/include/FLAC/metadata.h index e5799de8..68b24531 100644 --- a/include/FLAC/metadata.h +++ b/include/FLAC/metadata.h @@ -64,7 +64,8 @@ * There are three metadata interfaces of increasing complexity: * * Level 0: - * Read-only access to the STREAMINFO and VORBIS_COMMENT blocks. + * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and + * PICTURE blocks. * * Level 1: * Read-write access to all metadata blocks. This level is write- @@ -124,7 +125,8 @@ extern "C" { * * \brief * The level 0 interface consists of individual routines to read the - * STREAMINFO, VORBIS_COMMENT, and CUESHEET blocks, requiring only a filename. + * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring + * only a filename. * * They try to skip any ID3v2 tag at the head of the file. * @@ -162,7 +164,7 @@ FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__St * \code tags != NULL \endcode * \retval FLAC__bool * \c true if a valid VORBIS_COMMENT block was read from \a filename, - * and \a *tags will be set to the address of the tag structure. + * and \a *tags will be set to the address of the metadata structure. * Returns \c false if there was a memory allocation error, a file * decoder error, or the file contained no VORBIS_COMMENT block, and * \a *tags will be set to \c NULL. @@ -181,13 +183,51 @@ FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMe * \code cuesheet != NULL \endcode * \retval FLAC__bool * \c true if a valid CUESHEET block was read from \a filename, - * and \a *cuesheet will be set to the address of the tag structure. - * Returns \c false if there was a memory allocation error, a file - * decoder error, or the file contained no CUESHEET block, and - * \a *cuesheet will be set to \c NULL. + * and \a *cuesheet will be set to the address of the metadata + * structure. Returns \c false if there was a memory allocation + * error, a file decoder error, or the file contained no CUESHEET + * block, and \a *cuesheet will be set to \c NULL. */ FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet); +/** Read a PICTURE metadata block of the given FLAC file. This + * function will try to skip any ID3v2 tag at the head of the file. + * Since there can be more than one PICTURE block in a file, this + * function takes a number of parameters that act as constraints to + * the search. The PICTURE block with the largest area matching all + * the constraints will be returned, or \a *picture will be set to + * \c NULL if there was no such block. + * + * \param filename The path to the FLAC file to read. + * \param picture The address where the returned pointer will be + * stored. The \a picture object must be deleted by + * the caller using FLAC__metadata_object_delete(). + * \param type The desired picture type. Use \c -1 to mean + * "any type". + * \param mime_type The desired MIME type, e.g. "image/jpeg". The + * string will be matched exactly. Use \c NULL to + * mean "any MIME type". + * \param description The desired description. The string will be + * matched exactly. Use \c NULL to mean "any + * description". + * \param max_width The maximum width in pixels desired. Use + * \c (unsigned)(-1) to mean "any width". + * \param max_height The maximum height in pixels desired. Use + * \c (unsigned)(-1) to mean "any height". + * \param max_depth The maximum color depth in bits-per-pixel desired. + * Use \c (unsigned)(-1) to mean "any depth". + * \assert + * \code filename != NULL \endcode + * \code picture != NULL \endcode + * \retval FLAC__bool + * \c true if a valid PICTURE block was read from \a filename, + * and \a *picture will be set to the address of the metadata + * structure. Returns \c false if there was a memory allocation + * error, a file decoder error, or the file contained no PICTURE + * block, and \a *picture will be set to \c NULL. + */ +FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth); + /* \} */ @@ -203,9 +243,9 @@ FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__Stre * - Create an iterator using FLAC__metadata_simple_iterator_new() * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to - * see if the file is writable, or read-only access is allowed. + * see if the file is writable, or only read access is allowed. * - Use FLAC__metadata_simple_iterator_next() and - * FLAC__metadata_simple_iterator_prev() to move around the blocks. + * FLAC__metadata_simple_iterator_prev() to traverse the blocks. * This is does not read the actual blocks themselves. * FLAC__metadata_simple_iterator_next() is relatively fast. * FLAC__metadata_simple_iterator_prev() is slower since it needs to search @@ -1185,7 +1225,11 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b /** Sets the application data of an APPLICATION block. * * If \a copy is \c true, a copy of the data is stored; otherwise, the object - * takes ownership of the pointer. + * takes ownership of the pointer. The existing data will be freed if this + * function is successful, otherwise the original data will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a data if \a copy is \c true. * * \param object A pointer to an existing APPLICATION object. * \param data A pointer to the data to set. @@ -1911,6 +1955,95 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMe */ FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object); +/** Sets the MIME type of a PICTURE block. + * + * If \a copy is \c true, a copy of the string is stored; otherwise, the object + * takes ownership of the pointer. The existing string will be freed if this + * function is successful, otherwise the original string will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param mime_type A pointer to the MIME type string. The string must be + * ASCII characters 0x20-0x7e, NUL-terminated. No validation + * is done. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (mime_type != NULL) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy); + +/** Sets the description of a PICTURE block. + * + * If \a copy is \c true, a copy of the string is stored; otherwise, the object + * takes ownership of the pointer. The existing string will be freed if this + * function is successful, otherwise the original string will remain if \a copy + * is \c true and malloc() fails. + * + * \note It is safe to pass a const pointer to \a description if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param description A pointer to the description string. The string must be + * valid UTF-8, NUL-terminated. No validation is done. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (description != NULL) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy); + +/** Sets the picture data of a PICTURE block. + * + * If \a copy is \c true, a copy of the data is stored; otherwise, the object + * takes ownership of the pointer. Also sets the \a data_length field of the + * metadata object to what is passed in as the \a length parameter. The + * existing data will be freed if this function is successful, otherwise the + * original data and data_length will remain if \a copy is \c true and + * malloc() fails. + * + * \note It is safe to pass a const pointer to \a data if \a copy is \c true. + * + * \param object A pointer to an existing PICTURE object. + * \param data A pointer to the data to set. + * \param length The length of \a data in bytes. + * \param copy See above. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \code (data != NULL && length > 0) || + * (data == NULL && length == 0 && copy == false) \endcode + * \retval FLAC__bool + * \c false if \a copy is \c true and malloc() fails, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy); + +/** Check a PICTURE block to see if it conforms to the FLAC specification. + * See the format specification for limits on the contents of the + * PICTURE block. + * + * \param picture A pointer to existing PICTURE block to be checked. + * \param violation Address of a pointer to a string. If there is a + * violation, a pointer to a string explanation of the + * violation will be returned here. \a violation may be + * \c NULL if you don't need the returned string. Do not + * free the returned string; it will always point to static + * data. + * \assert + * \code object != NULL \endcode + * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode + * \retval FLAC__bool + * \c false if PICTURE block is illegal, else \c true. + */ +FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation); + /* \} */ #ifdef __cplusplus diff --git a/include/test_libs_common/metadata_utils.h b/include/test_libs_common/metadata_utils.h index 3d7af192..882bf5b5 100644 --- a/include/test_libs_common/metadata_utils.h +++ b/include/test_libs_common/metadata_utils.h @@ -40,6 +40,8 @@ FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_V FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy); +FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy); + FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length); FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy); @@ -52,6 +54,7 @@ void mutils__init_metadata_blocks( FLAC__StreamMetadata *application2, FLAC__StreamMetadata *vorbiscomment, FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, FLAC__StreamMetadata *unknown ); @@ -63,6 +66,7 @@ void mutils__free_metadata_blocks( FLAC__StreamMetadata *application2, FLAC__StreamMetadata *vorbiscomment, FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, FLAC__StreamMetadata *unknown ); diff --git a/src/libFLAC++/metadata.cpp b/src/libFLAC++/metadata.cpp index fc557033..30ca841e 100644 --- a/src/libFLAC++/metadata.cpp +++ b/src/libFLAC++/metadata.cpp @@ -68,6 +68,9 @@ namespace FLAC { case FLAC__METADATA_TYPE_CUESHEET: ret = new CueSheet(object, /*copy=*/false); break; + case FLAC__METADATA_TYPE_PICTURE: + ret = new Picture(object, /*copy=*/false); + break; default: ret = new Unknown(object, /*copy=*/false); break; @@ -87,6 +90,7 @@ namespace FLAC { const SeekTable *seektable = dynamic_cast(object); const VorbisComment *vorbiscomment = dynamic_cast(object); const CueSheet *cuesheet = dynamic_cast(object); + const Picture *picture = dynamic_cast(object); const Unknown *unknown = dynamic_cast(object); if(0 != streaminfo) @@ -101,6 +105,8 @@ namespace FLAC { return new VorbisComment(*vorbiscomment); else if(0 != cuesheet) return new CueSheet(*cuesheet); + else if(0 != picture) + return new Picture(*picture); else if(0 != unknown) return new Unknown(*unknown); else { @@ -1014,6 +1020,111 @@ namespace FLAC { } + // + // Picture + // + + Picture::Picture(): + Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false) + { } + + Picture::~Picture() + { } + + ::FLAC__StreamMetadata_Picture_Type Picture::get_type() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.type; + } + + const char *Picture::get_mime_type() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.mime_type; + } + + const FLAC__byte *Picture::get_description() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.description; + } + + FLAC__uint32 Picture::get_width() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.width; + } + + FLAC__uint32 Picture::get_height() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.height; + } + + FLAC__uint32 Picture::get_depth() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.depth; + } + + FLAC__uint32 Picture::get_data_length() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.data_length; + } + + const FLAC__byte *Picture::get_data() const + { + FLAC__ASSERT(is_valid()); + return object_->data.picture.data; + } + + void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type) + { + FLAC__ASSERT(is_valid()); + object_->data.picture.type = type; + } + + bool Picture::set_mime_type(const char *string) + { + FLAC__ASSERT(is_valid()); + // We can safely const_cast since copy=true + return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast(string), /*copy=*/true); + } + + bool Picture::set_description(const FLAC__byte *string) + { + FLAC__ASSERT(is_valid()); + // We can safely const_cast since copy=true + return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast(string), /*copy=*/true); + } + + void Picture::set_width(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.width = value; + } + + void Picture::set_height(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.height = value; + } + + void Picture::set_depth(FLAC__uint32 value) const + { + FLAC__ASSERT(is_valid()); + object_->data.picture.depth = value; + } + + bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length) + { + FLAC__ASSERT(is_valid()); + // We can safely const_cast since copy=true + return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast(data), data_length, /*copy=*/true); + } + + // // Unknown // @@ -1124,6 +1235,36 @@ namespace FLAC { return false; } + FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + picture = 0; + + if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth)) { + picture = new Picture(object, /*copy=*/false); + return true; + } + else + return false; + } + + FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth) + { + FLAC__ASSERT(0 != filename); + + ::FLAC__StreamMetadata *object; + + if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth)) { + picture.assign(object, /*copy=*/false); + return true; + } + else + return false; + } + // ============================================================ // diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c index 939ec670..bb5feebe 100644 --- a/src/libFLAC/format.c +++ b/src/libFLAC/format.c @@ -104,6 +104,14 @@ FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */ FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */ +FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */ + FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ @@ -168,7 +176,32 @@ FLAC_API const char * const FLAC__MetadataTypeString[] = { "APPLICATION", "SEEKTABLE", "VORBIS_COMMENT", - "CUESHEET" + "CUESHEET", + "PICTURE" +}; + +FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = { + "Other", + "32x32 pixels 'file icon' (PNG only)", + "Other file icon", + "Cover (front)", + "Cover (back)", + "Leaflet page", + "Media (e.g. label side of CD)", + "Lead artist/lead performer/soloist", + "Artist/performer", + "Conductor", + "Band/Orchestra", + "Composer", + "Lyricist/text writer", + "Recording Location", + "During recording", + "During performance", + "Movie/video screen capture", + "A bright coloured fish", + "Illustration", + "Band/artist logotype", + "Publisher/Studio logotype" }; FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate) @@ -437,6 +470,30 @@ FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_Cu return true; } +FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation) +{ + char *p; + FLAC__byte *b; + + for(p = picture->mime_type; *p; p++) { + if(*p < 0x20 || *p > 0x7e) { + if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)"; + return false; + } + } + + for(b = picture->description; *b; ) { + unsigned n = utf8len_(b); + if(n == 0) { + if(violation) *violation = "description string must be valid UTF-8"; + return false; + } + b += n; + } + + return true; +} + /* * These routines are private to libFLAC */ diff --git a/src/libFLAC/include/private/metadata.h b/src/libFLAC/include/private/metadata.h index 277d9895..7d4b5d86 100644 --- a/src/libFLAC/include/private/metadata.h +++ b/src/libFLAC/include/private/metadata.h @@ -34,7 +34,12 @@ #include "FLAC/metadata.h" +/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not + * be a consistent state (e.g. PICTURE) or equivalent to the initial + * state after FLAC__metadata_object_new() + */ void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object); + void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object); #endif diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c index 2ecb8b1e..a1c699aa 100644 --- a/src/libFLAC/metadata_iterators.c +++ b/src/libFLAC/metadata_iterators.c @@ -92,6 +92,7 @@ static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comme static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block); +static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block); static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length); static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block); @@ -104,6 +105,7 @@ static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handl static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block); static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block); static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block); +static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block); static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length); static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block); @@ -274,6 +276,55 @@ void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErro cd->got_error = true; } +FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth) +{ + FLAC__Metadata_SimpleIterator *it; + FLAC__uint64 max_area_seen = 0; + FLAC__uint64 max_depth_seen = 0; + + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != picture); + + *picture = 0; + + it = FLAC__metadata_simple_iterator_new(); + if(0 == it) + return false; + if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) { + FLAC__metadata_simple_iterator_delete(it); + return false; + } + do { + if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) { + FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it); + FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height; + /* check constraints */ + if( + (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) && + (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) && + (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) && + obj->data.picture.width <= max_width && + obj->data.picture.height <= max_height && + obj->data.picture.depth <= max_depth && + (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen)) + ) { + if(*picture) + FLAC__metadata_object_delete(*picture); + *picture = obj; + max_area_seen = area; + max_depth_seen = obj->data.picture.depth; + } + else { + FLAC__metadata_object_delete(obj); + } + } + } while(FLAC__metadata_simple_iterator_next(it)); + + FLAC__metadata_simple_iterator_delete(it); + + return (0 != *picture); +} + /**************************************************************************** * @@ -1851,6 +1902,8 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment); case FLAC__METADATA_TYPE_CUESHEET: return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture); default: return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length); } @@ -1882,7 +1935,6 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; } - FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length) { (void)block; /* nothing to do; we don't care about reading the padding bytes */ @@ -1947,7 +1999,7 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entr const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8; FLAC__byte buffer[4]; /* magic number is asserted below */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == 4); + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer)); if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len) return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; @@ -1979,7 +2031,7 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_( const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; FLAC__byte buffer[4]; /* magic number is asserted below */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == 4); + FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer)); if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string)))) return status; @@ -2117,6 +2169,85 @@ FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; } +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len) +{ + FLAC__byte buffer[sizeof(FLAC__uint32)]; + + FLAC__ASSERT(0 != data); + FLAC__ASSERT(length_len%8 == 0); + + length_len /= 8; /* convert to bytes */ + + FLAC__ASSERT(sizeof(buffer) >= length_len); + + if(read_cb(buffer, 1, length_len, handle) != length_len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + *length = unpack_uint32_(buffer, length_len); + + if(0 != *data) + free(*data); + + if(0 == (*data = (FLAC__byte*)malloc(*length+1))) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR; + + if(*length > 0) { + if(read_cb(*data, 1, *length, handle) != *length) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + } + + (*data)[*length] = '\0'; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + +FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block) +{ + FLAC__Metadata_SimpleIteratorStatus status; + FLAC__byte buffer[4]; /* asserted below that this is big enough */ + FLAC__uint32 len; + + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len); + + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->width = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->height = unpack_uint32_(buffer, len); + + FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0); + len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8; + if(read_cb(buffer, 1, len, handle) != len) + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR; + block->depth = unpack_uint32_(buffer, len); + + /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */ + if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) + return status; + + return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK; +} + FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length) { if(block_length == 0) { @@ -2193,6 +2324,8 @@ FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment); case FLAC__METADATA_TYPE_CUESHEET: return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture); default: return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length); } @@ -2285,7 +2418,7 @@ FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, F const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8; FLAC__byte buffer[4]; /* magic number is asserted below */ - FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == 4); + FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer)); pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len); if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len) @@ -2402,6 +2535,73 @@ FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__I return true; } +FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block) +{ + unsigned len; + size_t slen; + FLAC__byte buffer[4]; /* magic number is asserted below */ + + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8); + FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8); + FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8); + + len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8; + pack_uint32_(block->type, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8; + slen = strlen(block->mime_type); + pack_uint32_(slen, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->mime_type, 1, slen, handle) != slen) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8; + slen = strlen((const char *)block->description); + pack_uint32_(slen, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->description, 1, slen, handle) != slen) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8; + pack_uint32_(block->width, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8; + pack_uint32_(block->height, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8; + pack_uint32_(block->depth, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + + len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8; + pack_uint32_(block->data_length, buffer, len); + if(write_cb(buffer, 1, len, handle) != len) + return false; + if(write_cb(block->data, 1, block->data_length, handle) != block->data_length) + return false; + + return true; +} + FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length) { if(write_cb(block->data, 1, block_length, handle) != block_length) @@ -2556,7 +2756,7 @@ unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallbac size_t n; unsigned i; - FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4); + FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer)); /* skip any id3v2 tag */ errno = 0; diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c index 6846c3bc..7efa2cf1 100644 --- a/src/libFLAC/metadata_object.c +++ b/src/libFLAC/metadata_object.c @@ -47,8 +47,17 @@ * ***************************************************************************/ +/* copy bytes: + * from = NULL && bytes = 0 + * to <- NULL + * from != NULL && bytes > 0 + * to <- copy of from + * else ASSERT + * malloc error leaved 'to' unchanged + */ static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes) { + FLAC__ASSERT(0 != to); if(bytes > 0 && 0 != from) { FLAC__byte *x; if(0 == (x = (FLAC__byte*)malloc(bytes))) @@ -64,6 +73,25 @@ static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned return true; } +#if 0 /* UNUSED */ +/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */ +static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes) +{ + FLAC__byte *copy; + FLAC__ASSERT(0 != to); + if(copy_bytes_(©, from, bytes)) { + if(*to) + free(*to); + *to = copy; + return true; + } + else + return false; +} +#endif + +/* reallocate entry to 1 byte larger and add a terminating NUL */ +/* realloc() failure leaves entry unchanged */ static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length) { FLAC__byte *x = (FLAC__byte*)realloc(*entry, length+1); @@ -76,6 +104,24 @@ static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length) return false; } +/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to' + * unchanged if malloc fails, free()ing the original '*to' if it + * succeeds and the original '*to' was not NULL + */ +static FLAC__bool copy_cstring_(char **to, const char *from) +{ + FLAC__ASSERT(to); + char *copy = strdup(from); + if(copy) { + if(*to) + free(*to); + *to = copy; + return true; + } + else + return false; +} + static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from) { to->length = from->length; @@ -417,18 +463,49 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type */ break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: - { - object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING); - if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { - free(object); - return 0; - } - vorbiscomment_calculate_length_(object); + object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING); + if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) { + free(object); + return 0; } + vorbiscomment_calculate_length_(object); break; case FLAC__METADATA_TYPE_CUESHEET: cuesheet_calculate_length_(object); break; + case FLAC__METADATA_TYPE_PICTURE: + object->length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + + 0 /* no data */ + ) / 8; + object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; + object->data.picture.mime_type = 0; + object->data.picture.description = 0; + /* calloc() took care of this for us: + object->data.picture.width = 0; + object->data.picture.height = 0; + object->data.picture.depth = 0; + object->data.picture.data_length = 0; + object->data.picture.data = 0; + */ + /* now initialize mime_type and description with empty strings to make things easier on the client */ + if(!copy_cstring_(&object->data.picture.mime_type, "")) { + free(object); + return 0; + } + if(!copy_cstring_((char**)(&object->data.picture.description), "")) { + if(object->data.picture.mime_type) + free(object->data.picture.mime_type); + free(object); + return 0; + } + break; default: /* calloc() took care of this for us: object->length = 0; @@ -508,6 +585,25 @@ FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMet } } break; + case FLAC__METADATA_TYPE_PICTURE: + to->data.picture.type = object->data.picture.type; + if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) { + FLAC__metadata_object_delete(to); + return 0; + } + if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) { + FLAC__metadata_object_delete(to); + return 0; + } + to->data.picture.width = object->data.picture.width; + to->data.picture.height = object->data.picture.height; + to->data.picture.depth = object->data.picture.depth; + to->data.picture.data_length = object->data.picture.data_length; + if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) { + FLAC__metadata_object_delete(to); + return 0; + } + break; default: if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) { FLAC__metadata_object_delete(to); @@ -556,6 +652,20 @@ void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object) cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks); } break; + case FLAC__METADATA_TYPE_PICTURE: + if(0 != object->data.picture.mime_type) { + free(object->data.picture.mime_type); + object->data.picture.mime_type = 0; + } + if(0 != object->data.picture.description) { + free(object->data.picture.description); + object->data.picture.description = 0; + } + if(0 != object->data.picture.data) { + free(object->data.picture.data); + object->data.picture.data = 0; + } + break; default: if(0 != object->data.unknown.data) { free(object->data.unknown.data); @@ -710,6 +820,27 @@ static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueShe return true; } +static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2) +{ + if(block1->type != block2->type) + return false; + if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type))) + return false; + if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description))) + return false; + if(block1->width != block2->width) + return false; + if(block1->height != block2->height) + return false; + if(block1->depth != block2->depth) + return false; + if(block1->data_length != block2->data_length) + return false; + if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length))) + return false; + return true; +} + static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length) { FLAC__ASSERT(0 != block1); @@ -748,6 +879,8 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment); case FLAC__METADATA_TYPE_CUESHEET: return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return compare_block_data_picture_(&block1->data.picture, &block2->data.picture); default: return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length); } @@ -1553,3 +1686,99 @@ FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLA return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1); } } + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy) +{ + char *old; + size_t old_length, new_length; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT(0 != mime_type); + + old = object->data.picture.mime_type; + old_length = old? strlen(old) : 0; + new_length = strlen(mime_type); + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1)) + return false; + } + else { + object->data.picture.mime_type = mime_type; + } + + if(0 != old) + free(old); + + object->length -= old_length; + object->length += new_length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy) +{ + FLAC__byte *old; + size_t old_length, new_length; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT(0 != description); + + old = object->data.picture.description; + old_length = old? strlen((const char *)old) : 0; + new_length = strlen((const char *)description); + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(!copy_bytes_(&object->data.picture.description, description, new_length+1)) + return false; + } + else { + object->data.picture.description = description; + } + + if(0 != old) + free(old); + + object->length -= old_length; + object->length += new_length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy) +{ + FLAC__byte *old; + + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false)); + + old = object->data.picture.data; + + /* do the copy first so that if we fail we leave the object untouched */ + if(copy) { + if(!copy_bytes_(&object->data.picture.data, data, length)) + return false; + } + else { + object->data.picture.data = data; + } + + if(0 != old) + free(old); + + object->length -= object->data.picture.data_length; + object->data.picture.data_length = length; + object->length += length; + return true; +} + +FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation) +{ + FLAC__ASSERT(0 != object); + FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE); + + return FLAC__format_picture_is_legal(&object->data.picture, violation); +} diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c index d64280dd..802d4958 100644 --- a/src/libFLAC/stream_decoder.c +++ b/src/libFLAC/stream_decoder.c @@ -99,6 +99,7 @@ static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__ static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length); static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj); static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj); +static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj); static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder); static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder); static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode); @@ -1296,6 +1297,10 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) return false; break; + case FLAC__METADATA_TYPE_PICTURE: + if(!read_metadata_picture_(decoder, &block.data.picture)) + return false; + break; case FLAC__METADATA_TYPE_STREAMINFO: case FLAC__METADATA_TYPE_SEEKTABLE: FLAC__ASSERT(0); @@ -1342,6 +1347,14 @@ FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) if(0 != block.data.cue_sheet.tracks) free(block.data.cue_sheet.tracks); break; + case FLAC__METADATA_TYPE_PICTURE: + if(0 != block.data.picture.mime_type) + free(block.data.picture.mime_type); + if(0 != block.data.picture.description) + free(block.data.picture.description); + if(0 != block.data.picture.data) + free(block.data.picture.data); + break; case FLAC__METADATA_TYPE_STREAMINFO: case FLAC__METADATA_TYPE_SEEKTABLE: FLAC__ASSERT(0); @@ -1616,6 +1629,69 @@ FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMet return true; } +FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj) +{ + FLAC__uint32 len; + + FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input)); + + /* read type */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + + /* read MIME type */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + if(0 == (obj->mime_type = (char*)malloc(len+1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(len > 0) { + if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, len, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + } + obj->mime_type[len] = '\0'; + + /* read description */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + if(0 == (obj->description = (FLAC__byte*)malloc(len+1))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(len > 0) { + if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, len, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + } + obj->description[len] = '\0'; + + /* read width */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + + /* read height */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + + /* read depth */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + + /* read data */ + if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + if(0 == (obj->data = (FLAC__byte*)malloc(obj->data_length))) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + if(obj->data_length > 0) { + if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length, read_callback_, decoder)) + return false; /* read_callback_ sets the state for us */ + } + + return true; +} + FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder) { FLAC__uint32 x; diff --git a/src/libFLAC/stream_encoder.c b/src/libFLAC/stream_encoder.c index be11e5e0..407346fd 100644 --- a/src/libFLAC/stream_encoder.c +++ b/src/libFLAC/stream_encoder.c @@ -773,6 +773,10 @@ FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__St if(!FLAC__format_cuesheet_is_legal(&encoder->protected_->metadata[i]->data.cue_sheet, encoder->protected_->metadata[i]->data.cue_sheet.is_cd, /*violation=*/0)) return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; } + else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_PICTURE) { + if(!FLAC__format_picture_is_legal(&encoder->protected_->metadata[i]->data.picture, /*violation=*/0)) + return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA; + } } encoder->private_->input_capacity = 0; diff --git a/src/libFLAC/stream_encoder_framing.c b/src/libFLAC/stream_encoder_framing.c index 87611b7b..29bde9e2 100644 --- a/src/libFLAC/stream_encoder_framing.c +++ b/src/libFLAC/stream_encoder_framing.c @@ -177,6 +177,33 @@ FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__ } } break; + case FLAC__METADATA_TYPE_PICTURE: + { + size_t len; + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) + return false; + len = strlen(metadata->data.picture.mime_type); + if(!FLAC__bitbuffer_write_raw_uint32(bb, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) + return false; + if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)metadata->data.picture.mime_type, len)) + return false; + len = strlen((const char *)metadata->data.picture.description); + if(!FLAC__bitbuffer_write_raw_uint32(bb, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) + return false; + if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.picture.description, len)) + return false; + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) + return false; + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) + return false; + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) + return false; + if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) + return false; + if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.picture.data, metadata->data.picture.data_length)) + return false; + } + break; default: if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.unknown.data, metadata->length)) return false; diff --git a/src/metaflac/operations.c b/src/metaflac/operations.c index a2a7d7ff..aad872b7 100644 --- a/src/metaflac/operations.c +++ b/src/metaflac/operations.c @@ -646,6 +646,18 @@ void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned } } break; + case FLAC__METADATA_TYPE_PICTURE: + PPR; printf(" type: %u (%s)\n", block->data.picture.type, block->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED? FLAC__StreamMetadata_Picture_TypeString[block->data.picture.type] : "UNDEFINED"); + PPR; printf(" MIME type: %s\n", block->data.picture.mime_type); + PPR; printf(" description: %s\n", block->data.picture.description); + PPR; printf(" width: %u\n", (unsigned)block->data.picture.width); + PPR; printf(" height: %u\n", (unsigned)block->data.picture.height); + PPR; printf(" depth: %u\n", (unsigned)block->data.picture.depth); + PPR; printf(" data length: %u\n", (unsigned)block->data.picture.data_length); + PPR; printf(" data:\n"); + if(0 != block->data.picture.data) + hexdump(filename, block->data.picture.data, block->data.picture.data_length, " "); + break; default: PPR; printf(" data contents:\n"); if(0 != block->data.unknown.data) diff --git a/src/test_libFLAC++/decoders.cpp b/src/test_libFLAC++/decoders.cpp index 486af3b6..976342d2 100644 --- a/src/test_libFLAC++/decoders.cpp +++ b/src/test_libFLAC++/decoders.cpp @@ -58,8 +58,8 @@ static const char * const LayerString[] = { "Filename" }; -static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static ::FLAC__StreamMetadata *expected_metadata_sequence_[8]; +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static ::FLAC__StreamMetadata *expected_metadata_sequence_[9]; static unsigned num_expected_; static const char *flacfilename_ = "metadata.flac"; static off_t flacfilesize_; @@ -86,12 +86,12 @@ static FLAC__bool die_s_(const char *msg, const FLAC::Decoder::Stream *decoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static bool generate_file_() @@ -105,6 +105,7 @@ static bool generate_file_() expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!file_utils__generate_flacfile(flacfilename_, &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_)) @@ -710,6 +711,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -756,6 +758,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -785,6 +788,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -815,6 +819,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -851,6 +856,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -993,6 +999,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) diff --git a/src/test_libFLAC++/encoders.cpp b/src/test_libFLAC++/encoders.cpp index 24845b80..94124b9f 100644 --- a/src/test_libFLAC++/encoders.cpp +++ b/src/test_libFLAC++/encoders.cpp @@ -42,8 +42,8 @@ static const char * const LayerString[] = { "Filename" }; -static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static ::FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_ }; +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static ::FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_ }; static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]); static const char *flacfilename_ = "metadata.flac"; @@ -73,12 +73,12 @@ static bool die_s_(const char *msg, const FLAC::Encoder::Stream *encoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } class StreamEncoder : public FLAC::Encoder::Stream { diff --git a/src/test_libFLAC++/metadata_manip.cpp b/src/test_libFLAC++/metadata_manip.cpp index a8138130..cf27b9e4 100644 --- a/src/test_libFLAC++/metadata_manip.cpp +++ b/src/test_libFLAC++/metadata_manip.cpp @@ -106,6 +106,16 @@ static void *malloc_or_die_(size_t size) return x; } +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + /* functions for working with our metadata copy */ static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy) @@ -474,10 +484,10 @@ void OurFileDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status) printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status); } -static bool generate_file_(FLAC__bool include_cuesheet) +static bool generate_file_(FLAC__bool include_extras) { - ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding; - ::FLAC__StreamMetadata *metadata[3]; + ::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding; + ::FLAC__StreamMetadata *metadata[4]; unsigned i = 0, n = 0; printf("generating FLAC file for test\n"); @@ -524,23 +534,54 @@ static bool generate_file_(FLAC__bool include_cuesheet) return die_("priming our metadata"); } + { + picture.is_last = false; + picture.type = ::FLAC__METADATA_TYPE_PICTURE; + picture.length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture.data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture.length += strlen(picture.data.picture.mime_type); + picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture.length += strlen((const char *)picture.data.picture.description); + picture.data.picture.width = 300; + picture.data.picture.height = 300; + picture.data.picture.depth = 24; + picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture.data.picture.data_length = strlen((const char *)picture.data.picture.data); + picture.length += picture.data.picture.data_length; + } + padding.is_last = true; padding.type = ::FLAC__METADATA_TYPE_PADDING; padding.length = 1234; metadata[n++] = &vorbiscomment; - if (include_cuesheet) + if(include_extras) { metadata[n++] = cuesheet; + metadata[n++] = &picture; + } metadata[n++] = &padding; FLAC::Metadata::StreamInfo s(&streaminfo); FLAC::Metadata::VorbisComment v(&vorbiscomment); FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false); + FLAC::Metadata::Picture pi(&picture); FLAC::Metadata::Padding p(&padding); if( !insert_to_our_metadata_(&s, i++, /*copy=*/true) || !insert_to_our_metadata_(&v, i++, /*copy=*/true) || - (include_cuesheet && !insert_to_our_metadata_(&v, i++, /*copy=*/true)) || + (include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) || + (include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) || !insert_to_our_metadata_(&p, i++, /*copy=*/true) ) return die_("priming our metadata"); @@ -616,7 +657,7 @@ static bool test_level_0_() printf("\n\n++++++ testing level 0 interface\n"); - if(!generate_file_(/*include_cuesheet=*/true)) + if(!generate_file_(/*include_extras=*/true)) return false; if(!test_file_(flacfile_, /*ignore_metadata=*/true)) @@ -705,6 +746,38 @@ static bool test_level_0_() printf("OK\n"); } + { + printf("testing FLAC::Metadata::get_picture(Picture *&)... "); + + FLAC::Metadata::Picture *picture = 0; + + if(!FLAC::Metadata::get_picture(flacfile_, picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1))) + return die_("during FLAC::Metadata::get_picture()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) + return die_("mismatch in picture->get_type ()"); + + printf("OK\n"); + + delete picture; + } + + { + printf("testing FLAC::Metadata::get_picture(Picture &)... "); + + FLAC::Metadata::Picture picture; + + if(!FLAC::Metadata::get_picture(flacfile_, picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1))) + return die_("during FLAC::Metadata::get_picture()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) + return die_("mismatch in picture->get_type ()"); + + printf("OK\n"); + } + if(!remove_file_(flacfile_)) return false; @@ -729,7 +802,7 @@ static bool test_level_1_() { printf("simple iterator on read-only file\n"); - if(!generate_file_(/*include_cuesheet=*/false)) + if(!generate_file_(/*include_extras=*/false)) return false; if(!change_stats_(flacfile_, /*read_only=*/true)) @@ -1394,7 +1467,7 @@ static bool test_level_2_(bool filename_based) printf("generate read-only file\n"); - if(!generate_file_(/*include_cuesheet=*/false)) + if(!generate_file_(/*include_extras=*/false)) return false; if(!change_stats_(flacfile_, /*read_only=*/true)) @@ -1949,7 +2022,7 @@ static bool test_level_2_misc_() printf("generate file\n"); - if(!generate_file_(/*include_cuesheet=*/false)) + if(!generate_file_(/*include_extras=*/false)) return false; printf("create chain\n"); diff --git a/src/test_libFLAC++/metadata_object.cpp b/src/test_libFLAC++/metadata_object.cpp index 845fb1f7..ccf41f52 100644 --- a/src/test_libFLAC++/metadata_object.cpp +++ b/src/test_libFLAC++/metadata_object.cpp @@ -22,7 +22,7 @@ #include /* for malloc() */ #include /* for memcmp() */ -static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application_, vorbiscomment_, cuesheet_; +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application_, vorbiscomment_, cuesheet_, picture_; static bool die_(const char *msg) { @@ -40,6 +40,16 @@ static void *malloc_or_die_(size_t size) return x; } +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + static bool index_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Index &index, const ::FLAC__StreamMetadata_CueSheet_Index &indexcopy) { if(indexcopy.offset != index.offset) @@ -131,7 +141,7 @@ static void init_metadata_blocks_() vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12+1); memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12+1); - cuesheet_.is_last = true; + cuesheet_.is_last = false; cuesheet_.type = ::FLAC__METADATA_TYPE_CUESHEET; cuesheet_.length = /* cuesheet guts */ @@ -186,6 +196,31 @@ static void init_metadata_blocks_() cuesheet_.data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index)); cuesheet_.data.cue_sheet.tracks[1].indices[0].offset = 0; cuesheet_.data.cue_sheet.tracks[1].indices[0].number = 1; + + picture_.is_last = true; + picture_.type = FLAC__METADATA_TYPE_PICTURE; + picture_.length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture_.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture_.data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture_.length += strlen(picture_.data.picture.mime_type); + picture_.data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture_.length += strlen((const char *)picture_.data.picture.description); + picture_.data.picture.width = 300; + picture_.data.picture.height = 300; + picture_.data.picture.depth = 24; + picture_.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture_.data.picture.data_length = strlen((const char *)picture_.data.picture.data); + picture_.length += picture_.data.picture.data_length; } static void free_metadata_blocks_() @@ -199,6 +234,9 @@ static void free_metadata_blocks_() free(cuesheet_.data.cue_sheet.tracks[0].indices); free(cuesheet_.data.cue_sheet.tracks[1].indices); free(cuesheet_.data.cue_sheet.tracks); + free(picture_.data.picture.mime_type); + free(picture_.data.picture.description); + free(picture_.data.picture.data); } bool test_metadata_object_streaminfo() @@ -223,7 +261,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy(block); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != block) return die_("copy is not identical to original"); printf("OK\n"); @@ -237,7 +275,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy(streaminfo_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != streaminfo_) return die_("copy is not identical to original"); printf("OK\n"); @@ -248,7 +286,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy(&streaminfo_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != streaminfo_) return die_("copy is not identical to original"); printf("OK\n"); @@ -259,7 +297,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy(&streaminfo_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != streaminfo_) return die_("copy is not identical to original"); printf("OK\n"); @@ -271,7 +309,7 @@ bool test_metadata_object_streaminfo() ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_); FLAC::Metadata::StreamInfo blockcopy(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != streaminfo_) return die_("copy is not identical to original"); printf("OK\n"); @@ -283,7 +321,7 @@ bool test_metadata_object_streaminfo() FLAC::Metadata::StreamInfo blockcopy; blockcopy.assign(&streaminfo_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != streaminfo_) return die_("copy is not identical to original"); printf("OK\n"); @@ -296,7 +334,7 @@ bool test_metadata_object_streaminfo() FLAC::Metadata::StreamInfo blockcopy; blockcopy.assign(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != streaminfo_) return die_("copy is not identical to original"); printf("OK\n"); @@ -307,7 +345,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy = block; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == block)) return die_("copy is not identical to original"); printf("OK\n"); @@ -318,7 +356,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy = streaminfo_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == streaminfo_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -329,7 +367,7 @@ bool test_metadata_object_streaminfo() { FLAC::Metadata::StreamInfo blockcopy = &streaminfo_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == streaminfo_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -456,7 +494,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy(block); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != block) return die_("copy is not identical to original"); printf("OK\n"); @@ -470,7 +508,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy(padding_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != padding_) return die_("copy is not identical to original"); printf("OK\n"); @@ -481,7 +519,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy(&padding_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != padding_) return die_("copy is not identical to original"); printf("OK\n"); @@ -492,7 +530,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy(&padding_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != padding_) return die_("copy is not identical to original"); printf("OK\n"); @@ -504,7 +542,7 @@ bool test_metadata_object_padding() ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_); FLAC::Metadata::Padding blockcopy(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != padding_) return die_("copy is not identical to original"); printf("OK\n"); @@ -516,7 +554,7 @@ bool test_metadata_object_padding() FLAC::Metadata::Padding blockcopy; blockcopy.assign(&padding_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != padding_) return die_("copy is not identical to original"); printf("OK\n"); @@ -529,7 +567,7 @@ bool test_metadata_object_padding() FLAC::Metadata::Padding blockcopy; blockcopy.assign(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != padding_) return die_("copy is not identical to original"); printf("OK\n"); @@ -540,7 +578,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy = block; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == block)) return die_("copy is not identical to original"); printf("OK\n"); @@ -551,7 +589,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy = padding_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == padding_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -562,7 +600,7 @@ bool test_metadata_object_padding() { FLAC::Metadata::Padding blockcopy = &padding_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == padding_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -617,7 +655,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy(block); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != block) return die_("copy is not identical to original"); printf("OK\n"); @@ -631,7 +669,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy(application_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != application_) return die_("copy is not identical to original"); printf("OK\n"); @@ -642,7 +680,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy(&application_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != application_) return die_("copy is not identical to original"); printf("OK\n"); @@ -653,7 +691,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy(&application_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != application_) return die_("copy is not identical to original"); printf("OK\n"); @@ -665,7 +703,7 @@ bool test_metadata_object_application() ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_); FLAC::Metadata::Application blockcopy(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != application_) return die_("copy is not identical to original"); printf("OK\n"); @@ -677,7 +715,7 @@ bool test_metadata_object_application() FLAC::Metadata::Application blockcopy; blockcopy.assign(&application_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != application_) return die_("copy is not identical to original"); printf("OK\n"); @@ -690,7 +728,7 @@ bool test_metadata_object_application() FLAC::Metadata::Application blockcopy; blockcopy.assign(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != application_) return die_("copy is not identical to original"); printf("OK\n"); @@ -701,7 +739,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy = block; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == block)) return die_("copy is not identical to original"); printf("OK\n"); @@ -712,7 +750,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy = application_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == application_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -723,7 +761,7 @@ bool test_metadata_object_application() { FLAC::Metadata::Application blockcopy = &application_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == application_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -787,7 +825,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy(block); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != block) return die_("copy is not identical to original"); printf("OK\n"); @@ -801,7 +839,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy(seektable_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != seektable_) return die_("copy is not identical to original"); printf("OK\n"); @@ -812,7 +850,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy(&seektable_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != seektable_) return die_("copy is not identical to original"); printf("OK\n"); @@ -823,7 +861,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy(&seektable_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != seektable_) return die_("copy is not identical to original"); printf("OK\n"); @@ -835,7 +873,7 @@ bool test_metadata_object_seektable() ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_); FLAC::Metadata::SeekTable blockcopy(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != seektable_) return die_("copy is not identical to original"); printf("OK\n"); @@ -847,7 +885,7 @@ bool test_metadata_object_seektable() FLAC::Metadata::SeekTable blockcopy; blockcopy.assign(&seektable_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != seektable_) return die_("copy is not identical to original"); printf("OK\n"); @@ -860,7 +898,7 @@ bool test_metadata_object_seektable() FLAC::Metadata::SeekTable blockcopy; blockcopy.assign(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != seektable_) return die_("copy is not identical to original"); printf("OK\n"); @@ -871,7 +909,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy = block; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == block)) return die_("copy is not identical to original"); printf("OK\n"); @@ -882,7 +920,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy = seektable_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == seektable_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -893,7 +931,7 @@ bool test_metadata_object_seektable() { FLAC::Metadata::SeekTable blockcopy = &seektable_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == seektable_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1140,7 +1178,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy(block); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != block) return die_("copy is not identical to original"); printf("OK\n"); @@ -1154,7 +1192,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy(vorbiscomment_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != vorbiscomment_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1165,7 +1203,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != vorbiscomment_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1176,7 +1214,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != vorbiscomment_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1188,7 +1226,7 @@ bool test_metadata_object_vorbiscomment() ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_); FLAC::Metadata::VorbisComment blockcopy(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != vorbiscomment_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1200,7 +1238,7 @@ bool test_metadata_object_vorbiscomment() FLAC::Metadata::VorbisComment blockcopy; blockcopy.assign(&vorbiscomment_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != vorbiscomment_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1213,7 +1251,7 @@ bool test_metadata_object_vorbiscomment() FLAC::Metadata::VorbisComment blockcopy; blockcopy.assign(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != vorbiscomment_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1224,7 +1262,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy = block; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == block)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1235,7 +1273,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy = vorbiscomment_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == vorbiscomment_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1246,7 +1284,7 @@ bool test_metadata_object_vorbiscomment() { FLAC::Metadata::VorbisComment blockcopy = &vorbiscomment_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == vorbiscomment_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1518,7 +1556,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy(block); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != block) return die_("copy is not identical to original"); printf("OK\n"); @@ -1532,7 +1570,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy(cuesheet_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != cuesheet_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1543,7 +1581,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy(&cuesheet_); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != cuesheet_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1554,7 +1592,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy(&cuesheet_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != cuesheet_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1566,7 +1604,7 @@ bool test_metadata_object_cuesheet() ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_); FLAC::Metadata::CueSheet blockcopy(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != cuesheet_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1578,7 +1616,7 @@ bool test_metadata_object_cuesheet() FLAC::Metadata::CueSheet blockcopy; blockcopy.assign(&cuesheet_, /*copy=*/true); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != cuesheet_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1591,7 +1629,7 @@ bool test_metadata_object_cuesheet() FLAC::Metadata::CueSheet blockcopy; blockcopy.assign(copy, /*copy=*/false); if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(blockcopy != cuesheet_) return die_("copy is not identical to original"); printf("OK\n"); @@ -1602,7 +1640,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy = block; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == block)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1613,7 +1651,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy = cuesheet_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == cuesheet_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1624,7 +1662,7 @@ bool test_metadata_object_cuesheet() { FLAC::Metadata::CueSheet blockcopy = &cuesheet_; if(!blockcopy.is_valid()) - return die_("!block.is_valid()"); + return die_("!blockcopy.is_valid()"); if(!(blockcopy == cuesheet_)) return die_("copy is not identical to original"); printf("OK\n"); @@ -1759,6 +1797,254 @@ bool test_metadata_object_cuesheet() return true; } +bool test_metadata_object_picture() +{ + unsigned expected_length; + + printf("testing class FLAC::Metadata::Picture\n"); + + printf("testing Picture::Picture()... "); + FLAC::Metadata::Picture block; + if(!block.is_valid()) + return die_("!block.is_valid()"); + expected_length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + ) / 8; + if(block.get_length() != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length()); + return false; + } + printf("OK\n"); + + printf("testing Picture::Picture(const Picture &)... +\n"); + printf(" Picture::operator!=(const Picture &)... "); + { + FLAC::Metadata::Picture blockcopy(block); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != block) + return die_("copy is not identical to original"); + printf("OK\n"); + + printf("testing Picture::~Picture()... "); + } + printf("OK\n"); + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Picture blockcopy(picture_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy(&picture_); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy(&picture_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_); + FLAC::Metadata::Picture blockcopy(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy; + blockcopy.assign(&picture_, /*copy=*/true); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n"); + printf(" Picture::operator!=(const ::FLAC__StreamMetadata *)... "); + { + ::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_); + FLAC::Metadata::Picture blockcopy; + blockcopy.assign(copy, /*copy=*/false); + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(blockcopy != picture_) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::operator=(const Picture &)... +\n"); + printf(" Picture::operator==(const Picture &)... "); + { + FLAC::Metadata::Picture blockcopy = block; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == block)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::operator=(const ::FLAC__StreamMetadata &)... +\n"); + printf(" Picture::operator==(const ::FLAC__StreamMetadata &)... "); + { + FLAC::Metadata::Picture blockcopy = picture_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == picture_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::operator=(const ::FLAC__StreamMetadata *)... +\n"); + printf(" Picture::operator==(const ::FLAC__StreamMetadata *)... "); + { + FLAC::Metadata::Picture blockcopy = &picture_; + if(!blockcopy.is_valid()) + return die_("!blockcopy.is_valid()"); + if(!(blockcopy == picture_)) + return die_("copy is not identical to original"); + printf("OK\n"); + } + + printf("testing Picture::get_type()... "); + if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER) + return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER"); + printf("OK\n"); + + printf("testing Picture::set_type()... +\n"); + printf(" Picture::get_type()... "); + block.set_type(::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA); + if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA) + return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA"); + printf("OK\n"); + + printf("testing Picture::set_mime_type()... "); + if(!block.set_mime_type("qmage/jpeg")) + return die_("returned false"); + printf("OK\n"); + picture_.data.picture.mime_type[0] = 'q'; + + printf("testing Picture::get_mime_type()... "); + if(0 != strcmp(block.get_mime_type(), picture_.data.picture.mime_type)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Picture::set_description()... "); + if(!block.set_description((const FLAC__byte*)"qesc")) + return die_("returned false"); + printf("OK\n"); + picture_.data.picture.description[0] = 'q'; + + printf("testing Picture::get_description()... "); + if(0 != strcmp((const char *)block.get_description(), (const char *)picture_.data.picture.description)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing Picture::get_width()... "); + if(block.get_width() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_width()... +\n"); + printf(" Picture::get_width()... "); + block.set_width(400); + if(block.get_width() != 400) + return die_("value mismatch, expected 400"); + printf("OK\n"); + + printf("testing Picture::get_height()... "); + if(block.get_height() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_height()... +\n"); + printf(" Picture::get_height()... "); + block.set_height(200); + if(block.get_height() != 200) + return die_("value mismatch, expected 200"); + printf("OK\n"); + + printf("testing Picture::get_depth()... "); + if(block.get_depth() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_depth()... +\n"); + printf(" Picture::get_depth()... "); + block.set_depth(16); + if(block.get_depth() != 16) + return die_("value mismatch, expected 16"); + printf("OK\n"); + + printf("testing Picture::get_data_length()... "); + if(block.get_data_length() != 0) + return die_("value mismatch, expected 0"); + printf("OK\n"); + + printf("testing Picture::set_data()... "); + if(!block.set_data((const FLAC__byte*)"qOMEJPEGDATA", strlen("qOMEJPEGDATA"))) + return die_("returned false"); + printf("OK\n"); + picture_.data.picture.data[0] = 'q'; + + printf("testing Picture::get_data()... "); + if(block.get_data_length() != picture_.data.picture.data_length) + return die_("length mismatch"); + if(0 != memcmp(block.get_data(), picture_.data.picture.data, picture_.data.picture.data_length)) + return die_("value mismatch"); + printf("OK\n"); + + printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... "); + FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block); + if(0 == clone_) + return die_("returned NULL"); + if(0 == dynamic_cast(clone_)) + return die_("downcast is NULL"); + if(*dynamic_cast(clone_) != block) + return die_("clone is not identical"); + printf("OK\n"); + printf("testing Picture::~Picture()... "); + delete clone_; + printf("OK\n"); + + + printf("PASSED\n\n"); + return true; +} + bool test_metadata_object() { printf("\n+++ libFLAC++ unit test: metadata objects\n\n"); @@ -1783,6 +2069,9 @@ bool test_metadata_object() if(!test_metadata_object_cuesheet()) return false; + if(!test_metadata_object_picture()) + return false; + free_metadata_blocks_(); return true; diff --git a/src/test_libFLAC/decoders.c b/src/test_libFLAC/decoders.c index 1ac22d4e..3765853a 100644 --- a/src/test_libFLAC/decoders.c +++ b/src/test_libFLAC/decoders.c @@ -58,8 +58,8 @@ typedef struct { FLAC__bool error_occurred; } StreamDecoderClientData; -static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static FLAC__StreamMetadata *expected_metadata_sequence_[8]; +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *expected_metadata_sequence_[9]; static unsigned num_expected_; static const char *flacfilename_ = "metadata.flac"; static off_t flacfilesize_; @@ -86,12 +86,12 @@ static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static FLAC__bool generate_file_() @@ -105,6 +105,7 @@ static FLAC__bool generate_file_() expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!file_utils__generate_flacfile(flacfilename_, &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_)) @@ -627,6 +628,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -667,6 +669,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -692,6 +695,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -718,6 +722,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -748,6 +753,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -866,6 +872,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) diff --git a/src/test_libFLAC/encoders.c b/src/test_libFLAC/encoders.c index 053695f3..f3e97881 100644 --- a/src/test_libFLAC/encoders.c +++ b/src/test_libFLAC/encoders.c @@ -45,8 +45,8 @@ static const char * const LayerString[] = { "Filename" }; -static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_ }; +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_ }; static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]); static const char *flacfilename_ = "metadata.flac"; @@ -76,12 +76,12 @@ static FLAC__bool die_s_(const char *msg, const FLAC__StreamEncoder *encoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static FLAC__StreamEncoderWriteStatus stream_encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) diff --git a/src/test_libFLAC/metadata_manip.c b/src/test_libFLAC/metadata_manip.c index 21a8fa42..81885fde 100644 --- a/src/test_libFLAC/metadata_manip.c +++ b/src/test_libFLAC/metadata_manip.c @@ -100,6 +100,16 @@ static void *malloc_or_die_(size_t size) return x; } +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + /* functions for working with our metadata copy */ static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy) @@ -485,10 +495,10 @@ static void decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__St printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status); } -static FLAC__bool generate_file_(FLAC__bool include_cuesheet) +static FLAC__bool generate_file_(FLAC__bool include_extras) { - FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding; - FLAC__StreamMetadata *metadata[3]; + FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding; + FLAC__StreamMetadata *metadata[4]; unsigned i = 0, n = 0; printf("generating FLAC file for test\n"); @@ -535,19 +545,49 @@ static FLAC__bool generate_file_(FLAC__bool include_cuesheet) return die_("priming our metadata"); } + { + picture.is_last = false; + picture.type = FLAC__METADATA_TYPE_PICTURE; + picture.length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture.data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture.length += strlen(picture.data.picture.mime_type); + picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture.length += strlen((const char *)picture.data.picture.description); + picture.data.picture.width = 300; + picture.data.picture.height = 300; + picture.data.picture.depth = 24; + picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture.data.picture.data_length = strlen((const char *)picture.data.picture.data); + picture.length += picture.data.picture.data_length; + } + padding.is_last = true; padding.type = FLAC__METADATA_TYPE_PADDING; padding.length = 1234; metadata[n++] = &vorbiscomment; - if (include_cuesheet) + if(include_extras) { metadata[n++] = cuesheet; + metadata[n++] = &picture; + } metadata[n++] = &padding; if( !insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) || !insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) || - (include_cuesheet && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) || + (include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) || + (include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) || !insert_to_our_metadata_(&padding, i++, /*copy=*/true) ) return die_("priming our metadata"); @@ -627,10 +667,11 @@ static FLAC__bool test_level_0_() FLAC__StreamMetadata streaminfo; FLAC__StreamMetadata *tags = 0; FLAC__StreamMetadata *cuesheet = 0; + FLAC__StreamMetadata *picture = 0; printf("\n\n++++++ testing level 0 interface\n"); - if(!generate_file_(/*include_cuesheet=*/true)) + if(!generate_file_(/*include_extras=*/true)) return false; if(!test_file_(flacfile_, decoder_metadata_callback_null_)) @@ -675,12 +716,25 @@ static FLAC__bool test_level_0_() /* check to see if some basic data matches (c.f. generate_file_()) */ if(cuesheet->data.cue_sheet.lead_in != 123) - return die_("mismatch in cuesheet->data.vorbis_comment.num_comments"); + return die_("mismatch in cuesheet->data.cue_sheet.lead_in"); printf("OK\n"); FLAC__metadata_object_delete(cuesheet); + printf("testing FLAC__metadata_get_picture()... "); + + if(!FLAC__metadata_get_picture(flacfile_, &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1))) + return die_("during FLAC__metadata_get_picture()"); + + /* check to see if some basic data matches (c.f. generate_file_()) */ + if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER) + return die_("mismatch in picture->data.picture.type"); + + printf("OK\n"); + + FLAC__metadata_object_delete(picture); + if(!remove_file_(flacfile_)) return false; @@ -703,7 +757,7 @@ static FLAC__bool test_level_1_() printf("simple iterator on read-only file\n"); - if(!generate_file_(/*include_cuesheet=*/false)) + if(!generate_file_(/*include_extras=*/false)) return false; if(!change_stats_(flacfile_, /*read_only=*/true)) @@ -1362,7 +1416,7 @@ static FLAC__bool test_level_2_(FLAC__bool filename_based) printf("generate read-only file\n"); - if(!generate_file_(/*include_cuesheet=*/false)) + if(!generate_file_(/*include_extras=*/false)) return false; if(!change_stats_(flacfile_, /*read_only=*/true)) @@ -1875,7 +1929,7 @@ static FLAC__bool test_level_2_misc_() printf("generate file\n"); - if(!generate_file_(/*include_cuesheet=*/false)) + if(!generate_file_(/*include_extras=*/false)) return false; printf("create chain\n"); diff --git a/src/test_libFLAC/metadata_object.c b/src/test_libFLAC/metadata_object.c index 304df90d..2939ed3f 100644 --- a/src/test_libFLAC/metadata_object.c +++ b/src/test_libFLAC/metadata_object.c @@ -463,10 +463,43 @@ static void cs_delete_(FLAC__StreamMetadata *block, unsigned pos) cs_calc_len_(block); } +static void pi_set_mime_type(FLAC__StreamMetadata *block, const char *s) +{ + if(block->data.picture.mime_type) { + block->length -= strlen(block->data.picture.mime_type); + free(block->data.picture.mime_type); + } + block->data.picture.mime_type = strdup(s); + FLAC__ASSERT(block->data.picture.mime_type); + block->length += strlen(block->data.picture.mime_type); +} + +static void pi_set_description(FLAC__StreamMetadata *block, const FLAC__byte *s) +{ + if(block->data.picture.description) { + block->length -= strlen((const char *)block->data.picture.description); + free(block->data.picture.description); + } + block->data.picture.description = (FLAC__byte*)strdup((const char *)s); + FLAC__ASSERT(block->data.picture.description); + block->length += strlen((const char *)block->data.picture.description); +} + +static void pi_set_data(FLAC__StreamMetadata *block, const FLAC__byte *data, FLAC__uint32 len) +{ + if(block->data.picture.data) { + block->length -= block->data.picture.data_length; + free(block->data.picture.data); + } + block->data.picture.data = (FLAC__byte*)strdup((const char *)data); + FLAC__ASSERT(block->data.picture.data); + block->data.picture.data_length = len; + block->length += len; +} FLAC__bool test_metadata_object() { - FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet; + FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet, *picture; FLAC__StreamMetadata_SeekPoint seekpoint_array[14]; FLAC__StreamMetadata_VorbisComment_Entry entry; FLAC__StreamMetadata_CueSheet_Index index; @@ -1996,5 +2029,253 @@ FLAC__bool test_metadata_object() printf("OK\n"); + printf("testing PICTURE\n"); + + printf("testing FLAC__metadata_object_new()... "); + block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE); + if(0 == block) { + printf("FAILED, returned NULL\n"); + return false; + } + expected_length = ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN + ) / 8; + if(block->length != expected_length) { + printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length); + return false; + } + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + picture = FLAC__metadata_object_clone(block); + if(0 == picture) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + pi_set_mime_type(picture, "image/png\t"); + printf("testing FLAC__metadata_object_picture_set_mime_type(copy)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png\t", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_mime_type(picture, "image/png"); + printf("testing FLAC__metadata_object_picture_set_mime_type(copy)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff"); + printf("testing FLAC__metadata_object_picture_set_description(copy)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION\xff", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION"); + printf("testing FLAC__metadata_object_picture_set_description(copy)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION", /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + + pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA")); + printf("testing FLAC__metadata_object_picture_set_data(copy)..."); + if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)"PNGDATA", strlen("PNGDATA"), /*copy=*/true)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + pi_set_mime_type(picture, "image/png\t"); + printf("testing FLAC__metadata_object_picture_set_mime_type(own)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png\t"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_mime_type(picture, "image/png"); + printf("testing FLAC__metadata_object_picture_set_mime_type(own)..."); + if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff"); + printf("testing FLAC__metadata_object_picture_set_description(own)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION\xff"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned true when expecting false\n"); + return false; + } + printf("returned false as expected, violation=\"%s\" OK\n", violation); + } + + pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION"); + printf("testing FLAC__metadata_object_picture_set_description(own)..."); + if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_picture_is_legal()..."); + { + const char *violation; + if(!FLAC__metadata_object_picture_is_legal(block, &violation)) { + printf("FAILED, returned false, violation=\"%s\"\n", violation); + return false; + } + printf("OK\n"); + } + + pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA")); + printf("testing FLAC__metadata_object_picture_set_data(own)..."); + if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)strdup("PNGDATA"), strlen("PNGDATA"), /*copy=*/false)) { + printf("FAILED, returned false\n"); + return false; + } + if(!mutils__compare_block(picture, block)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_clone()... "); + blockcopy = FLAC__metadata_object_clone(block); + if(0 == blockcopy) { + printf("FAILED, returned NULL\n"); + return false; + } + if(!mutils__compare_block(block, blockcopy)) + return false; + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(blockcopy); + printf("OK\n"); + + printf("testing FLAC__metadata_object_delete()... "); + FLAC__metadata_object_delete(picture); + FLAC__metadata_object_delete(block); + printf("OK\n"); + + return true; } diff --git a/src/test_libOggFLAC++/decoders.cpp b/src/test_libOggFLAC++/decoders.cpp index 0776d0bf..9a91ab9a 100644 --- a/src/test_libOggFLAC++/decoders.cpp +++ b/src/test_libOggFLAC++/decoders.cpp @@ -58,8 +58,8 @@ static const char * const LayerString[] = { "Filename" }; -static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static ::FLAC__StreamMetadata *expected_metadata_sequence_[8]; +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static ::FLAC__StreamMetadata *expected_metadata_sequence_[9]; static unsigned num_expected_; static const char *flacfilename_ = "metadata.ogg"; static off_t flacfilesize_; @@ -90,12 +90,12 @@ static FLAC__bool die_s_(const char *msg, const OggFLAC::Decoder::Stream *decode static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static bool generate_file_() @@ -109,6 +109,7 @@ static bool generate_file_() expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; /* WATCHOUT: the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */ @@ -723,6 +724,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -769,6 +771,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -798,6 +801,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -828,6 +832,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -864,6 +869,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) @@ -1006,6 +1012,7 @@ static bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!(layer < LAYER_FILE? dynamic_cast(decoder)->test_respond() : dynamic_cast(decoder)->test_respond())) diff --git a/src/test_libOggFLAC++/encoders.cpp b/src/test_libOggFLAC++/encoders.cpp index d2c7f69f..ce91c8ec 100644 --- a/src/test_libOggFLAC++/encoders.cpp +++ b/src/test_libOggFLAC++/encoders.cpp @@ -42,8 +42,8 @@ static const char * const LayerString[] = { "Filename" }; -static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &unknown_ }; +static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ }; static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]); static const char *flacfilename_ = "metadata.ogg"; @@ -77,12 +77,12 @@ static bool die_s_(const char *msg, const OggFLAC::Encoder::Stream *encoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } class StreamEncoder : public OggFLAC::Encoder::Stream { diff --git a/src/test_libOggFLAC/decoders.c b/src/test_libOggFLAC/decoders.c index f02abbc7..4eea85d0 100644 --- a/src/test_libOggFLAC/decoders.c +++ b/src/test_libOggFLAC/decoders.c @@ -59,8 +59,8 @@ typedef struct { FLAC__bool error_occurred; } StreamDecoderClientData; -static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static FLAC__StreamMetadata *expected_metadata_sequence_[8]; +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *expected_metadata_sequence_[9]; static unsigned num_expected_; static const char *flacfilename_ = "metadata.ogg"; static off_t flacfilesize_; @@ -91,12 +91,12 @@ static FLAC__bool die_s_(const char *msg, const OggFLAC__StreamDecoder *decoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static FLAC__bool generate_file_() @@ -110,6 +110,7 @@ static FLAC__bool generate_file_() expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &vorbiscomment_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; /* WATCHOUT: the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */ @@ -643,6 +644,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -683,6 +685,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -708,6 +711,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -734,6 +738,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application2_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -764,6 +769,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &padding_; expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) @@ -882,6 +888,7 @@ static FLAC__bool test_stream_decoder(Layer layer) expected_metadata_sequence_[num_expected_++] = &seektable_; expected_metadata_sequence_[num_expected_++] = &application1_; expected_metadata_sequence_[num_expected_++] = &cuesheet_; + expected_metadata_sequence_[num_expected_++] = &picture_; expected_metadata_sequence_[num_expected_++] = &unknown_; if(!stream_decoder_test_respond_(decoder, &decoder_client_data)) diff --git a/src/test_libOggFLAC/encoders.c b/src/test_libOggFLAC/encoders.c index 871ead4a..d7701a5d 100644 --- a/src/test_libOggFLAC/encoders.c +++ b/src/test_libOggFLAC/encoders.c @@ -45,8 +45,8 @@ static const char * const LayerString[] = { "Filename" }; -static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_; -static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &unknown_ }; +static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_; +static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ }; static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]); static const char *flacfilename_ = "metadata.ogg"; @@ -80,12 +80,12 @@ static FLAC__bool die_s_(const char *msg, const OggFLAC__StreamEncoder *encoder) static void init_metadata_blocks_() { - mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static void free_metadata_blocks_() { - mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_); + mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_); } static OggFLAC__StreamEncoderReadStatus stream_encoder_read_callback_(const OggFLAC__StreamEncoder *encoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) diff --git a/src/test_libs_common/metadata_utils.c b/src/test_libs_common/metadata_utils.c index 926a8943..1c88251a 100644 --- a/src/test_libs_common/metadata_utils.c +++ b/src/test_libs_common/metadata_utils.c @@ -289,6 +289,56 @@ FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueShe return true; } +FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy) +{ + size_t len, lencopy; + if(blockcopy->type != block->type) { + printf("FAILED, type mismatch, expected %u, got %u\n", (unsigned)block->type, (unsigned)blockcopy->type); + return false; + } + len = strlen(block->mime_type); + lencopy = strlen(blockcopy->mime_type); + if(lencopy != len) { + printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy); + return false; + } + if(strcmp(blockcopy->mime_type, block->mime_type)) { + printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type); + return false; + } + len = strlen((const char *)block->description); + lencopy = strlen((const char *)blockcopy->description); + if(lencopy != len) { + printf("FAILED, description length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy); + return false; + } + if(strcmp((const char *)blockcopy->description, (const char *)block->description)) { + printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description); + return false; + } + if(blockcopy->width != block->width) { + printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width); + return false; + } + if(blockcopy->height != block->height) { + printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height); + return false; + } + if(blockcopy->depth != block->depth) { + printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth); + return false; + } + if(blockcopy->data_length != block->data_length) { + printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length); + return false; + } + if(memcmp(blockcopy->data, block->data, block->data_length)) { + printf("FAILED, data mismatch\n"); + return false; + } + return true; +} + FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length) { if(0 == block->data || 0 == blockcopy->data) { @@ -341,10 +391,13 @@ FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__ return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment); case FLAC__METADATA_TYPE_CUESHEET: return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet); + case FLAC__METADATA_TYPE_PICTURE: + return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture); default: return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length); } } + static void *malloc_or_die_(size_t size) { void *x = malloc(size); @@ -365,6 +418,16 @@ static void *calloc_or_die_(size_t n, size_t size) return x; } +static char *strdup_or_die_(const char *s) +{ + char *x = strdup(s); + if(0 == x) { + fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s); + exit(1); + } + return x; +} + void mutils__init_metadata_blocks( FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata *padding, @@ -373,6 +436,7 @@ void mutils__init_metadata_blocks( FLAC__StreamMetadata *application2, FLAC__StreamMetadata *vorbiscomment, FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, FLAC__StreamMetadata *unknown ) { @@ -503,6 +567,31 @@ void mutils__init_metadata_blocks( cuesheet->data.cue_sheet.tracks[2].number = 170; cuesheet->data.cue_sheet.tracks[2].num_indices = 0; + picture->is_last = false; + picture->type = FLAC__METADATA_TYPE_PICTURE; + picture->length = + ( + FLAC__STREAM_METADATA_PICTURE_TYPE_LEN + + FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */ + FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN + + FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN + + FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN + + FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */ + ) / 8 + ; + picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER; + picture->data.picture.mime_type = strdup_or_die_("image/jpeg"); + picture->length += strlen(picture->data.picture.mime_type); + picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc"); + picture->length += strlen((const char *)picture->data.picture.description); + picture->data.picture.width = 300; + picture->data.picture.height = 300; + picture->data.picture.depth = 24; + picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA"); + picture->data.picture.data_length = strlen((const char *)picture->data.picture.data); + picture->length += picture->data.picture.data_length; + unknown->is_last = true; unknown->type = 126; unknown->length = 8; @@ -518,6 +607,7 @@ void mutils__free_metadata_blocks( FLAC__StreamMetadata *application2, FLAC__StreamMetadata *vorbiscomment, FLAC__StreamMetadata *cuesheet, + FLAC__StreamMetadata *picture, FLAC__StreamMetadata *unknown ) { @@ -530,5 +620,8 @@ void mutils__free_metadata_blocks( free(cuesheet->data.cue_sheet.tracks[0].indices); free(cuesheet->data.cue_sheet.tracks[1].indices); free(cuesheet->data.cue_sheet.tracks); + free(picture->data.picture.mime_type); + free(picture->data.picture.description); + free(picture->data.picture.data); free(unknown->data.unknown.data); }