File indexing completed on 2024-05-12 04:55:48

0001 /**
0002  * \file taglibfile.h
0003  * Handling of tagged files using TagLib.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 12 Sep 2006
0008  *
0009  * Copyright (C) 2006-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 <QtGlobal>
0030 #include "taggedfile.h"
0031 #include "tagconfig.h"
0032 #include <taglib.h>
0033 #include <fileref.h>
0034 #include <id3v2frame.h>
0035 
0036 /** TagLib version in with 8 bits for major, minor and patch version. */
0037 #define TAGLIB_VERSION (((TAGLIB_MAJOR_VERSION) << 16) + \
0038                         ((TAGLIB_MINOR_VERSION) << 8) + (TAGLIB_PATCH_VERSION))
0039 
0040 class QTextCodec;
0041 class FileIOStream;
0042 
0043   namespace TagLib {
0044     namespace MP4 {
0045       class Tag;
0046     }
0047   }
0048 
0049 class TagLibFile;
0050 
0051 namespace TagLibFileInternal {
0052 
0053 void fixUpTagLibFrameValue(const TagLibFile* self,
0054                            Frame::Type frameType, QString& value);
0055 
0056 }
0057 
0058 /** List box item containing tagged file. */
0059 class TagLibFile : public TaggedFile {
0060 public:
0061   /**
0062    * Constructor.
0063    *
0064    * @param idx index in tagged file system model
0065    */
0066   explicit TagLibFile(const QPersistentModelIndex& idx);
0067 
0068   /**
0069    * Destructor.
0070    */
0071   ~TagLibFile() override;
0072 
0073   /**
0074    * Get key of tagged file format.
0075    * @return "TaglibMetadata".
0076    */
0077   QString taggedFileKey() const override;
0078 
0079   /**
0080    * Get features supported.
0081    * @return bit mask with Feature flags set.
0082    */
0083   int taggedFileFeatures() const override;
0084 
0085   /**
0086    * Get currently active tagged file features.
0087    * @return active tagged file features (TF_ID3v23, TF_ID3v24, or 0).
0088    * @see setActiveTaggedFileFeatures()
0089    */
0090   int activeTaggedFileFeatures() const override;
0091 
0092   /**
0093    * Activate some features provided by the tagged file.
0094    * TagLibFile provides the TF_ID3v23 and TF_ID3v24 features, which determine
0095    * the ID3v2 version used in writeTags() (the overload without id3v2Version).
0096    * If 0 is set, the default behavior applies, i.e. for new files,
0097    * TagConfig::id3v2Version() is used, else the existing version.
0098    *
0099    * @param features TF_ID3v23, TF_ID3v24, or 0
0100    */
0101   void setActiveTaggedFileFeatures(int features) override;
0102 
0103   /**
0104    * Read tags from file.
0105    *
0106    * @param force true to force reading even if tags were already read.
0107    */
0108   void readTags(bool force) override;
0109 
0110   /**
0111    * Write tags to file and rename it if necessary.
0112    *
0113    * @param force   true to force writing even if file was not changed.
0114    * @param renamed will be set to true if the file was renamed,
0115    *                i.e. the file name is no longer valid, else *renamed
0116    *                is left unchanged
0117    * @param preserve true to preserve file time stamps
0118    *
0119    * @return true if ok, false if the file could not be written or renamed.
0120    */
0121   bool writeTags(bool force, bool* renamed, bool preserve) override;
0122 
0123   /**
0124    * Free resources allocated when calling readTags().
0125    *
0126    * @param force true to force clearing even if the tags are modified
0127    */
0128   void clearTags(bool force) override;
0129 
0130   /**
0131    * Write tags to file and rename it if necessary.
0132    *
0133    * @param force    true to force writing even if file was not changed.
0134    * @param renamed  will be set to true if the file was renamed,
0135    *                 i.e. the file name is no longer valid, else *renamed
0136    *                 is left unchanged
0137    * @param preserve true to preserve file time stamps
0138    * @param id3v2Version ID3v2 version to use, 0 to use existing or preferred,
0139    *                     3 to force ID3v2.3.0, 4 to force ID3v2.4.0. Is ignored
0140    *                     if TagLib version is less than 1.8.0.
0141    *
0142    * @return true if ok, false if the file could not be written or renamed.
0143    */
0144   bool writeTags(bool force, bool* renamed, bool preserve, int id3v2Version);
0145 
0146   /**
0147    * Remove frames.
0148    *
0149    * @param tagNr tag number
0150    * @param flt filter specifying which frames to remove
0151    */
0152   void deleteFrames(Frame::TagNumber tagNr, const FrameFilter& flt) override;
0153 
0154   /**
0155    * Check if tag information has already been read.
0156    *
0157    * @return true if information is available,
0158    *         false if the tags have not been read yet, in which case
0159    *         hasTag() does not return meaningful information.
0160    */
0161   bool isTagInformationRead() const override;
0162 
0163   /**
0164    * Check if file has a tag.
0165    *
0166    * @param tagNr tag number
0167    * @return true if a V1 tag is available.
0168    * @see isTagInformationRead()
0169    */
0170   bool hasTag(Frame::TagNumber tagNr) const override;
0171 
0172   /**
0173    * Check if tags are supported by the format of this file.
0174    *
0175    * @param tagNr tag number
0176    * @return true.
0177    */
0178   bool isTagSupported(Frame::TagNumber tagNr) const override;
0179 
0180   /**
0181    * Get technical detail information.
0182    *
0183    * @param info the detail information is returned here
0184    */
0185   void getDetailInfo(DetailInfo& info) const override;
0186 
0187   /**
0188    * Get duration of file.
0189    *
0190    * @return duration in seconds,
0191    *         0 if unknown.
0192    */
0193   unsigned getDuration() const override;
0194 
0195   /**
0196    * Get file extension including the dot.
0197    *
0198    * @return file extension ".mp3".
0199    */
0200   QString getFileExtension() const override;
0201 
0202   /**
0203    * Get the format of tag.
0204    *
0205    * @param tagNr tag number
0206    * @return string describing format of tag 1,
0207    *         e.g. "ID3v1.1", "ID3v2.3", "Vorbis", "APE",
0208    *         QString::null if unknown.
0209    */
0210   QString getTagFormat(Frame::TagNumber tagNr) const override;
0211 
0212   /**
0213    * Get a specific frame from the tags.
0214    *
0215    * @param tagNr tag number
0216    * @param type  frame type
0217    * @param frame the frame is returned here
0218    *
0219    * @return true if ok.
0220    */
0221   bool getFrame(Frame::TagNumber tagNr, Frame::Type type, Frame& frame) const override;
0222 
0223   /**
0224    * Set a frame in the tags.
0225    *
0226    * @param tagNr tag number
0227    * @param frame frame to set
0228    *
0229    * @return true if ok.
0230    */
0231   bool setFrame(Frame::TagNumber tagNr, const Frame& frame) override;
0232 
0233   /**
0234    * Add a frame in the tags.
0235    *
0236    * @param tagNr tag number
0237    * @param frame frame to add, a field list may be added by this method
0238    *
0239    * @return true if ok.
0240    */
0241   bool addFrame(Frame::TagNumber tagNr, Frame& frame) override;
0242 
0243   /**
0244    * Delete a frame from the tags.
0245    *
0246    * @param tagNr tag number
0247    * @param frame frame to delete.
0248    *
0249    * @return true if ok.
0250    */
0251   bool deleteFrame(Frame::TagNumber tagNr, const Frame& frame) override;
0252 
0253   /**
0254    * Get all frames in tag.
0255    *
0256    * @param tagNr tag number
0257    * @param frames frame collection to set.
0258    */
0259   void getAllFrames(Frame::TagNumber tagNr, FrameCollection& frames) override;
0260 
0261   /**
0262    * Close file handle which is held open by the TagLib object.
0263    */
0264   void closeFileHandle() override;
0265 
0266   /**
0267    * Get a list of frame IDs which can be added.
0268    * @param tagNr tag number
0269    * @return list with frame IDs.
0270    */
0271   QStringList getFrameIds(Frame::TagNumber tagNr) const override;
0272 
0273   /**
0274    * Add a suitable field list for the frame if missing.
0275    * If a frame is created, its field list is empty. This method will create
0276    * a field list appropriate for the frame type and tagged file type if no
0277    * field list exists.
0278    * @param tagNr tag number
0279    * @param frame frame where field list is added
0280    */
0281   void addFieldList(Frame::TagNumber tagNr, Frame& frame) const override;
0282 
0283   /**
0284    * Static initialization.
0285    * Registers file types.
0286    */
0287   static void staticInit();
0288 
0289   /**
0290    * Get the default text encoding.
0291    * @return default text encoding.
0292    */
0293   static TagLib::String::Type getDefaultTextEncoding() { return s_defaultTextEncoding; }
0294 
0295   /**
0296    * Notify about configuration change.
0297    * This method shall be called when the configuration changes.
0298    */
0299   static void notifyConfigurationChange();
0300 
0301 private:
0302   friend void TagLibFileInternal::fixUpTagLibFrameValue(
0303       const TagLibFile* self, Frame::Type frameType, QString& value);
0304 
0305   TagLibFile(const TagLibFile&);
0306   TagLibFile& operator=(const TagLibFile&);
0307 
0308   /**
0309    * Close file handle.
0310    * TagLib keeps the file handle open until the FileRef is destroyed.
0311    * This causes problems when the operating system has a limited number of
0312    * open file handles. This method closes the file by assigning a new file
0313    * reference. Note that this will also invalidate the tag pointers.
0314    * The file is only closed if there are no unsaved tag changes or if the
0315    * @a force parameter is set.
0316    *
0317    * @param force true to close the file even if tags are changed
0318    */
0319   void closeFile(bool force = false);
0320 
0321   /**
0322    * Make sure that file is open.
0323    * This method should be called before accessing m_fileRef, m_tag.
0324    *
0325    * @param force true to force reopening of file even if it is already open
0326    */
0327   void makeFileOpen(bool force = false) const;
0328 
0329   /**
0330    * Create tag if it does not already exist so that it can be set.
0331    *
0332    * @param tagNr tag number
0333    * @return true if tag can be set.
0334    */
0335   bool makeTagSettable(Frame::TagNumber tagNr);
0336 
0337   /**
0338    * Cache technical detail information.
0339    */
0340   void readAudioProperties();
0341 
0342   /**
0343    * Get tracker name of a module file.
0344    *
0345    * @return tracker name, null if not found.
0346    */
0347   QString getTrackerName() const;
0348 
0349   /**
0350    * Set m_id3v2Version to 3 or 4 from tag if it exists, else to 0.
0351    * @param id3v2Tag ID3v2 tag
0352    */
0353   void setId3v2VersionFromTag(const TagLib::ID3v2::Tag* id3v2Tag);
0354 
0355   /**
0356    * Set m_id3v2Version from given value (3 or 4) or use default from
0357    * configuration if not already set to 3 or 4.
0358    * @param id3v2Version 3 or 4 to force version, 0 to use existing version
0359    * or default
0360    */
0361   void setId3v2VersionOrDefault(int id3v2Version);
0362 
0363   /**
0364    * Get internal name of a Vorbis frame.
0365    *
0366    * @param frame frame
0367    *
0368    * @return Vorbis key.
0369    */
0370   QString getVorbisName(const Frame& frame) const;
0371 
0372   /**
0373    * Set a frame in an MP4 tag.
0374    * @param frame frame to set
0375    * @param mp4Tag MP4 tag
0376    */
0377   void setMp4Frame(const Frame& frame, TagLib::MP4::Tag* mp4Tag);
0378 
0379   /**
0380    * Get the format of a tag.
0381    *
0382    * @param tag tag, 0 if no tag available
0383    * @param type the tag type is returned here
0384    *
0385    * @return string describing format of tag,
0386    *         e.g. "ID3v1.1", "ID3v2.3", "Vorbis", "APE",
0387    *         QString::null if unknown.
0388    */
0389   static QString getTagFormat(const TagLib::Tag* tag, TagType& type);
0390 
0391   /**
0392    * Set the encoding to be used for tag 1.
0393    *
0394    * @param name of encoding, default is ISO 8859-1
0395    */
0396   static void setTextEncodingV1(const QString& name);
0397 
0398   /**
0399    * Set the default text encoding.
0400    *
0401    * @param textEnc default text encoding
0402    */
0403   static void setDefaultTextEncoding(TagConfig::TextEncoding textEnc);
0404 
0405   static const int NUM_TAGS = 3;
0406 
0407   bool m_tagInformationRead;
0408   bool m_hasTag[NUM_TAGS];
0409   bool m_isTagSupported[NUM_TAGS];
0410 
0411   bool m_fileRead;           /**< true if file has been read */
0412 
0413   TagLib::FileRef m_fileRef; /**< file reference */
0414   TagLib::Tag* m_tag[NUM_TAGS];
0415   FileIOStream* m_stream;
0416   int m_id3v2Version;        /**< 3 for ID3v2.3, 4 for ID3v2.4, 0 if none */
0417   int m_activatedFeatures;   /**< TF_ID3v23, TF_ID3v24, or 0 */
0418 
0419   /* Cached information updated in readTags() */
0420   unsigned m_duration;
0421   TagType m_tagType[NUM_TAGS];
0422   QString m_tagFormat[NUM_TAGS];
0423   QString m_fileExtension;
0424   DetailInfo m_detailInfo;
0425 
0426   class Pictures : public QList<Frame> {
0427   public:
0428     Pictures() : m_read(false) {}
0429     bool isRead() const { return m_read; }
0430     void setRead(bool read) { m_read = read; }
0431 
0432   private:
0433     bool m_read;
0434   };
0435 
0436   Pictures m_pictures;
0437 
0438   /** default text encoding */
0439   static TagLib::String::Type s_defaultTextEncoding;
0440 };