Forcing v2.3 tags for Win XP compatibility...

Jeremy Gregorio jeremy.firefox.addon at gmail.com
Sat Nov 17 22:55:18 UTC 2012


Thanks! That got me on the right track. I'd completely missed the Test
folder :P, and was just looking in examples. Here's my code. The trick is
you create your FileRef object with a new TagLib::MPEG::File object instead
of the plain string, like so:

    TagLib::FileRef f( new MPEG::File( argv[argc - 1] ) );

Then when you get the file object from the list of File Refs you can cast
it to a TagLib::MPEG::File and call it's special 'save' method that lets
you set version:

    TagLib::MPEG::File *mpegFile = (TagLib::MPEG::File*)(*it).file();
    mpegFile->save(MPEG::File::AllTags, true, 3);

Here's the full code. The only wrinkle here is I've modified the original
sample tagger to take the incoming strings as base64 values as an ugly hack
to get around Windows XP's lousy Unicode support on the  Command line :P.
I'm pretty sure I can ditch this though.

#include <iostream>
#include <string.h>

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>

#include <tlist.h>
#include <fileref.h>
#include <tfile.h>
#include <tag.h>
#include <id3v2tag.h>
#include <mpegfile.h>


#include <Poco/URI.h>

#include "Poco/TextConverter.h"
#include "Poco/ASCIIEncoding.h"
#include "Poco/UTF8Encoding.h"
#include "Poco/UTF16Encoding.h"
#include "Poco/UnicodeConverter.h"
using Poco::TextConverter;
using Poco::ASCIIEncoding;
using Poco::UTF8Encoding;
using Poco::UTF16Encoding;


using namespace std;
using namespace TagLib;

bool isArgument(const char *s)
{
  return strlen(s) == 2 && s[0] == '-';
}

bool isFile(const char *s)
{
  struct stat st;
#ifdef _WIN32
  return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG));
#else
  return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG | S_IFLNK));
#endif
}

void usage()
{
  cout << endl;
  cout << "Usage: tagwriter <fields> <files>" << endl;
  cout << endl;
  cout << "Where the valid fields are:" << endl;
  cout << "  -t <title>"   << endl;
  cout << "  -a <artist>"  << endl;
  cout << "  -A <album>"   << endl;
  cout << "  -c <comment>" << endl;
  cout << "  -g <genre>"   << endl;
  cout << "  -y <year>"    << endl;
  cout << "  -T <track>"   << endl;
  cout << endl;

  exit(1);
}

int main(int argc, char *argv[])
{
  TagLib::List<TagLib::FileRef> fileList;

  while(argc > 0 && isFile(argv[argc - 1])) {

    TagLib::FileRef f( new MPEG::File( argv[argc - 1] ) );

    if(!f.isNull() && f.tag())
      fileList.append(f);

    argc--;
  }

  if(fileList.isEmpty())
    usage();



  for(int i = 1; i < argc - 1; i += 2) {

    if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {



      char field = argv[i][1];

    std::string decoded;
    std::wstring decoded16;

    Poco::URI::decode ( argv[i + 1] , decoded ) ;

    const char* mp3FileName;

    Poco::UnicodeConverter::toUTF16(decoded, decoded16);

    TagLib::String value ( decoded16 );

    cout << "Decoded Value " << decoded << endl;

      TagLib::List<TagLib::FileRef>::Iterator it;
      for(it = fileList.begin(); it != fileList.end(); ++it) {

    cout << "file name found " << endl;


        TagLib::Tag *t = (*it).tag();

        switch (field) {
        case 't':
          t->setTitle(value);
          break;
        case 'a':
          t->setArtist(value);
          break;
        case 'A':
          t->setAlbum(value);
          break;
        case 'c':
          t->setComment(value);
          break;
        case 'g':
          t->setGenre(value);
          break;
        case 'y':
          t->setYear(value.toInt());
          break;
        case 'T':
          t->setTrack(value.toInt());
          break;
        default:
          usage();
          break;
        }//END SWITCH STATEMENT*/


      }//END FOR LOOP
    }else
      usage();
  }//end if-else

  TagLib::List<TagLib::FileRef>::Iterator it;
  for(it = fileList.begin(); it != fileList.end(); ++it){

    TagLib::MPEG::File *mpegFile = (TagLib::MPEG::File*)(*it).file();
    mpegFile->save(MPEG::File::AllTags, true, 3);
    //(*it).file()->save();

  }

  return 0;
}//END MAIN


To build the above run:

g++ ./mid3lib_tagger.cpp -o encTagwriter -L/use/local/lib/
-I/usr/local/include/taglib -ltag -lPocoFoundation -lPocoUtil -lPocoXML
-lPocoNet `llvm-config --libs core` `llvm-config --ldflags`

You'll need to install Poco statically, but that's pretty easy :P

On Fri, Nov 16, 2012 at 7:09 PM, Neil Hodge <neil.hodge at gmail.com> wrote:

> Jeremy:
>
>
> On 11/15/12 7:10 PM, Jeremy Gregorio wrote:
>
>> I wanted to start up a new thread on this because I just can't seem to
>> figure it out. Do I need to set the option at the frame level or can I
>> instantiate an 'ID3V2.3' object? For reference, I'm trying to keep
>> compatibility with Win XP (Still running it for games...).
>>
>>    Thanks yet again!
>>
>>
> They seem to have some stuff implemented in TagLib::ID3v2::Header,
> including:
>
> * uint majorVersion
> * void setMajorVersion
>
> Although, regarding setMajorVersion, they say "This is used by the
> internal parser; this will not change the version which is written and in
> general should not be called by API users."
>
> I think if you want as much control as you are asking for, you need to
> implement it yourself.  Check out the function "testDowngradeTo23" in
> test_id3v2.cpp.
>
> Good luck . . .
>
> Neil
>
> ______________________________**_________________
> taglib-devel mailing list
> taglib-devel at kde.org
> https://mail.kde.org/mailman/**listinfo/taglib-devel<https://mail.kde.org/mailman/listinfo/taglib-devel>
>



-- 
Jeremy D Gregorio
Sr Consultant
#: 520-275-5352
fax: 520-747-2540

<http://www.linkedin.com/pub/jeremy-gregorio/36/302/429>
<http://www.glimmersoft.com/socialmedia/btn_viewmy_160x33.png>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/taglib-devel/attachments/20121117/bba562a3/attachment.html>


More information about the taglib-devel mailing list