"Fossies" - the Fresh Open Source Software Archive

Member "MP3Diags-unstable-1.5.01/src/Notes.cpp" (9 Jul 2017, 17298 Bytes) of package /linux/privat/MP3Diags-unstable-1.5.01.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Notes.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.3.04_vs_1.5.01.

    1 /***************************************************************************
    2  *   MP3 Diags - diagnosis, repairs and tag editing for MP3 files          *
    3  *                                                                         *
    4  *   Copyright (C) 2009 by Marian Ciobanu                                  *
    5  *   ciobi@inbox.com                                                       *
    6  *                                                                         *
    7  *   This program is free software; you can redistribute it and/or modify  *
    8  *   it under the terms of the GNU General Public License version 2 as     *
    9  *   published by the Free Software Foundation.                            *
   10  *                                                                         *
   11  *   This program is distributed in the hope that it will be useful,       *
   12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
   13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
   14  *   GNU General Public License for more details.                          *
   15  *                                                                         *
   16  *   You should have received a copy of the GNU General Public License     *
   17  *   along with this program; if not, write to the                         *
   18  *   Free Software Foundation, Inc.,                                       *
   19  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
   20  ***************************************************************************/
   21 
   22 
   23 #include  <sstream>
   24 #include  <vector>
   25 #include  <algorithm>
   26 
   27 #include  "Notes.h"
   28 
   29 #include  "Helpers.h"
   30 #include  "CbException.h"
   31 
   32 using namespace std;
   33 using namespace pearl;
   34 
   35 
   36 /*static*/ Notes::NoteSet Notes::s_spAllNotes;
   37 
   38 /*static*/ vector<vector<const Note*> > Notes::s_vpNotesByCateg (static_cast<int>(Note::CATEG_CNT));
   39 /*static*/ vector<const Note*> Notes::s_vpAllNotes;
   40 
   41 
   42 static const char* s_szPlaceholderDescr (QT_TRANSLATE_NOOP("Notes", "<Placeholder for a note that can no longer be found, most likely as a result of a software upgrade. You should rescan the file.>"));
   43 
   44 // to be used by serialization: if a description is no longer found, the note gets replace with a default, "missing", one
   45 /*static*/ const Note* Notes::getMissingNote()
   46 {
   47     static Note::SharedData sd (Note::SUPPORT, Note::CUSTOM, s_szPlaceholderDescr, false); // !!! m_nLabelIndex is initialized to -1, which will result in an empty label;
   48     static Note note (sd, -1);
   49     return &note;
   50 }
   51 
   52 
   53 /*static*/ const Note* Notes::getMaster(const Note* p)
   54 {
   55     const Note* q (getNote(p->getDescription()));
   56     if (0 != q) { return q; }
   57 
   58     q = getMissingNote();
   59     CB_ASSERT (p->m_pSharedData == q->m_pSharedData);
   60     return q;
   61 }
   62 
   63 
   64 
   65 // destoys the pointers added by addToDestroyList(); to be called after loading is complete;
   66 /*static*/void Notes::clearDestroyList()
   67 {
   68     clearPtrContainer(s_spDestroyList);
   69 }
   70 
   71 /*static*/ set<Note::SharedData*> Notes::s_spDestroyList;
   72 
   73 /*static*/ void Notes::addNote(Note* p)
   74 {
   75     CB_ASSERT (0 == s_spAllNotes.count(p));
   76     int nCateg (p->getCategory());
   77     CB_ASSERT (0 <= nCateg && nCateg < Note::CATEG_CNT);
   78     p->m_pSharedData->m_nLabelIndex = cSize(s_vpNotesByCateg[nCateg]);
   79     s_vpNotesByCateg[nCateg].push_back(p);
   80 
   81     p->m_pSharedData->m_nNoteId = cSize(s_vpAllNotes);
   82     s_vpAllNotes.push_back(p);
   83 
   84     s_spAllNotes.insert(p);
   85 }
   86 
   87 
   88 //ttt2 if one of the addNote() is missing, the program just crashes instead of showing an assertion; the reason seems to be that the UI will ask for the color of an invalid note;
   89 /*static*/ void Notes::initVec()
   90 {
   91     static bool s_bInit (false);
   92     if (s_bInit) { return; }
   93     s_bInit = true;
   94 
   95     // audio
   96     addNote(&Notes::twoAudio()); // e
   97     addNote(&Notes::lowQualAudio()); // w
   98     addNote(&Notes::noAudio()); // e
   99     addNote(&Notes::vbrUsedForNonMpg1L3()); // w
  100     addNote(&Notes::incompleteFrameInAudio()); // e
  101     addNote(&Notes::validFrameDiffVer()); // e
  102     addNote(&Notes::validFrameDiffLayer()); // e
  103     addNote(&Notes::validFrameDiffMode()); // e
  104     addNote(&Notes::validFrameDiffFreq()); // e
  105     addNote(&Notes::validFrameDiffCrc()); // e
  106     addNote(&Notes::audioTooShort()); // e
  107     addNote(&Notes::diffBitrateInFirstFrame()); // e
  108     addNote(&Notes::noMp3Gain()); // w
  109     addNote(&Notes::untestedEncoding()); // s
  110 
  111     // xing
  112     addNote(&Notes::twoLame()); // e
  113     addNote(&Notes::xingAddedByMp3Fixer()); // e
  114     addNote(&Notes::xingFrameCountMismatch()); // e
  115     addNote(&Notes::twoXing()); // e
  116     addNote(&Notes::xingNotBeforeAudio()); // e
  117     addNote(&Notes::incompatXing()); // e
  118     addNote(&Notes::missingXing()); // w
  119     addNote(&Notes::xingFrameInCount()); // w
  120 
  121     // vbri
  122     addNote(&Notes::twoVbri());
  123     addNote(&Notes::vbriFound());
  124     addNote(&Notes::foundVbriAndXing()); // w
  125 
  126     // id3 v2
  127     addNote(&Notes::id3v2FrameTooShort()); // e
  128     addNote(&Notes::id3v2InvalidName()); // e
  129     addNote(&Notes::id3v2IncorrectFlg1()); // w
  130     addNote(&Notes::id3v2IncorrectFlg2()); // w
  131     addNote(&Notes::id3v2TextError()); // e
  132     addNote(&Notes::id3v2HasLatin1NonAscii()); // w
  133     addNote(&Notes::id3v2EmptyTcon()); // w
  134     addNote(&Notes::id3v2MultipleFramesWithSameName()); // w
  135     addNote(&Notes::id3v2PaddingTooLarge()); // w
  136     addNote(&Notes::id3v2UnsuppVer()); // s
  137     addNote(&Notes::id3v2UnsuppFlag()); // s
  138     addNote(&Notes::id3v2UnsuppFlags1()); // s
  139     addNote(&Notes::id3v2UnsuppFlags2()); // s
  140     addNote(&Notes::id3v2DuplicatePopm()); //s
  141     addNote(&Notes::id3v2EmptyTag()); //w // ttt2 perhaps move up in a new release, so it isn't shown after support notes; better: assign ids to support notes at the end of the alphabet;
  142     addNote(&Notes::id3v2EmptyTextFrame()); //w // ttt2 perhaps move up in a new release, so it isn't shown after support notes; better: assign ids to support notes at the end of the alphabet;
  143 
  144     // apic
  145     addNote(&Notes::id3v2NoApic()); // w
  146     addNote(&Notes::id3v2CouldntLoadPic()); // w
  147     //addNote(&Notes::id3v2LinkNotSupported()); // s
  148     addNote(&Notes::id3v2NotCoverPicture()); // w
  149     addNote(&Notes::id3v2ErrorLoadingApic()); // w
  150     addNote(&Notes::id3v2ErrorLoadingApicTooShort()); // w
  151     addNote(&Notes::id3v2DuplicatePic()); // e
  152     addNote(&Notes::id3v2MultipleApic()); // w
  153     addNote(&Notes::id3v2UnsupApicTextEnc()); //s
  154     addNote(&Notes::id3v2LinkInApic()); //s
  155     addNote(&Notes::id3v2PictDescrIgnored()); //s
  156     addNote(&Notes::id3v2ProgressiveJpeg()); //w
  157 
  158     // id3 v2.3.0
  159     addNote(&Notes::noId3V230()); // w
  160     addNote(&Notes::twoId3V230()); // e
  161     addNote(&Notes::bothId3V230_V240()); // w
  162     addNote(&Notes::id3v230AfterAudio()); // e
  163     addNote(&Notes::id3v230UsesUtf8()); // w
  164     addNote(&Notes::id3v230UnsuppText()); // s
  165     addNote(&Notes::id3v230CantReadFrame()); // e
  166 
  167     // id3 v2.4.0
  168     addNote(&Notes::twoId3V240()); // e
  169     addNote(&Notes::id3v240CantReadFrame()); // e
  170     addNote(&Notes::id3v240IncorrectSynch()); // w
  171     addNote(&Notes::id3v240DeprTyerAndTdrc()); // w
  172     addNote(&Notes::id3v240DeprTyer()); // w
  173     addNote(&Notes::id3v240DeprTdatAndTdrc()); // w
  174     addNote(&Notes::id3v240IncorrectDli()); // w
  175     addNote(&Notes::id3v240IncorrectFrameSynch()); // w
  176     addNote(&Notes::id3v240DeprTdat()); // w
  177     addNote(&Notes::id3v240UnsuppText()); // s
  178 
  179     // id3 v1
  180     addNote(&Notes::onlyId3V1()); // w
  181     addNote(&Notes::id3v1BeforeAudio()); // w
  182     addNote(&Notes::id3v1TooShort()); // e
  183     addNote(&Notes::twoId3V1()); // e
  184     //addNote(&Notes::zeroInId3V1());
  185     addNote(&Notes::mixedPaddingInId3V1()); // w
  186     addNote(&Notes::mixedFieldPaddingInId3V1()); // w
  187     addNote(&Notes::id3v1InvalidName()); // e
  188     addNote(&Notes::id3v1InvalidArtist()); // e
  189     addNote(&Notes::id3v1InvalidAlbum()); // e
  190     addNote(&Notes::id3v1InvalidYear()); // e
  191     addNote(&Notes::id3v1InvalidComment()); // e
  192 
  193     // broken
  194     addNote(&Notes::brokenAtTheEnd()); // e
  195     addNote(&Notes::brokenInTheMiddle()); // e
  196 
  197     // trunc
  198     addNote(&Notes::truncAudioWithWholeFile()); // e
  199     addNote(&Notes::truncAudio()); // e
  200 
  201     // unknown
  202     addNote(&Notes::unknTooShort()); // w
  203     addNote(&Notes::unknownAtTheEnd()); // e
  204     addNote(&Notes::unknownInTheMiddle()); // e
  205     addNote(&Notes::foundNull()); // w
  206 
  207     // lyrics
  208     addNote(&Notes::lyrTooShort()); // e
  209     addNote(&Notes::twoLyr()); // s
  210     addNote(&Notes::invalidLyr()); // e
  211     addNote(&Notes::duplicateFields()); // s
  212     //addNote(&Notes::imgInLyrics()); // s
  213     addNote(&Notes::infInLyrics()); // s
  214 
  215     // ape
  216     addNote(&Notes::apeItemTooShort()); // e
  217     addNote(&Notes::apeItemTooBig()); // e
  218     addNote(&Notes::apeMissingTerminator()); // e
  219     addNote(&Notes::apeFoundFooter()); // e
  220     addNote(&Notes::apeTooShort()); // e
  221     addNote(&Notes::apeFoundHeader()); // e
  222     addNote(&Notes::apeHdrFtMismatch()); // e
  223     addNote(&Notes::twoApe()); // s
  224     addNote(&Notes::apeFlagsNotSupported()); // s
  225     addNote(&Notes::apeUnsupported()); // s
  226 
  227     // misc
  228     addNote(&Notes::fileWasChanged()); // w
  229     addNote(&Notes::noInfoTag()); // w
  230     addNote(&Notes::tooManyTraceNotes()); // w
  231     addNote(&Notes::tooManyNotes()); // w
  232     addNote(&Notes::tooManyStreams()); // w
  233     addNote(&Notes::unsupportedFound()); // w
  234     addNote(&Notes::rescanningNeeded()); // w
  235     addNote(&Notes::failedToRead()); // e
  236 
  237     {
  238         CB_ASSERT (Note::CUSTOM == Note::CATEG_CNT - 1);
  239 
  240         for (int i = 1; i < cSize(s_vpAllNotes); ++i)
  241         {
  242             const Note* p1 (s_vpAllNotes[i - 1]);
  243             const Note* p2 (s_vpAllNotes[i]);
  244             CB_ASSERT (p1->getCategory() <= p2->getCategory());
  245             CB_ASSERT (p1->getNoteId() <= p2->getNoteId());
  246         }
  247     }
  248 //    qDebug("%d errors, %d warnings, %d support notes", cSize(s_vpErrNotes), cSize(s_vpWarnNotes), cSize(s_vpSuppNotes));
  249 }
  250 
  251 
  252 //ttt2 perhaps warn that file has multiple pictures, so will get deleted; probably like unsupportedFound; anyway after deciding on some standard way to tell the user about features and limitations; a class is probably a better answer than the current approach of "told/warned/..." settings scattered over the config file; should not show the messages too soon one after another, should get rid of all the static variables, ...
  253 
  254 /*static*/ const Note* Notes::getNote(const std::string& strDescr)
  255 {
  256     initVec();
  257 
  258     Note::SharedData d (strDescr.c_str(), false); // !!! sev doesn't matter
  259     Note n (d);
  260     NoteSet::iterator it;
  261     it = (s_spAllNotes.find(&n));
  262     if (s_spAllNotes.end() == it)
  263     {
  264         if (strDescr == s_szPlaceholderDescr)
  265         {
  266             return getMissingNote();
  267         }
  268 
  269         return 0;
  270     }
  271     return *it;
  272 }
  273 
  274 
  275 /*static*/ const Note* Notes::getNote(int n) // returns 0 if n is out of range
  276 {
  277     initVec();
  278 
  279     if (n < 0 || n >= cSize(s_vpAllNotes)) { return 0; }
  280     return s_vpAllNotes[n];
  281 }
  282 
  283 
  284 /*static*/ const std::vector<const Note*>& Notes::getAllNotes()
  285 {
  286     initVec();
  287     return s_vpAllNotes;
  288 }
  289 
  290 
  291 /*static*/ const vector<int>& Notes::getDefaultIgnoredNoteIds()
  292 {
  293     initVec();
  294 
  295     static bool bInit (false);
  296     static vector<int> v;
  297     if (!bInit)
  298     {
  299         bInit = true;
  300         //v.push_back(zeroInId3V1().getNoteId());
  301         v.push_back(mixedPaddingInId3V1().getNoteId());
  302         v.push_back(mixedFieldPaddingInId3V1().getNoteId());
  303         //v.push_back(lyricsNotSupported().getNoteId());
  304         v.push_back(tooManyTraceNotes().getNoteId());
  305         v.push_back(tooManyNotes().getNoteId());
  306     }
  307 
  308     return v;
  309 }
  310 
  311 
  312 //============================================================================================================
  313 //============================================================================================================
  314 //============================================================================================================
  315 
  316 
  317 
  318 //ttt2 maybe new type for Note::Severity: BROKEN, which is basically the same as ERR, but shown in UI with a different color
  319 
  320 //ttt2 maybe new type for Note::Severity: INFO, to be used for searches; normally they are "ignored", but can be used to search for, e.g., "CBR files"
  321 
  322 //======================================================================================================
  323 //======================================================================================================
  324 
  325 
  326 Note::Note(const Note& note, std::streampos pos, const std::string& strDetail /* = ""*/) :
  327         m_pSharedData(note.m_pSharedData),
  328         m_pos(pos),
  329         m_strDetail(strDetail)
  330 {
  331     //char a [30]; sprintf(a, "1 Note::Note() %p", this); TRACER(a);
  332 }
  333 
  334 Note::Note(SharedData& sharedData, std::streampos pos, const std::string& strDetail /* = ""*/) :
  335         m_pSharedData(&sharedData),
  336         m_pos(pos),
  337         m_strDetail(strDetail)
  338 {
  339     //char a [30]; sprintf(a, "2 Note::Note() %p", this); TRACER(a);
  340 }
  341 
  342 Note::Note(SharedData& sharedData) :
  343         m_pSharedData(&sharedData),
  344         m_pos(-1)
  345 {
  346     //char a [30]; sprintf(a, "3 Note::Note() %p", this); TRACER(a);
  347 }
  348 
  349 Note::Note()
  350 {
  351     //char a [30]; sprintf(a, "4 Note::Note() %p", this); TRACER(a);
  352 }
  353 
  354 Note::~Note()
  355 {
  356     //qDebug("destroyed note at %p", this);
  357     //char a [30]; sprintf(a, "Note::~Note() %p", this); TRACER(a);
  358 }
  359 
  360 //ttt2 maybe get rid of some/most ser-specific constructors, revert const changes, and call real constructors from the parent (adding serialization as member functions required switching from references to pointers and from const to non-const data members)
  361 
  362 
  363 
  364 bool Note::operator==(const Note& other) const
  365 {
  366     return
  367         m_pSharedData == other.m_pSharedData &&
  368         m_pos == other.m_pos &&
  369         m_strDetail == other.m_strDetail;
  370 }
  371 
  372 // returns an empty string for an invalid position (i.e. one initialized from -1)
  373 string Note::getPosHex() const
  374 {
  375     if (-1 == m_pos) { return ""; }
  376     ostringstream s;
  377     s << "0x" << hex << m_pos;
  378     return s.str();
  379 }
  380 
  381 
  382 /*static*/ const std::string Note::severityToString(Severity s) {
  383     if (s == ERR) return convStr(Notes::tr("ERROR"));
  384     if (s == WARNING) return convStr(Notes::tr("WARNING"));
  385     if (s == SUPPORT) return convStr(Notes::tr("SUPPORT"));
  386     CB_THROW1(CbInvalidArgument, boost::lexical_cast<std::string>((int)s));
  387 }
  388 
  389 
  390 
  391 //======================================================================================================
  392 //======================================================================================================
  393 
  394 
  395 NoteColl::~NoteColl()
  396 {
  397     pearl::clearPtrContainer(m_vpNotes);
  398 }
  399 
  400 
  401 
  402 void NoteColl::add(Note* pNote)
  403 {
  404     if (Note::TRACE == pNote->getSeverity())
  405     {
  406         if (m_nMaxTrace == m_nTraceCount)
  407         {
  408             m_vpNotes.push_back(new Note(Notes::tooManyTraceNotes(), -1));
  409             ++m_nTraceCount;
  410         }
  411 
  412         if (m_nTraceCount > m_nMaxTrace)
  413         {
  414             delete pNote;
  415             return;
  416         }
  417 
  418         ++m_nTraceCount;
  419     }
  420     else
  421     {
  422         if (200 == m_nCount)
  423         {
  424             m_vpNotes.push_back(new Note(Notes::tooManyNotes(), -1));
  425             ++m_nCount;
  426         }
  427 
  428         if (m_nCount > 200)
  429         {
  430             delete pNote;
  431             return;
  432         }
  433 
  434         ++m_nCount;
  435     }
  436 
  437 
  438     trace(pNote->getPosHex() + string(": ") + pNote->getDescription());
  439     if (!pNote->getDetail().empty())
  440     {
  441         trace(pNote->getDetail()); // ttt2 perhaps log the description only if the detail is empty (so strDetail would be expected to hold all the info in strDescription)
  442     }
  443 
  444     // try to avoid adding duplicates by comparing pNote to the last 10 notes
  445     for (int i = 10, n = cSize(m_vpNotes) - 1; i > 0 && n >= 0; --i, --n)
  446     {
  447         const Note* pLast (m_vpNotes[n]);
  448         if (*pLast == *pNote)
  449         {
  450             delete pNote;
  451             return;
  452         }
  453     }
  454 
  455     m_vpNotes.push_back(pNote);
  456 }
  457 
  458 
  459 
  460 void NoteColl::sort()
  461 {
  462     std::sort(m_vpNotes.begin(), m_vpNotes.end(), CmpNotePtrById()); // !!! needed when applying filters
  463 }
  464 
  465 
  466 void NoteColl::removeTraceNotes()
  467 {
  468     vector<Note*> v;
  469     for (int i = 0, n = cSize(m_vpNotes); i < n; ++i)
  470     {
  471         Note* p (m_vpNotes[i]);
  472         if (Note::TRACE == p->getSeverity())
  473         {
  474             delete p;
  475         }
  476         else
  477         {
  478             v.push_back(p);
  479         }
  480     }
  481     m_vpNotes.swap(v);
  482 }
  483 
  484 
  485 bool NoteColl::hasFastSaveWarn() const
  486 {
  487     for (int i = cSize(m_vpNotes) - 1; i >= 0; --i)
  488     {
  489         Note* pNote (m_vpNotes[i]);
  490         if (*pNote == Notes::rescanningNeeded()) { return true; }
  491     }
  492 
  493     return false;
  494 }
  495 
  496 
  497 void NoteColl::addFastSaveWarn()
  498 {
  499     if (hasFastSaveWarn()) { return; }
  500     add(new Note(Notes::rescanningNeeded(), -1));
  501 }
  502 
  503 
  504 void NoteColl::removeNotes(const std::streampos& posFrom, const std::streampos& posTo) // removes notes with addresses in the given range; posFrom is included, but posTo isn't
  505 {
  506     for (int i = cSize(m_vpNotes) - 1; i >= 0; --i)
  507     {
  508         Note* pNote (m_vpNotes[i]);
  509         if (pNote->getPos() >= posFrom && pNote->getPos() < posTo)
  510         {
  511             delete pNote;
  512             m_vpNotes.erase(m_vpNotes.begin() + i);
  513         }
  514     }
  515 }
  516 
  517 
  518 
  519 
  520 
  521 bool Notes::CompNoteByName::operator()(const Note* p1, const Note* p2) const
  522 {
  523     return strcmp(p1->getDescription(), p2->getDescription()) < 0;
  524 }
  525