Returning QByteArray as Qvariant



  • Hello I am experiencing some problems with my code. I am implementing a function that returns tag value from a music:

    QVariant getTagValue (TagKey key)
    

    For the cover the return value is a QByteArray. The problem shows up when I try to convert the returned value to a QPixmap.

    ...
    QPixmap image;
    QByteArray data = music.getTagValue (Music::TagKey::Cover).toByteArray();
    bool ok = image.loadFromData(data);    //Returns false
                                           //Error: Corrupt JPEG data: premature end of data segment
                                           //Unsupported marker type 0x0b
    

    But when I do the same thing inside the function just before the return statement it just works fine.
    How do you explain that?


  • Lifetime Qt Champion

    Hi,

    How is getTagValue implemented ?



  • @SGaist The implementation:

    QVariant Music::getTagValue(Music::TagKey key)
    {
       TagParser::TagValue value;
       value = getRawValue ((TagParser::KnownField) key);
    
       if (key == ... )
       ....
    
       else if (key == TagKey::Cover)
          {
             if (value.isEmpty ())
                return QByteArray  ();
    
             QByteArray data = QByteArray::fromRawData (value.dataPointer (), value.dataSize ());
    
             return data;
          }
       ...
    }
    


  • @SGaist

    TagParser::TagValue Music::getRawValue(TagParser::KnownField field)
    {
       if (fileInfo.isOpen ())
          {
             auto tags = fileInfo.tags ();
    
             for (uint i=0; i < tags.size (); i++)
                {
                   TagParser::TagValue value = tags.at (i)->value (field);
                   if (!value.isEmpty ())
                      return value;
                }
         }
    
       return TagParser::TagValue();
    }
    

    TagParser is library from GitHub.
    I already made the following implementation with the library and it worked perfectly:

    QPixmap cover()
    {
       TagParser::TagValue value;
       value = getRawValue (TagParser::KnownField::Cover);
    
       if (value.isEmpty ())
          return QByteArray  ();
    
       QByteArray data = QByteArray::fromRawData (value.dataPointer (), value.dataSize ());
       QPixmap pixmap;
       pixmap.loadFromData (data);
    
       return pixmap;
    }
    

  • Moderators

    @Euclide said in Returning QByteArray as Qvariant:

    QVariant Music::getTagValue(Music::TagKey key)
    {....
    
             QByteArray data = QByteArray::fromRawData (value.dataPointer (), value.dataSize ());
    
             return data;
          }
       ...
    }
    

    I'm not sure if that implicit conversion will work. You should try:

    return QVariant(data);


  • Qt Champions 2018

    @Euclide said in Returning QByteArray as Qvariant:

    QByteArray data = QByteArray::fromRawData (value.dataPointer (), value.dataSize ());

    This is very very dangerous in the current use case. When value goes out of scope before data (which is likely the case here since data is moved into the QVariant) the next access to this data will likely point to uninitialized memory.
    Don't use QByteArray::fromRawData() when you don't know what you're doing!



  • @Christian-Ehrlicher Yes I agree.



  • I found where the problem was!

    As Christian Ehrlicher said according to the Documentation QByteArray::fromRawData() only store the pointer to the data. That explain why it doensn't work outside the function since the data goes out of scope. Instead of using this method I used one the constructors that make deep copy of the data. And it just works fine!

         QByteArray data (value.dataPointer (), value.dataSize ());
         return data;
    

    Thanks all!