|
|
@ -179,24 +179,17 @@ static int string_is_ascii(const uint8_t *str) |
|
|
|
int ff_ape_write_tag(AVFormatContext *s) |
|
|
|
int ff_ape_write_tag(AVFormatContext *s) |
|
|
|
{ |
|
|
|
{ |
|
|
|
AVDictionaryEntry *e = NULL; |
|
|
|
AVDictionaryEntry *e = NULL; |
|
|
|
int64_t start, end; |
|
|
|
int size, ret, count = 0; |
|
|
|
int size, count = 0; |
|
|
|
AVIOContext *dyn_bc = NULL; |
|
|
|
|
|
|
|
uint8_t *dyn_buf = NULL; |
|
|
|
|
|
|
|
|
|
|
|
if (!s->pb->seekable) |
|
|
|
if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0) |
|
|
|
return 0; |
|
|
|
goto end; |
|
|
|
|
|
|
|
|
|
|
|
start = avio_tell(s->pb); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// header
|
|
|
|
|
|
|
|
avio_write(s->pb, "APETAGEX", 8); // id
|
|
|
|
|
|
|
|
avio_wl32 (s->pb, APE_TAG_VERSION); // version
|
|
|
|
|
|
|
|
avio_wl32(s->pb, 0); // reserve space for size
|
|
|
|
|
|
|
|
avio_wl32(s->pb, 0); // reserve space for tag count
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// flags
|
|
|
|
// flags
|
|
|
|
avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER | |
|
|
|
avio_wl32(dyn_bc, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER | |
|
|
|
APE_TAG_FLAG_IS_HEADER); |
|
|
|
APE_TAG_FLAG_IS_HEADER); |
|
|
|
ffio_fill(s->pb, 0, 8); // reserved
|
|
|
|
ffio_fill(dyn_bc, 0, 8); // reserved
|
|
|
|
|
|
|
|
|
|
|
|
while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) { |
|
|
|
int val_len; |
|
|
|
int val_len; |
|
|
@ -207,18 +200,31 @@ int ff_ape_write_tag(AVFormatContext *s) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
val_len = strlen(e->value); |
|
|
|
val_len = strlen(e->value); |
|
|
|
avio_wl32(s->pb, val_len); // value length
|
|
|
|
avio_wl32(dyn_bc, val_len); // value length
|
|
|
|
avio_wl32(s->pb, 0); // item flags
|
|
|
|
avio_wl32(dyn_bc, 0); // item flags
|
|
|
|
avio_put_str(s->pb, e->key); // key
|
|
|
|
avio_put_str(dyn_bc, e->key); // key
|
|
|
|
avio_write(s->pb, e->value, val_len); // value
|
|
|
|
avio_write(dyn_bc, e->value, val_len); // value
|
|
|
|
count++; |
|
|
|
count++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!count) |
|
|
|
|
|
|
|
goto end; |
|
|
|
|
|
|
|
|
|
|
|
size = avio_tell(s->pb) - start; |
|
|
|
size = avio_close_dyn_buf(dyn_bc, &dyn_buf); |
|
|
|
|
|
|
|
if (size <= 0) |
|
|
|
|
|
|
|
goto end; |
|
|
|
|
|
|
|
size += 20; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// header
|
|
|
|
|
|
|
|
avio_write(s->pb, "APETAGEX", 8); // id
|
|
|
|
|
|
|
|
avio_wl32(s->pb, APE_TAG_VERSION); // version
|
|
|
|
|
|
|
|
avio_wl32(s->pb, size); |
|
|
|
|
|
|
|
avio_wl32(s->pb, count); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
avio_write(s->pb, dyn_buf, size - 20); |
|
|
|
|
|
|
|
|
|
|
|
// footer
|
|
|
|
// footer
|
|
|
|
avio_write(s->pb, "APETAGEX", 8); // id
|
|
|
|
avio_write(s->pb, "APETAGEX", 8); // id
|
|
|
|
avio_wl32 (s->pb, APE_TAG_VERSION); // version
|
|
|
|
avio_wl32(s->pb, APE_TAG_VERSION); // version
|
|
|
|
avio_wl32(s->pb, size); // size
|
|
|
|
avio_wl32(s->pb, size); // size
|
|
|
|
avio_wl32(s->pb, count); // tag count
|
|
|
|
avio_wl32(s->pb, count); // tag count
|
|
|
|
|
|
|
|
|
|
|
@ -226,12 +232,10 @@ int ff_ape_write_tag(AVFormatContext *s) |
|
|
|
avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER); |
|
|
|
avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER); |
|
|
|
ffio_fill(s->pb, 0, 8); // reserved
|
|
|
|
ffio_fill(s->pb, 0, 8); // reserved
|
|
|
|
|
|
|
|
|
|
|
|
// update values in the header
|
|
|
|
end: |
|
|
|
end = avio_tell(s->pb); |
|
|
|
if (dyn_bc && !dyn_buf) |
|
|
|
avio_seek(s->pb, start + 12, SEEK_SET); |
|
|
|
avio_close_dyn_buf(dyn_bc, &dyn_buf); |
|
|
|
avio_wl32(s->pb, size); |
|
|
|
av_freep(&dyn_buf); |
|
|
|
avio_wl32(s->pb, count); |
|
|
|
|
|
|
|
avio_seek(s->pb, end, SEEK_SET); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|