int opus_tags_add_comment(OpusTags *_tags,const char *_comment){ int comment_len; int ncomments; int ret; ncomments=_tags->comments; ret=op_tags_ensure_capacity(_tags,ncomments+1); if(OP_UNLIKELY(ret<0))return ret; comment_len=(int)strlen(_comment); _tags->comment_lengths[ncomments]=0; _tags->user_comments[ncomments]=op_strdup_with_len(_comment,comment_len); if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT; _tags->comment_lengths[ncomments]=comment_len; _tags->comments=ncomments+1; return 0; }
int opus_tags_add_comment(OpusTags *_tags,const char *_comment){ char *comment; int ncomments; int comment_len; int ret; ret=op_tags_add_prepare(_tags); if(OP_UNLIKELY(ret<0))return ret; comment_len=strlen(_comment); ncomments=_tags->comments; _tags->user_comments[ncomments]=comment=(char *) _ogg_malloc(sizeof(*_tags->user_comments[ncomments])*(comment_len+1)); if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; _tags->comment_lengths[ncomments]=comment_len; memcpy(comment,_comment,sizeof(*comment)*(comment_len+1)); return 0; }
/*Add room for a new comment.*/ static int op_tags_add_prepare(OpusTags *_tags){ char **user_comments; int *comment_lengths; int ncomments; ncomments=_tags->comments; user_comments=(char **)_ogg_realloc(_tags->user_comments, sizeof(*_tags->user_comments)*(ncomments+2)); if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT; _tags->user_comments=user_comments; comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths, sizeof(*_tags->comment_lengths)*(ncomments+2)); if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT; _tags->comment_lengths=comment_lengths; comment_lengths[ncomments]=comment_lengths[ncomments+1]=0; /*Our caller will always set user_comments[ncomments].*/ user_comments[ncomments+1]=NULL; return 0; }
int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){ OpusTags dst; int ret; opus_tags_init(&dst); ret=opus_tags_copy_impl(&dst,_src); if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst); else *_dst=*&dst; return 0; }
/*Ensure there's room for up to _ncomments comments.*/ static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){ char **user_comments; int *comment_lengths; size_t size; if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT; size=sizeof(*_tags->comment_lengths)*(_ncomments+1); if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT; comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size); if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT; comment_lengths[_ncomments]=0; _tags->comment_lengths=comment_lengths; size=sizeof(*_tags->user_comments)*(_ncomments+1); if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT; user_comments=(char **)_ogg_realloc(_tags->user_comments,size); if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT; user_comments[_ncomments]=NULL; _tags->user_comments=user_comments; return 0; }
int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){ char *comment; int tag_len; int value_len; int ncomments; int ret; ret=op_tags_add_prepare(_tags); if(OP_UNLIKELY(ret<0))return ret; tag_len=strlen(_tag); value_len=strlen(_value); ncomments=_tags->comments; /*+2 for '=' and '\0'.*/ _tags->user_comments[ncomments]=comment= (char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2)); if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; _tags->comment_lengths[ncomments]=tag_len+value_len+1; memcpy(comment,_tag,sizeof(*comment)*tag_len); comment[tag_len]='='; memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1)); return 0; }
/*Duplicate a (possibly non-NUL terminated) string with a known length.*/ static char *op_strdup_with_len(const char *_s,size_t _len){ size_t size; char *ret; size=sizeof(*ret)*(_len+1); if(OP_UNLIKELY(size<_len))return NULL; ret=(char *)_ogg_malloc(size); if(OP_LIKELY(ret!=NULL)){ ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len); ret[_len]='\0'; } return ret; }
/*The actual implementation of opus_tags_copy(). Unlike the public API, this function requires _dst to already be initialized, modifies its contents before success is guaranteed, and assumes the caller will clear it on error.*/ static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){ char *vendor; int ncomments; int ret; int ci; vendor=_src->vendor; _dst->vendor=op_strdup_with_len(vendor,strlen(vendor)); if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT; ncomments=_src->comments; ret=op_tags_ensure_capacity(_dst,ncomments); if(OP_UNLIKELY(ret<0))return ret; for(ci=0;ci<ncomments;ci++){ int len; len=_src->comment_lengths[ci]; OP_ASSERT(len>=0); _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len); if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT; _dst->comment_lengths[ci]=len; _dst->comments=ci+1; } return 0; }