|
@@ -73,23 +73,20 @@ static void free_geobtag(ID3v2ExtraMetaGEOB *geob)
|
|
|
|
|
|
/**
|
|
|
* Decode characters to UTF-8 according to encoding type. The decoded buffer is
|
|
|
- * always null terminated.
|
|
|
+ * always null terminated. Stop reading when either *maxread bytes are read from
|
|
|
+ * pb or U+0000 character is found.
|
|
|
*
|
|
|
* @param dst Pointer where the address of the buffer with the decoded bytes is
|
|
|
* stored. Buffer must be freed by caller.
|
|
|
- * @param dstlen Pointer to an int where the length of the decoded string
|
|
|
- * is stored (in bytes, incl. null termination)
|
|
|
* @param maxread Pointer to maximum number of characters to read from the
|
|
|
* AVIOContext. After execution the value is decremented by the number of bytes
|
|
|
* actually read.
|
|
|
- * @seeknull If true, decoding stops after the first U+0000 character found, if
|
|
|
- * there is any before maxread is reached
|
|
|
* @returns 0 if no error occured, dst is uninitialized on error
|
|
|
*/
|
|
|
static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
|
|
|
- uint8_t **dst, int *dstlen, int *maxread, const int seeknull)
|
|
|
+ uint8_t **dst, int *maxread)
|
|
|
{
|
|
|
- int len, ret;
|
|
|
+ int ret;
|
|
|
uint8_t tmp;
|
|
|
uint32_t ch = 1;
|
|
|
int left = *maxread;
|
|
@@ -104,7 +101,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
|
|
|
switch (encoding) {
|
|
|
|
|
|
case ID3v2_ENCODING_ISO8859:
|
|
|
- while (left && (!seeknull || ch)) {
|
|
|
+ while (left && ch) {
|
|
|
ch = avio_r8(pb);
|
|
|
PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
|
|
|
left--;
|
|
@@ -133,7 +130,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
|
|
|
// fall-through
|
|
|
|
|
|
case ID3v2_ENCODING_UTF16BE:
|
|
|
- while ((left > 1) && (!seeknull || ch)) {
|
|
|
+ while ((left > 1) && ch) {
|
|
|
GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
|
|
|
PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
|
|
|
}
|
|
@@ -142,7 +139,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
|
|
|
break;
|
|
|
|
|
|
case ID3v2_ENCODING_UTF8:
|
|
|
- while (left && (!seeknull || ch)) {
|
|
|
+ while (left && ch) {
|
|
|
ch = avio_r8(pb);
|
|
|
avio_w8(dynbuf, ch);
|
|
|
left--;
|
|
@@ -155,10 +152,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
|
|
|
if (ch)
|
|
|
avio_w8(dynbuf, 0);
|
|
|
|
|
|
- len = avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
|
|
|
- if (dstlen)
|
|
|
- *dstlen = len;
|
|
|
-
|
|
|
+ avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
|
|
|
*maxread = left;
|
|
|
|
|
|
return 0;
|
|
@@ -170,38 +164,40 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
|
|
|
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
|
|
|
{
|
|
|
uint8_t *dst;
|
|
|
- const char *val = NULL;
|
|
|
- int len, dstlen;
|
|
|
+ int encoding, dict_flags = AV_DICT_DONT_OVERWRITE;
|
|
|
unsigned genre;
|
|
|
|
|
|
if (taglen < 1)
|
|
|
return;
|
|
|
|
|
|
+ encoding = avio_r8(pb);
|
|
|
taglen--; /* account for encoding type byte */
|
|
|
|
|
|
- if (decode_str(s, pb, avio_r8(pb), &dst, &dstlen, &taglen, 0) < 0) {
|
|
|
+ if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
|
|
|
av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
|
|
|
&& (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
|
|
|
- && genre <= ID3v1_GENRE_MAX)
|
|
|
- val = ff_id3v1_genre_str[genre];
|
|
|
- else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
|
|
|
- /* dst now contains two 0-terminated strings */
|
|
|
- dst[dstlen] = 0;
|
|
|
- len = strlen(dst);
|
|
|
+ && genre <= ID3v1_GENRE_MAX) {
|
|
|
+ av_freep(&dst);
|
|
|
+ dst = ff_id3v1_genre_str[genre];
|
|
|
+ } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
|
|
|
+ /* dst now contains the key, need to get value */
|
|
|
key = dst;
|
|
|
- val = dst + FFMIN(len + 1, dstlen);
|
|
|
+ if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
|
|
|
+ av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
|
|
|
+ av_freep(&key);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ dict_flags |= AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_STRDUP_KEY;
|
|
|
}
|
|
|
else if (*dst)
|
|
|
- val = dst;
|
|
|
-
|
|
|
- if (val)
|
|
|
- av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
|
|
|
+ dict_flags |= AV_DICT_DONT_STRDUP_VAL;
|
|
|
|
|
|
- av_free(dst);
|
|
|
+ if (dst)
|
|
|
+ av_dict_set(&s->metadata, key, dst, dict_flags);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -234,17 +230,17 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *
|
|
|
taglen--;
|
|
|
|
|
|
/* read MIME type (always ISO-8859) */
|
|
|
- if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, NULL, &taglen, 1) < 0
|
|
|
+ if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, &taglen) < 0
|
|
|
|| taglen <= 0)
|
|
|
goto fail;
|
|
|
|
|
|
/* read file name */
|
|
|
- if (decode_str(s, pb, encoding, &geob_data->file_name, NULL, &taglen, 1) < 0
|
|
|
+ if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0
|
|
|
|| taglen <= 0)
|
|
|
goto fail;
|
|
|
|
|
|
/* read content description */
|
|
|
- if (decode_str(s, pb, encoding, &geob_data->description, NULL, &taglen, 1) < 0
|
|
|
+ if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0
|
|
|
|| taglen < 0)
|
|
|
goto fail;
|
|
|
|