add support for new PICTURE metadata block
authorJosh Coalson <jcoalson@users.sourceforce.net>
Sat, 23 Sep 2006 19:21:19 +0000 (19:21 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Sat, 23 Sep 2006 19:21:19 +0000 (19:21 +0000)
26 files changed:
include/FLAC++/metadata.h
include/FLAC/format.h
include/FLAC/metadata.h
include/test_libs_common/metadata_utils.h
src/libFLAC++/metadata.cpp
src/libFLAC/format.c
src/libFLAC/include/private/metadata.h
src/libFLAC/metadata_iterators.c
src/libFLAC/metadata_object.c
src/libFLAC/stream_decoder.c
src/libFLAC/stream_encoder.c
src/libFLAC/stream_encoder_framing.c
src/metaflac/operations.c
src/test_libFLAC++/decoders.cpp
src/test_libFLAC++/encoders.cpp
src/test_libFLAC++/metadata_manip.cpp
src/test_libFLAC++/metadata_object.cpp
src/test_libFLAC/decoders.c
src/test_libFLAC/encoders.c
src/test_libFLAC/metadata_manip.c
src/test_libFLAC/metadata_object.c
src/test_libOggFLAC++/decoders.cpp
src/test_libOggFLAC++/encoders.cpp
src/test_libOggFLAC/decoders.c
src/test_libOggFLAC/encoders.c
src/test_libs_common/metadata_utils.c

index 549546b..9641f91 100644 (file)
@@ -782,6 +782,80 @@ namespace FLAC {
                        FLAC__uint32 calculate_cddb_id() const;
                };
 
+               /** PICTURE metadata block.
+                *  See <A HREF="../format.html#metadata_block_picture">format specification</A>.
+                */
+               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().
+
+               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_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_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().
 
-               //! 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_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().
 
                /* \} */
 
index de9f6ea..6d09df6 100644 (file)
@@ -478,7 +478,10 @@ typedef enum {
        FLAC__METADATA_TYPE_CUESHEET = 5,
        /**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
 
-       FLAC__METADATA_TYPE_UNDEFINED = 6
+       FLAC__METADATA_TYPE_PICTURE = 6,
+       /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> 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
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * 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
index e5799de..68b2453 100644 (file)
@@ -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
index 3d7af19..882bf5b 100644 (file)
@@ -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
 );
 
index fc55703..30ca841 100644 (file)
@@ -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<const SeekTable *>(object);
                        const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
                        const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
+                       const Picture *picture = dynamic_cast<const Picture *>(object);
                        const Unknown *unknown = dynamic_cast<const Unknown *>(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 {
@@ -1015,6 +1021,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<char*>(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<FLAC__byte*>(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<FLAC__byte*>(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;
+               }
+
 
                // ============================================================
                //
index 939ec67..bb5feeb 100644 (file)
@@ -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
  */
index 277d989..7d4b5d8 100644 (file)
 
 #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
index 2ecb8b1..a1c699a 100644 (file)
@@ -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;
index 6846c3b..7efa2cf 100644 (file)
  *
  ***************************************************************************/
 
+/* 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_(&copy, 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);
+}
index d64280d..802d495 100644 (file)
@@ -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;
index be11e5e..407346f 100644 (file)
@@ -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;
index 87611b7..29bde9e 100644 (file)
@@ -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;
index a2a7d7f..aad872b 100644 (file)
@@ -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)
index 486af3b..976342d 100644 (file)
@@ -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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
index 24845b8..94124b9 100644 (file)
@@ -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 {
index a813813..cf27b9e 100644 (file)
@@ -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");
index 845fb1f..ccf41f5 100644 (file)
@@ -22,7 +22,7 @@
 #include <stdlib.h> /* for malloc() */
 #include <string.h> /* 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<FLAC::Metadata::Picture *>(clone_))
+               return die_("downcast is NULL");
+       if(*dynamic_cast<FLAC::Metadata::Picture *>(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;
index 1ac22d4..3765853 100644 (file)
@@ -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))
index 053695f..f3e9788 100644 (file)
@@ -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)
index 21a8fa4..81885fd 100644 (file)
@@ -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");
index 304df90..2939ed3 100644 (file)
@@ -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;
 }
index 0776d0b..9a91ab9 100644 (file)
@@ -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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(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<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
index d2c7f69..ce91c8e 100644 (file)
@@ -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 {
index f02abbc..4eea85d 100644 (file)
@@ -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))
index 871ead4..d7701a5 100644 (file)
@@ -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)
index 926a894..1c88251 100644 (file)
@@ -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);
 }