File indexing completed on 2024-05-26 04:57:59

0001 /**
0002  * \file frame.h
0003  * Generalized frame.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 25 Aug 2007
0008  *
0009  * Copyright (C) 2007-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #pragma once
0028 
0029 #include <QString>
0030 #include <QVariant>
0031 #include <QList>
0032 #include <QSet>
0033 #include <QHash>
0034 #include <set>
0035 #include "formatreplacer.h"
0036 #include "framenotice.h"
0037 #include "kid3api.h"
0038 
0039 /** Generalized frame. */
0040 class KID3_CORE_EXPORT Frame {
0041   Q_GADGET
0042   Q_ENUMS(Type)
0043   Q_ENUMS(FieldId)
0044   Q_ENUMS(TextEncoding)
0045   Q_ENUMS(PictureType)
0046   Q_ENUMS(TagVersion)
0047   Q_ENUMS(TagNumber)
0048 public:
0049   /** Generalized frame types. */
0050   enum Type {
0051     FT_Title,
0052     FT_FirstFrame = FT_Title,
0053     FT_Artist,
0054     FT_Album,
0055     FT_Comment,
0056     FT_Date,
0057     FT_Track,
0058     FT_Genre,
0059     FT_LastV1Frame = FT_Genre,
0060     FT_AlbumArtist,
0061     FT_Arranger,
0062     FT_Author,
0063     FT_Bpm,
0064     FT_CatalogNumber,
0065     FT_Compilation,
0066     FT_Composer,
0067     FT_Conductor,
0068     FT_Copyright,
0069     FT_Disc,
0070     FT_EncodedBy,
0071     FT_EncoderSettings,
0072     FT_EncodingTime,
0073     FT_Grouping,
0074     FT_InitialKey,
0075     FT_Isrc,
0076     FT_Language,
0077     FT_Lyricist,
0078     FT_Lyrics,
0079     FT_Media,
0080     FT_Mood,
0081     FT_OriginalAlbum,
0082     FT_OriginalArtist,
0083     FT_OriginalDate,
0084     FT_Description,
0085     FT_Performer,
0086     FT_Picture,
0087     FT_Publisher,
0088     FT_ReleaseCountry,
0089     FT_Remixer,
0090     FT_SortAlbum,
0091     FT_SortAlbumArtist,
0092     FT_SortArtist,
0093     FT_SortComposer,
0094     FT_SortName,
0095     FT_Subtitle,
0096     FT_Website,
0097     FT_WWWAudioFile,
0098     FT_WWWAudioSource,
0099     FT_ReleaseDate,
0100     FT_Rating,
0101     FT_Work,
0102     FT_Custom1,
0103     FT_Custom2,
0104     FT_Custom3,
0105     FT_Custom4,
0106     FT_Custom5,
0107     FT_Custom6,
0108     FT_Custom7,
0109     FT_Custom8,
0110     FT_LastFrame = FT_Custom8,
0111     FT_Other,
0112     FT_UnknownFrame
0113   };
0114 
0115   /** Maximum number of custom frame names. */
0116   static const int NUM_CUSTOM_FRAME_NAMES = FT_LastFrame - FT_Custom1 + 1;
0117 
0118   /**
0119    * Check if a frame type is a custom frame.
0120    * @param type frame type
0121    * @return true if @a type is a custom frame type.
0122    */
0123   static constexpr bool isCustomFrameType(Type type) {
0124     return type >= FT_Custom1 && type <= FT_LastFrame;
0125   }
0126 
0127   /**
0128    * Check if a frame type is a custom frame or FT_Other
0129    * @param type frame type
0130    * @return true if @a type is a custom frame type or FT_Other.
0131    */
0132   static constexpr bool isCustomFrameTypeOrOther(Type type) {
0133     return type >= FT_Custom1 && type <= FT_Other;
0134   }
0135 
0136   /**
0137    * Types of fields in a frame, must be the same as id3lib's ID3_FieldID.
0138    **/
0139   enum FieldId {
0140     ID_NoField,
0141     ID_TextEnc,
0142     ID_Text,
0143     ID_Url,
0144     ID_Data,
0145     ID_Description,
0146     ID_Owner,
0147     ID_Email,
0148     ID_Rating,
0149     ID_Filename,
0150     ID_Language,
0151     ID_PictureType,
0152     ID_ImageFormat,
0153     ID_MimeType,
0154     ID_Counter,
0155     ID_Id,
0156     ID_VolumeAdj,
0157     ID_NumBits,
0158     ID_VolChgRight,
0159     ID_VolChgLeft,
0160     ID_PeakVolRight,
0161     ID_PeakVolLeft,
0162     ID_TimestampFormat,
0163     ID_ContentType,
0164 
0165     // These are additional fields used by TagLib
0166     ID_Price,
0167     ID_Date,
0168     ID_Seller,
0169 
0170     // Additional field for METADATA_BLOCK_PICTURE
0171     ID_ImageProperties,
0172 
0173     // Type of subframe in CTOC and CHAP frames
0174     ID_Subframe
0175   };
0176 
0177   /** Text encoding for fields of type ID_TextEnc. */
0178   enum TextEncoding {
0179     TE_ISO8859_1 = 0,
0180     TE_UTF16 = 1,
0181     TE_UTF16BE = 2,
0182     TE_UTF8 = 3
0183   };
0184 
0185   /** Picture type, compatible with ID3v2 and FLAC. */
0186   enum PictureType {
0187     PT_Other = 0,
0188     PT_Png32Icon = 1,
0189     PT_OtherIcon = 2,
0190     PT_CoverFront = 3,
0191     PT_CoverBack = 4,
0192     PT_LeafletPage = 5,
0193     PT_Media = 6,
0194     PT_LeadArtist = 7,
0195     PT_Artist = 8,
0196     PT_Conductor = 9,
0197     PT_Band = 10,
0198     PT_Composer = 11,
0199     PT_Lyricist = 12,
0200     PT_RecordingLocation = 13,
0201     PT_DuringRecording = 14,
0202     PT_DuringPerformance = 15,
0203     PT_Video = 16,
0204     PT_Fish = 17,
0205     PT_Illustration = 18,
0206     PT_ArtistLogo = 19,
0207     PT_PublisherLogo = 20
0208   };
0209 
0210   /** Supported tags. */
0211   enum TagNumber {
0212     Tag_1,              /**< First tag */
0213     Tag_2,              /**< Second tag */
0214     Tag_3,              /**< Third tag */
0215     Tag_NumValues,      /**< Total number of tags */
0216 
0217     // Special uses of tags
0218     Tag_Id3v1 = Tag_1,  /**< Tag which can be ID3v1 tag */
0219     Tag_Id3v2 = Tag_2,  /**< Tag which can be ID3v2 tag */
0220     Tag_Picture = Tag_2 /**< Tag used for pictures */
0221   };
0222 
0223   /** Tag version contained in track data. */
0224   enum TagVersion {
0225     TagNone = 0, /**< Empty or imported and not from a tag */
0226     TagV1 = 1 << Tag_1,   /**< Tag 1 */
0227     TagV2 = 1 << Tag_2,   /**< Tag 2 */
0228     TagV3 = 1 << Tag_3,   /**< Tag 3 */
0229     /** Tag 1 and 2 or merged from tag 2 and tag 1 (where tag 2 is not set) */
0230     TagV2V1 = TagV1 | TagV2,
0231     TagVAll = TagV1 | TagV2 | TagV3 /**< All tags */
0232   };
0233 
0234   /**
0235    * Cast a mask of tag version bits to a TagVersion enum.
0236    * @param tagMask tag mask (bit 0 for tag 1, bit 1 for tag 2)
0237    * @return tag version mask.
0238    */
0239   static TagVersion tagVersionCast(int tagMask) {
0240     return static_cast<TagVersion>(tagMask & TagVAll);
0241   }
0242 
0243   /**
0244    * @brief Cast an integer to a tag number.
0245    * @param nr number
0246    * @return tag number, Tag_NumValues if invalid.
0247    */
0248   static TagNumber tagNumberCast(int nr) {
0249     return nr >= Tag_1 && nr < Tag_NumValues
0250         ? static_cast<TagNumber>(nr) : Tag_NumValues;
0251   }
0252 
0253   /**
0254    * Get a tag mask from a tag number.
0255    * @param tagNr tag number
0256    * @return tag version mask.
0257    */
0258   static TagVersion tagVersionFromNumber(TagNumber tagNr) {
0259     return tagNr < Tag_NumValues
0260         ? static_cast<TagVersion>(1 << tagNr) : TagNone;
0261   }
0262 
0263   /**
0264    * Get list of available tag versions with translated description.
0265    * @return tag version/description pairs.
0266    */
0267   static const QList<QPair<TagVersion, QString> > availableTagVersions();
0268 
0269   /**
0270    * Get highest priority tag number which is set in a tag mask.
0271    * @param tagMask tag mask with bits set for tags
0272    * @return tag number, Tag_NumValues if no tag is set.
0273    */
0274   static TagNumber tagNumberFromMask(TagVersion tagMask) {
0275     return (tagMask & TagV2)
0276         ? Tag_2 : (tagMask & TagV1)
0277           ? Tag_1 : (tagMask & TagV3)
0278             ? Tag_3 : Tag_NumValues;
0279   }
0280 
0281   /**
0282    * Get tag numbers which are set in a tag mask, ordered from highest
0283    * to lowest priority.
0284    * @param tagMask tag mask with bits set for tags
0285    * @return list of tag numbers.
0286    */
0287   static const QList<TagNumber> tagNumbersFromMask(TagVersion tagMask) {
0288     QList<TagNumber> result;
0289     if (tagMask & TagV2) result << Tag_2;
0290     if (tagMask & TagV1) result << Tag_1;
0291     if (tagMask & TagV3) result << Tag_3;
0292     return result;
0293   }
0294 
0295   /**
0296    * Get all tag numbers, ordered from highest to lowest priority.
0297    * @return list of tag numbers.
0298    */
0299   static const QList<TagNumber> allTagNumbers() {
0300     return tagNumbersFromMask(TagVAll);
0301   }
0302 
0303   /**
0304    * Get string representation for tag number.
0305    * @param tagNr tag number
0306    * @return "1" for Tag_1, "2" for Tag_2, ..., null if invalid.
0307    */
0308   static QString tagNumberToString(TagNumber tagNr);
0309 
0310   /**
0311    * Get tag number from string representation.
0312    * @param str string representation
0313    * @return Tag_1 for "1", Tag_2 for "2", ..., Tag_NumValues if invalid.
0314    */
0315   static TagNumber tagNumberFromString(const QString& str);
0316 
0317 /** for loop through all TagNumber values. */
0318 #define FOR_ALL_TAGS(variable) \
0319   for (Frame::TagNumber variable = Frame::Tag_1; \
0320        variable < Frame::Tag_NumValues; \
0321        variable = static_cast<Frame::TagNumber>(variable + 1))
0322 
0323 /** for loop through TagNumber values set in mask. */
0324 #define FOR_TAGS_IN_MASK(variable, mask) \
0325   FOR_ALL_TAGS(variable) \
0326     if ((mask) & (1 << variable))
0327 
0328   /** Field in frame. */
0329   struct KID3_CORE_EXPORT Field {
0330     /**
0331      * Equality operator.
0332      * @param rhs right hand side to compare
0333      * @return true if this == rhs.
0334      */
0335     bool operator==(const Field& rhs) const {
0336       return m_id == rhs.m_id && m_value == rhs.m_value;
0337     }
0338 
0339     int m_id;         /**< type of field. */
0340     QVariant m_value; /**< value of field. */
0341 
0342     /**
0343      * Get a translated string for a field ID.
0344      *
0345      * @param type field ID type
0346      *
0347      * @return field ID type, null string if unknown.
0348      */
0349     static QString getFieldIdName(FieldId type);
0350 
0351     /**
0352      * List of field ID strings, NULL terminated.
0353      */
0354     static const char* const* getFieldIdNames();
0355 
0356     /**
0357      * Get field ID from field name.
0358      * @param fieldName name of field, can be English or translated
0359      * @return field ID, ID_NoField if not found.
0360      */
0361     static FieldId getFieldId(const QString& fieldName);
0362 
0363     /**
0364      * Get a translated string for a text encoding.
0365      *
0366      * @param type text encoding type
0367      *
0368      * @return text encoding type, null string if unknown.
0369      */
0370     static QString getTextEncodingName(TextEncoding type);
0371 
0372     /**
0373      * List of text encoding strings, NULL terminated.
0374      */
0375     static const char* const* getTextEncodingNames();
0376 
0377     /**
0378      * Get a translated string for a timestamp format.
0379      *
0380      * @param type timestamp format type
0381      *
0382      * @return timestamp format type, null string if unknown.
0383      */
0384     static QString getTimestampFormatName(int type);
0385 
0386     /**
0387      * List of timestamp format strings, NULL terminated.
0388      */
0389     static const char* const* getTimestampFormatNames();
0390 
0391     /**
0392      * Get a translated string for a content type.
0393      *
0394      * @param type content type
0395      *
0396      * @return content type, null string if unknown.
0397      */
0398     static QString getContentTypeName(int type);
0399 
0400     /**
0401      * List of content type strings, NULL terminated.
0402      */
0403     static const char* const* getContentTypeNames();
0404 
0405     /**
0406      * Compare two field lists in a tolerant way.
0407      * This function can be used instead of the standard QList equality
0408      * operator if the field lists can be from different tag formats, which
0409      * may not all support the same field types.
0410      * @param fl1 first field list
0411      * @param fl2 second field list
0412      * @return true if they are similar enough.
0413      */
0414     static bool fuzzyCompareFieldLists(const QList<Field>& fl1,
0415                                        const QList<Field>& fl2);
0416 
0417   };
0418 
0419   /** list of fields. */
0420   typedef QList<Field> FieldList;
0421 
0422   /**
0423    * Type and name of frame.
0424    */
0425   class KID3_CORE_EXPORT ExtendedType {
0426   public:
0427     /**
0428      * Constructor.
0429      */
0430     ExtendedType() : m_type(FT_UnknownFrame) {}
0431 
0432     /**
0433      * Constructor.
0434      * @param type type
0435      * @param name internal name
0436      */
0437     ExtendedType(Type type, const QString& name) : m_type(type), m_name(name) {}
0438 
0439     /**
0440      * Constructor.
0441      * @param name internal name
0442      */
0443     explicit ExtendedType(const QString& name);
0444 
0445     /**
0446      * Constructor.
0447      * @param type type
0448      */
0449     explicit ExtendedType(Type type);
0450 
0451     /**
0452      * Get name of type.
0453      * @return name.
0454      */
0455     QString getName() const;
0456 
0457     /**
0458      * Get translated name of type.
0459      * @return name.
0460      */
0461     QString getTranslatedName() const;
0462 
0463     /**
0464      * Get internal name of type.
0465      * @return name.
0466      */
0467     QString getInternalName() const { return m_name; }
0468 
0469     /**
0470      * Less than operator.
0471      * @param rhs right hand side to compare
0472      * @return true if this < rhs.
0473      */
0474     bool operator<(const ExtendedType& rhs) const {
0475       return m_type < rhs.m_type ||
0476              (m_type == FT_Other && m_type == rhs.m_type && m_name < rhs.m_name);
0477     }
0478 
0479     /**
0480      * Equality operator.
0481      * @param rhs right hand side to compare
0482      * @return true if this == rhs.
0483      */
0484     bool operator==(const ExtendedType& rhs) const {
0485       return m_type == rhs.m_type &&
0486              (m_type != FT_Other || m_name == rhs.m_name);
0487     }
0488 
0489     /**
0490      * Get type
0491      * @return type.
0492      */
0493     Type getType() const { return m_type; }
0494 
0495   private:
0496     friend class Frame;
0497     Type m_type;
0498     QString m_name;
0499   };
0500 
0501 
0502   /**
0503    * Constructor.
0504    */
0505   Frame();
0506 
0507   /**
0508    * Constructor.
0509    * @param type  type
0510    * @param value value
0511    * @param name  internal name
0512    * @param index index inside tag, -1 if unknown
0513    */
0514   Frame(Type type, const QString& value, const QString& name, int index);
0515 
0516   /**
0517    * Constructor.
0518    * @param type  type and internal name
0519    * @param value value
0520    * @param index index inside tag, -1 if unknown
0521    */
0522   Frame(const ExtendedType& type, const QString& value, int index);
0523 
0524   /**
0525    * Less than operator.
0526    * Needed for sorting in multiset.
0527    * @param rhs right hand side to compare
0528    * @return true if this < rhs.
0529    */
0530   bool operator<(const Frame& rhs) const {
0531     return m_extendedType < rhs.m_extendedType;
0532   }
0533 
0534 #ifdef Q_CC_MSVC
0535   /**
0536    * Equality operator.
0537    * Needed when building with MSVC and BUILD_SHARED_LIBS.
0538    * @param rhs right hand side to compare
0539    * @return true if this == rhs.
0540    */
0541   bool operator==(const Frame& rhs) const {
0542     return m_extendedType == rhs.m_extendedType && m_value == rhs.m_value &&
0543       m_fieldList == rhs.m_fieldList;
0544   }
0545 #endif
0546 
0547   /**
0548    * Get type of frame.
0549    * @return type.
0550    */
0551   Type getType() const { return m_extendedType.m_type; }
0552 
0553   /**
0554    * Set type of frame.
0555    * @param type type of frame
0556    */
0557   void setType(Type type) { m_extendedType.m_type = type; }
0558 
0559   /**
0560    * Get type and name of frame.
0561    * @return extended type.
0562    */
0563   ExtendedType getExtendedType() const { return m_extendedType; }
0564 
0565   /**
0566    * Set type and name of frame.
0567    * @param type extended type of frame
0568    */
0569   void setExtendedType(const ExtendedType& type) { m_extendedType = type; }
0570 
0571   /**
0572    * Get index of frame.
0573    * @return index.
0574    */
0575   int getIndex() const { return m_index; }
0576 
0577   /**
0578    * Set index of frame.
0579    * @param index index of frame
0580    */
0581   void setIndex(int index) { m_index = index; }
0582 
0583   /**
0584    * Get name of frame.
0585    * @return name.
0586    */
0587   QString getName() const { return m_extendedType.getName(); }
0588 
0589   /**
0590    * Get internal name of frame.
0591    * @return name.
0592    */
0593   QString getInternalName() const { return m_extendedType.getInternalName(); }
0594 
0595   /**
0596    * Get value as string.
0597    * @return value.
0598    */
0599   QString getValue() const { return m_value; }
0600 
0601   /**
0602    * Set value as string.
0603    * @param value value as string
0604    */
0605   void setValue(const QString& value) { m_value = value; }
0606 
0607   /**
0608    * Get value as integer.
0609    * @return value.
0610    */
0611   int getValueAsNumber() const;
0612 
0613   /**
0614    * Set value as integer.
0615    * @param n value as number
0616    */
0617   void setValueAsNumber(int n);
0618 
0619   /**
0620    * Check if value is empty.
0621    * @return true if empty.
0622    */
0623   bool isEmpty() const { return m_value.isEmpty(); }
0624 
0625   /**
0626    * Check if the value of this frame is fuzzy equal to another frame.
0627    * Other than with strict equality, total values and some fields which are
0628    * not supported in all tag formats are ignored.
0629    * @param other frame to compare
0630    * @return true if more or less equal.
0631    */
0632   bool isFuzzyEqual(const Frame& other) const;
0633 
0634   /**
0635    * Check if frame is inactive.
0636    * @return true if inactive.
0637    */
0638   bool isInactive() const { return m_value.isNull(); }
0639 
0640   /**
0641    * Set frame inactive.
0642    */
0643   void setInactive() { m_value = QString(); }
0644 
0645   /**
0646    * Check if frame represents different frames in multiple files.
0647    * @return true if different.
0648    */
0649   bool isDifferent() const { return m_value == differentRepresentation(); }
0650 
0651   /**
0652    * Represents different frames in multiple files.
0653    */
0654   void setDifferent() { m_value = differentRepresentation(); }
0655 
0656   /**
0657    * Get warning notice if frame is marked.
0658    * @return notice.
0659    */
0660   FrameNotice getNotice() const { return m_marked; }
0661 
0662   /**
0663    * Check if frame is marked.
0664    * @return true if marked.
0665    */
0666   bool isMarked() const { return m_marked; }
0667 
0668   /**
0669    * Mark frame.
0670    * @param notice warning notice
0671    */
0672   void setMarked(FrameNotice notice) { m_marked = notice; }
0673 
0674   /**
0675    * Check if value is changed.
0676    * @return true if changed.
0677    */
0678   bool isValueChanged() const { return m_valueChanged; }
0679 
0680   /**
0681    * Mark the value as changed.
0682    * @param changed true to mark as changed
0683    */
0684   void setValueChanged(bool changed = true) { m_valueChanged = changed; }
0685 
0686   /**
0687    * Set value as string and mark it as changed if it is changed.
0688    * This method will avoid setting "different" representations.
0689    * @param value value as string
0690    */
0691   void setValueIfChanged(const QString& value);
0692 
0693   /**
0694    * Set the value from a field in the field list.
0695    */
0696   void setValueFromFieldList();
0697 
0698   /**
0699    * Read value text from file.
0700    * @param fileName name of data file
0701    * @return true if file read and value set.
0702    */
0703   bool setValueFromFile(const QString& fileName);
0704 
0705   /**
0706    * Save value text to a file.
0707    * @param fileName name of data file to save
0708    * @return true if saved.
0709    */
0710   bool writeValueToFile(const QString& fileName) const;
0711 
0712   /**
0713    * Set a field in the field list from the value.
0714    */
0715   void setFieldListFromValue();
0716 
0717   /**
0718    * Get fields in the frame.
0719    * @return field list.
0720    */
0721   const FieldList& getFieldList() const { return m_fieldList; }
0722 
0723   /**
0724    * Set fields in the frame.
0725    * @param fields field list
0726    */
0727   void setFieldList(const FieldList& fields) { m_fieldList = fields; }
0728 
0729   /**
0730    * Get fields in the frame.
0731    * @return reference to field list.
0732    */
0733   FieldList& fieldList() { return m_fieldList; }
0734 
0735   /**
0736    * Get the value of a field.
0737    *
0738    * @param id field ID
0739    *
0740    * @return field value, invalid if field not found.
0741    */
0742   QVariant getFieldValue(FieldId id) const;
0743 
0744   /**
0745    * Check if the fields in another frame are equal.
0746    *
0747    * @param other other frame
0748    *
0749    * @return true if equal.
0750    */
0751   bool isEqual(const Frame& other) const;
0752 
0753 #ifndef QT_NO_DEBUG
0754   /**
0755    * Dump contents of frame to debug console.
0756    */
0757   void dump() const;
0758 #endif
0759 
0760   /**
0761    * If a frame contains a string list as a value, it is stored in a single
0762    * string, separated by this special separator character.
0763    *
0764    * @return separator character.
0765    */
0766   static QLatin1Char stringListSeparator() { return QLatin1Char('|'); }
0767 
0768   /**
0769    * Split a string into a string list using stringListSeparator().
0770    * @param str string to split at stringListSeparator(), with support of
0771    *            '\' as an escape character.
0772    * @return list of strings split at separator character not prefixed with
0773    *         escape character.
0774    */
0775   static QStringList splitStringList(const QString& str);
0776 
0777   /**
0778    * Join a string list using stringListSeparator().
0779    * @param strs strings to join, if they contain the separator character,
0780    *             it will be escaped with '\'.
0781    * @return escaped strings joined by separator characters.
0782    */
0783   static QString joinStringList(const QStringList& strs);
0784 
0785   /**
0786    * Convert string (e.g. "track/total number of tracks") to number.
0787    *
0788    * @param str string to convert
0789    * @param ok  if not 0, true is returned here if conversion is ok
0790    *
0791    * @return number in string ignoring total after slash.
0792    */
0793   static int numberWithoutTotal(const QString& str, bool* ok = nullptr);
0794 
0795   /**
0796    * Get representation of different frames in multiple files.
0797    * @return "different" representation.
0798    */
0799   static QChar differentRepresentation() { return QChar(0x2260); }
0800 
0801   /**
0802    * Set value of a field.
0803    *
0804    * @param frame frame to set
0805    * @param id    field ID
0806    * @param value field value
0807    *
0808    * @return true if field found and set.
0809    */
0810   static bool setField(Frame& frame, FieldId id, const QVariant& value);
0811 
0812   /**
0813    * Set value of a field.
0814    *
0815    * @param frame frame to set
0816    * @param fieldName name of field, can be English or translated
0817    * @param value field value
0818    *
0819    * @return true if field found and set.
0820    */
0821   static bool setField(Frame& frame, const QString& fieldName,
0822                        const QVariant& value);
0823 
0824   /**
0825    * Get value of a field.
0826    *
0827    * @param frame frame to get
0828    * @param id    field ID
0829    *
0830    * @return field value, invalid if not found.
0831    */
0832   static QVariant getField(const Frame& frame, FieldId id);
0833 
0834   /**
0835    * Get value of a field.
0836    *
0837    * @param frame frame to get
0838    * @param fieldName name of field, can be English or translated
0839    *
0840    * @return field value, invalid if not found.
0841    */
0842   static QVariant getField(const Frame& frame, const QString& fieldName);
0843 
0844   /**
0845    * Get type of frame from English name.
0846    *
0847    * @param name name, spaces and case are ignored
0848    *
0849    * @return type.
0850    */
0851   static Type getTypeFromName(const QString& name);
0852 
0853   /**
0854    * Get a translated string for a frame type.
0855    *
0856    * @param type frame type
0857    *
0858    * @return frame type, null string if unknown.
0859    */
0860   static QString getFrameTypeName(Type type);
0861 
0862   /**
0863    * Get a display name for a frame name.
0864    * @param name frame name as returned by getName()
0865    * @return display name, transformed if necessary and translated.
0866    */
0867   static QString getDisplayName(const QString& name);
0868 
0869   /**
0870    * Get a map with display names as keys and frame names as values.
0871    * @param names frame names as returned by getName()
0872    * @return mapping of display names to frame names.
0873    */
0874   static QMap<QString, QString> getDisplayNameMap(const QStringList& names);
0875 
0876   /**
0877    * Get the frame name for a translated display name.
0878    * @param name translated display name
0879    * @return English frame name for @a name if found, else @a name.
0880    */
0881   static QString getNameForTranslatedFrameName(const QString& name);
0882 
0883   /**
0884    * Get internal frame ID of non unified frame for a translated display name.
0885    * @param name translated display name
0886    * @return internal frame ID, e.g. "SYLT", "keyw" of non unified frame,
0887    *         null if @a name is not the name of a supported non unified frame.
0888    */
0889   static QByteArray getFrameIdForTranslatedFrameName(const QString& name);
0890 
0891   /**
0892    * Get the internal name for a custom frame.
0893    * @param type custom frame type (FT_Custom1..FT_LastFrame)
0894    * @return custom frame name, empty if not used.
0895    */
0896   static QByteArray getNameForCustomFrame(Frame::Type type);
0897 
0898   /**
0899    * Get type of frame from custom frame name.
0900    * @param name custom frame name
0901    * @return type, FT_Other if no custom frame with @a name exists.
0902    */
0903   static Frame::Type getTypeFromCustomFrameName(const QByteArray& name);
0904 
0905   /**
0906    * Set the internal names for all custom frames.
0907    * The number of custom frames is limited. The internal vector will be resized
0908    * to fit the fixed number of custom frames.
0909    *
0910    * @param customNames names for the custom frame types (FT_Custom1...),
0911    * leading '!' will be removed from the names
0912    * @return true if custom frame names were changed.
0913    */
0914   static bool setNamesForCustomFrames(const QStringList& customNames);
0915 
0916   /**
0917    * Get the names for all custom frames.
0918    * The returned list does not contain empty names.
0919    *
0920    * @return names for the custom frame types (FT_Custom1, ...).
0921    */
0922   static QStringList getNamesForCustomFrames();
0923 
0924   /**
0925    * Convert frame index to a negative index used for a second collection.
0926    * This can be a collection containing picture frames, the mapping is
0927    * -1 -> -1, 0 -> -2, 1 -> -3, 2 -> -4, ...
0928    * @param index positive index, -1 is the unknown index
0929    * @return negative index <= -1.
0930    */
0931   static int toNegativeIndex(int index) { return -2 - index; }
0932 
0933   /**
0934    * Convert negative index used for a second collection to a frame index.
0935    * This can be used to get the index of a collection containing picture
0936    * frames, the mapping is
0937    * -1 -> -1, -2 -> 0, -3 -> 1, -4 -> 2, ...
0938    * @param negativeIndex negative index, -1 is the unknown index
0939    * @return frame negative >= -1.
0940    */
0941   static int fromNegativeIndex(int negativeIndex) { return -2 - negativeIndex; }
0942 
0943 private:
0944   friend class TaggedFile;
0945 
0946   ExtendedType m_extendedType;
0947   int m_index;
0948   QString m_value;
0949   FieldList m_fieldList;
0950   FrameNotice m_marked;
0951   bool m_valueChanged;
0952 };
0953 
0954 /** Filter to enable a subset of frame types. */
0955 class KID3_CORE_EXPORT FrameFilter {
0956 public:
0957   /**
0958    * Constructor.
0959    * All frames are disabled
0960    */
0961   FrameFilter();
0962 
0963   /**
0964    * Enable all frames.
0965    */
0966   void enableAll();
0967 
0968   /**
0969    * Check if all fields are true.
0970    *
0971    * @return true if all fields are true.
0972    */
0973   bool areAllEnabled() const;
0974 
0975   /**
0976    * Check if frame is enabled.
0977    *
0978    * @param type frame type
0979    * @param name frame name
0980    *
0981    * @return true if frame is enabled.
0982    */
0983   bool isEnabled(Frame::Type type, const QString& name = QString()) const;
0984 
0985   /**
0986    * Enable or disable frame.
0987    *
0988    * @param type frame type
0989    * @param name frame name
0990    * @param en true to enable
0991    */
0992   void enable(Frame::Type type, const QString& name = QString(), bool en = true);
0993 
0994 private:
0995   static const quint64 FTM_AllFrames = (1ULL << (Frame::FT_LastFrame + 1)) - 1;
0996   quint64 m_enabledFrames;
0997   std::set<QString> m_disabledOtherFrames;
0998 };
0999 
1000 /** Collection of frames. */
1001 class KID3_CORE_EXPORT FrameCollection : public std::multiset<Frame> {
1002 public:
1003   /**
1004    * Default value for quick access frames.
1005    */
1006   static constexpr quint64 DEFAULT_QUICK_ACCESS_FRAMES =
1007       (1ULL << Frame::FT_Title)   |
1008       (1ULL << Frame::FT_Artist)  |
1009       (1ULL << Frame::FT_Album)   |
1010       (1ULL << Frame::FT_Comment) |
1011       (1ULL << Frame::FT_Date)    |
1012       (1ULL << Frame::FT_Track)   |
1013       (1ULL << Frame::FT_Genre);
1014 
1015   /**
1016    * Set values which are different inactive.
1017    *
1018    * @param others frames to compare, will be modified!
1019    * @param differentValues optional storage for the different values
1020    */
1021   void filterDifferent(FrameCollection& others,
1022           QHash<Frame::ExtendedType, QSet<QString>>* differentValues = nullptr);
1023 
1024   /**
1025    * Add standard frames which are missing.
1026    */
1027   void addMissingStandardFrames();
1028 
1029   /**
1030    * Copy enabled frames.
1031    *
1032    * @param flt filter with enabled frames
1033    *
1034    * @return copy with enabled frames.
1035    */
1036   FrameCollection copyEnabledFrames(const FrameFilter& flt) const;
1037 
1038   /**
1039    * Remove all frames which are not enabled from the collection.
1040    *
1041    * @param flt filter with enabled frames
1042    */
1043   void removeDisabledFrames(const FrameFilter& flt);
1044 
1045   /**
1046    * Set the index of all frames to -1.
1047    */
1048   void setIndexesInvalid();
1049 
1050   /**
1051    * Copy frames which are empty or inactive from other frames.
1052    * This can be used to merge two frame collections.
1053    *
1054    * @param frames other frames
1055    */
1056   void merge(const FrameCollection& frames);
1057 
1058   /**
1059    * Check if the standard tags are empty or inactive.
1060    *
1061    * @return true if empty or inactive.
1062    */
1063   bool isEmptyOrInactive() const;
1064 
1065   /**
1066    * Find a frame by name.
1067    *
1068    * @param name  the name of the frame to find, if the exact name is not
1069    *              found, a case-insensitive search for the first name
1070    *              starting with this string is performed
1071    * @param index 0 for first frame with @a name, 1 for second, etc.
1072    *
1073    * @return iterator or end() if not found.
1074    */
1075   const_iterator findByName(const QString& name, int index = 0) const;
1076 
1077   /**
1078    * Find a frame by type or name.
1079    *
1080    * @param type  type and name of the frame to find, if the exact name is not
1081    *              found, a case-insensitive search for the first name
1082    *              starting with this string is performed
1083    * @param index 0 for first frame with @a type, 1 for second, etc.
1084    *
1085    * @return iterator or end() if not found.
1086    */
1087   const_iterator findByExtendedType(const Frame::ExtendedType& type,
1088                                     int index = 0) const;
1089 
1090   /**
1091    * Find a frame by index.
1092    *
1093    * @param index the index in the frame, see \ref Frame::getIndex()
1094    *
1095    * @return iterator or end() if not found.
1096    */
1097   const_iterator findByIndex(int index) const;
1098 
1099   /**
1100    * Get value by type.
1101    *
1102    * @param type type
1103    *
1104    * @return value, QString::null if not found.
1105    */
1106   QString getValue(Frame::Type type) const;
1107 
1108   /**
1109    * Get value by type and name.
1110    *
1111    * @param type  type and name of the frame to find, if the exact name is not
1112    *              found, a case-insensitive search for the first name
1113    *              starting with this string is performed
1114    *
1115    * @return value, QString::null if not found.
1116    */
1117   QString getValue(const Frame::ExtendedType& type) const;
1118 
1119   /**
1120    * Set value by type.
1121    *
1122    * @param type type
1123    * @param value value, nothing is done if QString::null
1124    */
1125   void setValue(Frame::Type type, const QString& value);
1126 
1127   /**
1128    * Set value by type and name.
1129    *
1130    * @param type  type and name of the frame to find, if the exact name is not
1131    *              found, a case-insensitive search for the first name
1132    *              starting with this string is performed
1133    * @param value value, nothing is done if QString::null
1134    */
1135   void setValue(const Frame::ExtendedType& type, const QString& value);
1136 
1137   /**
1138    * Get integer value by type.
1139    *
1140    * @param type type
1141    *
1142    * @return value, 0 if empty, -1 if not found.
1143    */
1144   int getIntValue(Frame::Type type) const;
1145 
1146   /**
1147    * Set integer value by type.
1148    *
1149    * @param type type
1150    * @param value value, 0 to set empty, nothing is done if -1
1151    */
1152   void setIntValue(Frame::Type type, int value);
1153 
1154   /**
1155    * Get artist.
1156    *
1157    * @return artist, QString::null if not found.
1158    */
1159   QString getArtist() const { return getValue(Frame::FT_Artist); }
1160 
1161   /**
1162    * Set artist.
1163    *
1164    * @param artist artist, nothing is done if QString::null
1165    */
1166   void setArtist(const QString& artist) { setValue(Frame::FT_Artist, artist); }
1167 
1168   /**
1169    * Get album.
1170    *
1171    * @return album, QString::null if not found.
1172    */
1173   QString getAlbum() const { return getValue(Frame::FT_Album); }
1174 
1175   /**
1176    * Set album.
1177    *
1178    * @param album album, nothing is done if QString::null
1179    */
1180   void setAlbum(const QString& album) { setValue(Frame::FT_Album, album); }
1181 
1182   /**
1183    * Get title.
1184    *
1185    * @return title, QString::null if not found.
1186    */
1187   QString getTitle() const { return getValue(Frame::FT_Title); }
1188 
1189   /**
1190    * Set title.
1191    *
1192    * @param title title, nothing is done if QString::null
1193    */
1194   void setTitle(const QString& title) { setValue(Frame::FT_Title, title); }
1195 
1196   /**
1197    * Get comment.
1198    *
1199    * @return comment, QString::null if not found.
1200    */
1201   QString getComment() const { return getValue(Frame::FT_Comment); }
1202 
1203   /**
1204    * Set comment.
1205    *
1206    * @param comment comment, nothing is done if QString::null
1207    */
1208   void setComment(const QString& comment) { setValue(Frame::FT_Comment, comment); }
1209 
1210   /**
1211    * Get genre.
1212    *
1213    * @return genre, QString::null if not found.
1214    */
1215   QString getGenre() const { return getValue(Frame::FT_Genre); }
1216 
1217   /**
1218    * Set genre.
1219    *
1220    * @param genre genre, nothing is done if QString::null
1221    */
1222   void setGenre(const QString& genre) { setValue(Frame::FT_Genre, genre); }
1223 
1224   /**
1225    * Get track.
1226    *
1227    * @return track, -1 if not found.
1228    */
1229   int getTrack() const { return getIntValue(Frame::FT_Track); }
1230 
1231   /**
1232    * Set track.
1233    *
1234    * @param track track, nothing is done if -1
1235    */
1236   void setTrack(int track) { setIntValue(Frame::FT_Track, track); }
1237 
1238   /**
1239    * Get year.
1240    *
1241    * @return year, -1 if not found.
1242    */
1243   int getYear() const { return getIntValue(Frame::FT_Date); }
1244 
1245   /**
1246    * Set year.
1247    *
1248    * @param year year, nothing is done if -1
1249    */
1250   void setYear(int year) { setIntValue(Frame::FT_Date, year); }
1251 
1252   /**
1253    * Compare the frames with another frame collection and mark the value as
1254    * changed on frames which are different.
1255    *
1256    * @param other other frame collection
1257    */
1258   void markChangedFrames(const FrameCollection& other);
1259 
1260 #ifndef QT_NO_DEBUG
1261   /**
1262    * Dump contents of frame collection to debug console.
1263    */
1264   void dump() const;
1265 #endif
1266 
1267   /**
1268    * Set mask containing the bits of all frame types which shall be used as
1269    * quick access frames.
1270    * @param mask bit mask with bits for quick access frames set, default is
1271    * DEFAULT_QUICK_ACCESS_FRAMES.
1272    */
1273   static void setQuickAccessFrames(quint64 mask) {
1274     s_quickAccessFrames = mask;
1275   }
1276 
1277   /**
1278    * Get mask containing the bits of all frame types which shall be used as
1279    * quick access frames.
1280    * @return mask bit mask with bits for quick access frames set.
1281    */
1282   static quint64 getQuickAccessFrames() {
1283     return s_quickAccessFrames;
1284   }
1285 
1286   /**
1287    * Create a frame collection from a list of subframe fields.
1288    *
1289    * The given subframe fields must start with a Frame::ID_Subframe field with
1290    * the frame name as its value, followed by the fields of the frame. More
1291    * subframes may follow.
1292    *
1293    * @param begin iterator to begin of subframes
1294    * @param end iterator after end of subframes
1295    *
1296    * @return frames constructed from subframe fields.
1297    */
1298   static FrameCollection fromSubframes(Frame::FieldList::const_iterator begin,
1299                                        Frame::FieldList::const_iterator end);
1300 
1301 private:
1302   /**
1303    * Search for a frame only by name.
1304    *
1305    * @param name the name of the frame to find, a case-insensitive search for
1306    *             the first name starting with this string is performed
1307    *
1308    * @return iterator or end() if not found.
1309    */
1310   const_iterator searchByName(const QString& name) const;
1311 
1312   /**
1313    * Bit mask containing the bits of all frame types which shall be used as
1314    * quick access frames.
1315    * This mask has to be handled like FrameFilter::m_enabledFrames.
1316    */
1317   static quint64 s_quickAccessFrames;
1318 };
1319 
1320 
1321 /**
1322  * Replaces frame format codes in a string.
1323  */
1324 class KID3_CORE_EXPORT FrameFormatReplacer : public FormatReplacer {
1325 public:
1326   /**
1327    * Constructor.
1328    *
1329    * @param frames frame collection
1330    * @param str    string with format codes
1331    */
1332   explicit FrameFormatReplacer(
1333     const FrameCollection& frames, const QString& str = QString());
1334 
1335   /**
1336    * Destructor.
1337    */
1338   ~FrameFormatReplacer() override = default;
1339 
1340   FrameFormatReplacer(const FrameFormatReplacer& other) = delete;
1341   FrameFormatReplacer &operator=(const FrameFormatReplacer& other) = delete;
1342 
1343   /**
1344    * Get help text for supported format codes.
1345    *
1346    * @param onlyRows if true only the tr elements are returned,
1347    *                 not the surrounding table
1348    *
1349    * @return help text.
1350    */
1351   static QString getToolTip(bool onlyRows = false);
1352 
1353 protected:
1354   /**
1355    * Replace a format code (one character %c or multiple characters %{chars}).
1356    * Supported format fields:
1357    * %s title (song)
1358    * %l album
1359    * %a artist
1360    * %c comment
1361    * %y year
1362    * %t track, two digits, i.e. leading zero if < 10
1363    * %T track, without leading zeroes
1364    * %g genre
1365    *
1366    * @param code format code
1367    *
1368    * @return replacement string,
1369    *         QString::null if code not found.
1370    */
1371   QString getReplacement(const QString& code) const override;
1372 
1373 private:
1374   const FrameCollection& m_frames;
1375 };
1376 
1377 /** Hash function to use Frame::ExtendedType as a QHash key. */
1378 inline uint qHash(const Frame::ExtendedType& key) {
1379   return qHash(key.getType()) ^ qHash(key.getInternalName());
1380 }