id3v2: read TXXX frames with two calls to decode_str() instead of one.

Read the key in the first, value in the second.

This allows to avoid pointless strdups and simplify decode_str() by
dropping two of its parameters.
This commit is contained in:
Anton Khirnov 2011-10-02 09:06:34 +02:00
parent 1e18d32d01
commit d2961e4ebf
1 changed files with 28 additions and 32 deletions

View File

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