d->text = values;
}
+APE::Item::Item(const String &key, const ByteVector &value)
+{
+ d = new ItemPrivate;
+ d->type = Binary;
+ d->key = key;
+ d->value = value;
+}
+
APE::Item::Item(const Item &item)
{
d = new ItemPrivate(*item.d);
return d->key;
}
+ByteVector APE::Item::binaryData() const
+{
+ return d->value;
+}
+
+void APE::Item::setBinaryData(const ByteVector &value)
+{
+ d->type = Binary;
+ d->value = value;
+}
+
ByteVector APE::Item::value() const
{
// This seems incorrect as it won't be actually rendering the value to keep it
void APE::Item::setValue(const String &value)
{
+ d->type = Text;
d->text = value;
}
void APE::Item::setValues(const StringList &value)
{
+ d->type = Text;
d->text = value;
}
void APE::Item::appendValue(const String &value)
{
+ d->type = Text;
d->text.append(value);
}
void APE::Item::appendValues(const StringList &values)
{
+ d->type = Text;
d->text.append(values);
}
int APE::Item::size() const
{
- return 8 + d->key.size() + 1 + d->value.size();
+ // SFB: Why is d->key.size() used when size() returns the length in UniChars and not UTF-8?
+ int result = 8 + d->key.size() /* d->key.data(String::UTF8).size() */ + 1;
+ switch (d->type) {
+ case Text:
+ {
+ StringList::ConstIterator it = d->text.begin();
+
+ result += it->data(String::UTF8).size();
+ it++;
+ for(; it != d->text.end(); ++it)
+ result += 1 + it->data(String::UTF8).size();
+ break;
+ }
+
+ case Binary:
+ case Locator:
+ result += d->value.size();
+ break;
+ }
+ return result;
}
StringList APE::Item::toStringList() const
{
switch(d->type) {
case Text:
- case Binary:
if(d->text.isEmpty())
return true;
if(d->text.size() == 1 && d->text.front().isEmpty())
return true;
return false;
+ case Binary:
case Locator:
return d->value.isEmpty();
default:
setReadOnly(flags & 1);
setType(ItemTypes((flags >> 1) & 3));
- if(int(d->type) < 2)
+ if(Text == d->type)
d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
}
Item();
/*!
- * Constructs an item with \a key and \a value.
+ * Constructs a text item with \a key and \a value.
*/
// BIC: Remove this, StringList has a constructor from a single string
Item(const String &key, const String &value);
/*!
- * Constructs an item with \a key and \a values.
+ * Constructs a text item with \a key and \a values.
*/
Item(const String &key, const StringList &values);
+ /*!
+ * Constructs a binary item with \a key and \a value.
+ */
+ Item(const String &key, const ByteVector &value);
+
/*!
* Construct an item as a copy of \a item.
*/
/*!
* Returns the binary value.
- *
- * \deprecated This will be removed in the next binary incompatible version
- * as it is not kept in sync with the things that are set using setValue()
- * and friends.
+ * If the item type is not \a Binary, the returned contents are undefined
*/
+ ByteVector binaryData() const;
+
+ /*!
+ * Set the binary value to \a value
+ * The item's type will also be set to \a Binary
+ */
+ void setBinaryData(const ByteVector &value);
+
+#ifndef DO_NOT_DOCUMENT
+ /* Remove in next binary incompatible release */
ByteVector value() const;
+#endif
/*!
* Sets the key for the item to \a key.
void setKey(const String &key);
/*!
- * Sets the value of the item to \a value and clears any previous contents.
+ * Sets the text value of the item to \a value and clears any previous contents.
*
* \see toString()
*/
void setValue(const String &value);
/*!
- * Sets the value of the item to the list of values in \a value and clears
+ * Sets the text value of the item to the list of values in \a value and clears
* any previous contents.
*
* \see toStringList()
void setValues(const StringList &values);
/*!
- * Appends \a value to create (or extend) the current list of values.
+ * Appends \a value to create (or extend) the current list of text values.
*
* \see toString()
*/
void appendValue(const String &value);
/*!
- * Appends \a values to extend the current list of values.
+ * Appends \a values to extend the current list of text values.
*
* \see toStringList()
*/
*/
String toString() const;
- /*!
- * \deprecated
- * \see values
- */
+#ifndef DO_NOT_DOCUMENT
+ /* Remove in next binary incompatible release */
StringList toStringList() const;
+#endif
/*!
- * Returns the list of values.
+ * Returns the list of text values.
*/
StringList values() const;
if(replace)
removeItem(key);
if(!key.isEmpty() && !value.isEmpty()) {
- if(!replace && d->itemListMap.contains(key))
- d->itemListMap[key.upper()].appendValue(value);
+ if(!replace && d->itemListMap.contains(key)) {
+ // Text items may contain more than one value
+ if(APE::Item::Text == d->itemListMap.begin()->second.type())
+ d->itemListMap[key.upper()].appendValue(value);
+ // Binary or locator items may have only one value
+ else
+ setItem(key, Item(key, value));
+ }
else
setItem(key, Item(key, value));
}
}
+void APE::Tag::setData(const String &key, const ByteVector &value)
+{
+ removeItem(key);
+ if(!key.isEmpty() && !value.isEmpty())
+ setItem(key, Item(key, value));
+}
+
void APE::Tag::setItem(const String &key, const Item &item)
{
if(!key.isEmpty())
void removeItem(const String &key);
/*!
- * Adds to the item specified by \a key the data \a value. If \a replace
+ * Adds to the text item specified by \a key the data \a value. If \a replace
* is true, then all of the other values on the same key will be removed
- * first.
+ * first. If a binary item exists for \a key it will be removed first.
*/
void addValue(const String &key, const String &value, bool replace = true);
+ /*!
+ * Set the binary data for the key specified by \a item to \a value
+ * This will convert the item to type \a Binary if it isn't already and
+ * all of the other values on the same key will be removed.
+ */
+ void setData(const String &key, const ByteVector &value);
+
/*!
* Sets the \a key item to the value of \a item. If an item with the \a key is already
* present, it will be replaced.