|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
|
Packit |
a38265 |
Organisation (CSIRO) Australia
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
a38265 |
modification, are permitted provided that the following conditions
|
|
Packit |
a38265 |
are met:
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions of source code must retain the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions in binary form must reproduce the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
a38265 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Neither the name of CSIRO Australia nor the names of its
|
|
Packit |
a38265 |
contributors may be used to endorse or promote products derived from
|
|
Packit |
a38265 |
this software without specific prior written permission.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
a38265 |
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
a38265 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
a38265 |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
|
|
Packit |
a38265 |
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
a38265 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
a38265 |
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
a38265 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
a38265 |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
a38265 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
a38265 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "config.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <stdio.h>
|
|
Packit |
a38265 |
#include <stdlib.h>
|
|
Packit |
a38265 |
#include <string.h>
|
|
Packit |
a38265 |
#include <limits.h> /* ULONG_MAX */
|
|
Packit |
a38265 |
#ifndef WIN32
|
|
Packit |
a38265 |
#include <strings.h>
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <assert.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz_private.h"
|
|
Packit |
a38265 |
#include "oggz_vector.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz/oggz_stream.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*#define DEBUG*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef WIN32
|
|
Packit |
a38265 |
#define strcasecmp _stricmp
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Ensure comment vector length can be expressed in 32 bits
|
|
Packit |
a38265 |
* including space for the trailing NUL */
|
|
Packit |
a38265 |
#define MAX_COMMENT_LENGTH 0xFFFFFFFE
|
|
Packit |
a38265 |
#define oggz_comment_clamp(c) MIN((c),MAX_COMMENT_LENGTH)
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static size_t
|
|
Packit |
a38265 |
oggz_comment_len (const char * s)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
size_t len;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (s == NULL) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
len = strlen (s);
|
|
Packit |
a38265 |
return oggz_comment_clamp(len);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static char *
|
|
Packit |
a38265 |
oggz_strdup (const char * s)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
char * ret;
|
|
Packit |
a38265 |
if (s == NULL) return NULL;
|
|
Packit |
a38265 |
ret = oggz_malloc (oggz_comment_len(s) + 1);
|
|
Packit |
a38265 |
if (ret == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return strcpy (ret, s);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static char *
|
|
Packit |
a38265 |
oggz_strdup_len (const char * s, size_t len)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
char * ret;
|
|
Packit |
a38265 |
if (s == NULL) return NULL;
|
|
Packit |
a38265 |
if (len == 0) return NULL;
|
|
Packit |
a38265 |
len = oggz_comment_clamp(len);
|
|
Packit |
a38265 |
ret = oggz_malloc (len + 1);
|
|
Packit |
a38265 |
if (!ret) return NULL;
|
|
Packit |
a38265 |
if (strncpy (ret, s, len) == NULL) {
|
|
Packit |
a38265 |
oggz_free (ret);
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ret[len] = '\0';
|
|
Packit |
a38265 |
return ret;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static char *
|
|
Packit |
a38265 |
oggz_index_len (const char * s, char c, int len)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (i = 0; *s && i < len; i++, s++) {
|
|
Packit |
a38265 |
if (*s == c) return (char *)s;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
Comments will be stored in the Vorbis style.
|
|
Packit |
a38265 |
It is describled in the "Structure" section of
|
|
Packit |
a38265 |
http://www.xiph.org/ogg/vorbis/doc/v-comment.html
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
The comment header is decoded as follows:
|
|
Packit |
a38265 |
1) [vendor_length] = read an unsigned integer of 32 bits
|
|
Packit |
a38265 |
2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
|
|
Packit |
a38265 |
3) [user_comment_list_length] = read an unsigned integer of 32 bits
|
|
Packit |
a38265 |
4) iterate [user_comment_list_length] times {
|
|
Packit |
a38265 |
5) [length] = read an unsigned integer of 32 bits
|
|
Packit |
a38265 |
6) this iteration's user comment = read a UTF-8 vector as [length] octets
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
7) [framing_bit] = read a single bit as boolean
|
|
Packit |
a38265 |
8) if ( [framing_bit] unset or end of packet ) then ERROR
|
|
Packit |
a38265 |
9) done.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
If you have troubles, please write to ymnk@jcraft.com.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
|
|
Packit |
a38265 |
((buf[base+2]<<16)&0xff0000)| \
|
|
Packit |
a38265 |
((buf[base+1]<<8)&0xff00)| \
|
|
Packit |
a38265 |
(buf[base]&0xff))
|
|
Packit |
a38265 |
#define writeint(buf, base, val) buf[base+3]=(char)(((val)>>24)&0xff); \
|
|
Packit |
a38265 |
buf[base+2]=(char)(((val)>>16)&0xff); \
|
|
Packit |
a38265 |
buf[base+1]=(char)(((val)>>8)&0xff); \
|
|
Packit |
a38265 |
buf[base]=(char)((val)&0xff);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* The FLAC header will encode the length of the comments in
|
|
Packit |
a38265 |
24bit BE format.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
#define writeint24be(buf, base, val) buf[base]=(char)(((val)>>16)&0xff); \
|
|
Packit |
a38265 |
buf[base+1]=(char)(((val)>>8)&0xff); \
|
|
Packit |
a38265 |
buf[base+2]=(char)((val)&0xff);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
oggz_comment_validate_byname (const char * name)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
const char * c;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!name) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (c = name; *c; c++) {
|
|
Packit |
a38265 |
if (*c < 0x20 || *c > 0x7D || *c == 0x3D) {
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("XXX char %c in %s invalid\n", *c, name);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* XXX: we really should validate value as UTF-8 here, but ... */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static OggzComment *
|
|
Packit |
a38265 |
oggz_comment_new (const char * name, const char * value)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OggzComment * comment;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!oggz_comment_validate_byname (name)) return NULL;
|
|
Packit |
a38265 |
/* Ensures that name != NULL and contains only valid characters */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
comment = oggz_malloc (sizeof (OggzComment));
|
|
Packit |
a38265 |
if (comment == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
comment->name = oggz_strdup (name);
|
|
Packit |
a38265 |
if (comment->name == NULL) {
|
|
Packit |
a38265 |
oggz_free (comment);
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (value) {
|
|
Packit |
a38265 |
comment->value = oggz_strdup (value);
|
|
Packit |
a38265 |
if (comment->value == NULL) {
|
|
Packit |
a38265 |
oggz_free (comment->name);
|
|
Packit |
a38265 |
oggz_free (comment);
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
comment->value = NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return comment;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
oggz_comment_free (OggzComment * comment)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
if (!comment) return;
|
|
Packit |
a38265 |
if (comment->name) oggz_free (comment->name);
|
|
Packit |
a38265 |
if (comment->value) oggz_free (comment->value);
|
|
Packit |
a38265 |
oggz_free (comment);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
oggz_comment_cmp (const OggzComment * comment1, const OggzComment * comment2)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
if (comment1 == comment2) return 1;
|
|
Packit |
a38265 |
if (!comment1 || !comment2) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (strcasecmp (comment1->name, comment2->name)) return 0;
|
|
Packit |
a38265 |
if (strcmp (comment1->value, comment2->value)) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
_oggz_comment_set_vendor (OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
const char * vendor_string)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->vendor) oggz_free (stream->vendor);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((stream->vendor = oggz_strdup (vendor_string)) == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Public API */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
const char *
|
|
Packit |
a38265 |
oggz_comment_get_vendor (OGGZ * oggz, long serialno)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return stream->vendor;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comment_set_vendor (OGGZ * oggz, long serialno, const char * vendor_string)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL)
|
|
Packit |
a38265 |
stream = oggz_add_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz->flags & OGGZ_WRITE) {
|
|
Packit |
a38265 |
if (OGGZ_CONFIG_WRITE) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return _oggz_comment_set_vendor (oggz, serialno, vendor_string);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_DISABLED;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_INVALID;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
const OggzComment *
|
|
Packit |
a38265 |
oggz_comment_first (OGGZ * oggz, long serialno)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return oggz_vector_nth_p (stream->comments, 0);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
const OggzComment *
|
|
Packit |
a38265 |
oggz_comment_first_byname (OGGZ * oggz, long serialno, char * name)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
OggzComment * comment;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (name == NULL) return oggz_vector_nth_p (stream->comments, 0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!oggz_comment_validate_byname (name))
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (i = 0; i < oggz_vector_size (stream->comments); i++) {
|
|
Packit |
a38265 |
comment = (OggzComment *) oggz_vector_nth_p (stream->comments, i);
|
|
Packit |
a38265 |
if (comment->name && !strcasecmp (name, comment->name))
|
|
Packit |
a38265 |
return comment;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
const OggzComment *
|
|
Packit |
a38265 |
oggz_comment_next (OGGZ * oggz, long serialno, const OggzComment * comment)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL || comment == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
i = oggz_vector_find_index_p (stream->comments, comment);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return oggz_vector_nth_p (stream->comments, i+1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
const OggzComment *
|
|
Packit |
a38265 |
oggz_comment_next_byname (OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
const OggzComment * comment)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
OggzComment * v_comment;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL || comment == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
i = oggz_vector_find_index_p (stream->comments, comment);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (i++; i < oggz_vector_size (stream->comments); i++) {
|
|
Packit |
a38265 |
v_comment = (OggzComment *) oggz_vector_nth_p (stream->comments, i);
|
|
Packit |
a38265 |
if (v_comment->name && !strcasecmp (comment->name, v_comment->name))
|
|
Packit |
a38265 |
return v_comment;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static OggzComment *
|
|
Packit |
a38265 |
_oggz_comment_add_byname (oggz_stream_t * stream, const char * name, const char * value)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OggzComment * comment, * new_comment;
|
|
Packit |
a38265 |
int i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Check that the same name=value pair is not already present */
|
|
Packit |
a38265 |
for (i = 0; i < oggz_vector_size (stream->comments); i++) {
|
|
Packit |
a38265 |
comment = (OggzComment *) oggz_vector_nth_p (stream->comments, i);
|
|
Packit |
a38265 |
if (comment->name && !strcasecmp (name, comment->name)) {
|
|
Packit |
a38265 |
if (comment->value == NULL) {
|
|
Packit |
a38265 |
if (value == NULL) return comment;
|
|
Packit |
a38265 |
} else if ((value && !strcmp (value, comment->value)) ||
|
|
Packit |
a38265 |
(value == NULL && comment->value == NULL)) {
|
|
Packit |
a38265 |
return comment;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Allocate new comment and insert it */
|
|
Packit |
a38265 |
if ((new_comment = oggz_comment_new (name, value)) == NULL)
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return oggz_vector_insert_p (stream->comments, new_comment);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comment_add (OGGZ * oggz, long serialno, const OggzComment * comment)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
OggzComment * new_comment;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL)
|
|
Packit |
a38265 |
stream = oggz_add_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz->flags & OGGZ_WRITE) {
|
|
Packit |
a38265 |
if (OGGZ_CONFIG_WRITE) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!oggz_comment_validate_byname (comment->name))
|
|
Packit |
a38265 |
return OGGZ_ERR_COMMENT_INVALID;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (_oggz_comment_add_byname (stream, comment->name, comment->value) == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_DISABLED;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_INVALID;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comment_add_byname (OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
const char * name, const char * value)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
OggzComment * new_comment;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL)
|
|
Packit |
a38265 |
stream = oggz_add_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz->flags & OGGZ_WRITE) {
|
|
Packit |
a38265 |
if (OGGZ_CONFIG_WRITE) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!oggz_comment_validate_byname (name))
|
|
Packit |
a38265 |
return OGGZ_ERR_COMMENT_INVALID;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (_oggz_comment_add_byname (stream, name, value) == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_DISABLED;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_INVALID;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comment_remove (OGGZ * oggz, long serialno, OggzComment * comment)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
OggzComment * v_comment;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz->flags & OGGZ_WRITE) {
|
|
Packit |
a38265 |
if (OGGZ_CONFIG_WRITE) {
|
|
Packit |
a38265 |
v_comment = oggz_vector_find_p (stream->comments, comment);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (v_comment == NULL) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_vector_remove_p (stream->comments, v_comment);
|
|
Packit |
a38265 |
oggz_comment_free (v_comment);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_DISABLED;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_INVALID;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comment_remove_byname (OGGZ * oggz, long serialno, char * name)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
OggzComment * comment;
|
|
Packit |
a38265 |
int i, ret = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz->flags & OGGZ_WRITE) {
|
|
Packit |
a38265 |
if (OGGZ_CONFIG_WRITE) {
|
|
Packit |
a38265 |
for (i = 0; i < oggz_vector_size (stream->comments); i++) {
|
|
Packit |
a38265 |
comment = (OggzComment *) oggz_vector_nth_p (stream->comments, i);
|
|
Packit |
a38265 |
if (!strcasecmp (name, comment->name)) {
|
|
Packit |
a38265 |
oggz_comment_remove (oggz, serialno, comment);
|
|
Packit |
a38265 |
i--;
|
|
Packit |
a38265 |
ret++;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
return ret;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_DISABLED;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_INVALID;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comments_copy (OGGZ * src, long src_serialno,
|
|
Packit |
a38265 |
OGGZ * dest, long dest_serialno)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
const OggzComment * comment;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (src == NULL || dest == NULL) return OGGZ_ERR_BAD_OGGZ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (dest->flags & OGGZ_WRITE) {
|
|
Packit |
a38265 |
if (OGGZ_CONFIG_WRITE) {
|
|
Packit |
a38265 |
oggz_comment_set_vendor (dest, dest_serialno,
|
|
Packit |
a38265 |
oggz_comment_get_vendor (src, src_serialno));
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (comment = oggz_comment_first (src, src_serialno); comment;
|
|
Packit |
a38265 |
comment = oggz_comment_next (src, src_serialno, comment)) {
|
|
Packit |
a38265 |
oggz_comment_add (dest, dest_serialno, comment);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_DISABLED;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
return OGGZ_ERR_INVALID;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Internal API */
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comments_init (oggz_stream_t * stream)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
stream->vendor = NULL;
|
|
Packit |
a38265 |
stream->comments = oggz_vector_new ();
|
|
Packit |
a38265 |
if (stream->comments == NULL) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_vector_set_cmp (stream->comments, (OggzCmpFunc) oggz_comment_cmp, NULL);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comments_free (oggz_stream_t * stream)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_vector_foreach (stream->comments, (OggzFunc)oggz_comment_free);
|
|
Packit |
a38265 |
oggz_vector_delete (stream->comments);
|
|
Packit |
a38265 |
stream->comments = NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->vendor) oggz_free (stream->vendor);
|
|
Packit |
a38265 |
stream->vendor = NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
oggz_comments_decode (OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
unsigned char * comments, long length)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
char *c= (char *)comments;
|
|
Packit |
a38265 |
int i, nb_fields, n;
|
|
Packit |
a38265 |
size_t len;
|
|
Packit |
a38265 |
char *end;
|
|
Packit |
a38265 |
char * name, * value, * nvalue = NULL;
|
|
Packit |
a38265 |
OggzComment * comment;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (length<8)
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
end = c+length;
|
|
Packit |
a38265 |
len=readint(c, 0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
c+=4;
|
|
Packit |
a38265 |
if (len>(size_t)(end-c)) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Vendor */
|
|
Packit |
a38265 |
if (len > 0) {
|
|
Packit |
a38265 |
if ((nvalue = oggz_strdup_len (c, len)) == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (_oggz_comment_set_vendor (oggz, serialno, nvalue) == OGGZ_ERR_OUT_OF_MEMORY) {
|
|
Packit |
a38265 |
oggz_free (nvalue);
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_free (nvalue);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fwrite(c, 1, len, stderr); fputc ('\n', stderr);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
c+=len;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (c+4>end) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* This value gets checked effectively by the 'for' condition
|
|
Packit |
a38265 |
and the checks within the loop for c running off the end. */
|
|
Packit |
a38265 |
nb_fields=readint(c, 0);
|
|
Packit |
a38265 |
c+=4;
|
|
Packit |
a38265 |
for (i=0;i
|
|
Packit |
a38265 |
if (c+4>end) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
len=readint(c, 0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
c+=4;
|
|
Packit |
a38265 |
if (len>(size_t)(end-c)) return -1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
n = 0;
|
|
Packit |
a38265 |
name = c;
|
|
Packit |
a38265 |
value = oggz_index_len (c, '=', len);
|
|
Packit |
a38265 |
if (value) {
|
|
Packit |
a38265 |
*value = '\0';
|
|
Packit |
a38265 |
value++;
|
|
Packit |
a38265 |
n = c+len - value;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (n != 0) {
|
|
Packit |
a38265 |
if ((nvalue = oggz_strdup_len (value, n)) == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("oggz_comments_decode: [%d] %s -> %s (length %d)\n",
|
|
Packit |
a38265 |
i, name, nvalue, n);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
if (_oggz_comment_add_byname (stream, name, nvalue) == NULL) {
|
|
Packit |
a38265 |
oggz_free (nvalue);
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_free (nvalue);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
/* For the case of a comment which is not in key=value form,
|
|
Packit |
a38265 |
* duplicate exactly the length of the comment, as it is
|
|
Packit |
a38265 |
* not NUL-terminated. In the case of the last comment of the
|
|
Packit |
a38265 |
* packet, it will be followed immediately by a framing bit.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if ((nvalue = oggz_strdup_len (name, len)) == NULL)
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("oggz_comments_decode: [%d] %s (no value) (length %d)\n",
|
|
Packit |
a38265 |
i, nvalue, len);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (_oggz_comment_add_byname (stream, nvalue, NULL) == NULL) {
|
|
Packit |
a38265 |
oggz_free (nvalue);
|
|
Packit |
a38265 |
return OGGZ_ERR_OUT_OF_MEMORY;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_free (nvalue);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
c+=len;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("oggz_comments_decode: done\n");
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
* Pre-condition: at least one of accum, delta are non-zero,
|
|
Packit |
a38265 |
* ie. don't call accum_length (0, 0);
|
|
Packit |
a38265 |
* \retval 0 Failure: integer overflow
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
static unsigned long
|
|
Packit |
a38265 |
accum_length (unsigned long * accum, unsigned long delta)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
/* Pre-condition: don't call accum_length (0, 0) */
|
|
Packit |
a38265 |
assert (*accum != 0 || delta != 0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Check for integer overflow */
|
|
Packit |
a38265 |
if (delta > ULONG_MAX - (*accum))
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
*accum += delta;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return *accum;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
long
|
|
Packit |
a38265 |
oggz_comments_encode (OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
unsigned char * buf, long length)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_stream_t * stream;
|
|
Packit |
a38265 |
char * c = (char *)buf;
|
|
Packit |
a38265 |
const OggzComment * comment;
|
|
Packit |
a38265 |
int nb_fields = 0, vendor_length = 0;
|
|
Packit |
a38265 |
unsigned long actual_length = 0, remaining = length, field_length;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Deal with sign of length first */
|
|
Packit |
a38265 |
if (length < 0) return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
stream = oggz_get_stream (oggz, serialno);
|
|
Packit |
a38265 |
if (stream == NULL) return OGGZ_ERR_BAD_SERIALNO;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Vendor string */
|
|
Packit |
a38265 |
if (stream->vendor)
|
|
Packit |
a38265 |
vendor_length = oggz_comment_len (stream->vendor);
|
|
Packit |
a38265 |
if (accum_length (&actual_length, 4 + vendor_length) == 0)
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("oggz_comments_encode: vendor = %s\n", stream->vendor);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* user comment list length */
|
|
Packit |
a38265 |
if (accum_length (&actual_length, 4) == 0)
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (comment = oggz_comment_first (oggz, serialno); comment;
|
|
Packit |
a38265 |
comment = oggz_comment_next (oggz, serialno, comment)) {
|
|
Packit |
a38265 |
/* [size]"name" */
|
|
Packit |
a38265 |
if (accum_length (&actual_length, 4 + oggz_comment_len (comment->name)) == 0)
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
if (comment->value) {
|
|
Packit |
a38265 |
/* "=value" */
|
|
Packit |
a38265 |
if (accum_length (&actual_length, 1 + oggz_comment_len (comment->value)) == 0)
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
printf ("oggz_comments_encode: %s = %s\n",
|
|
Packit |
a38265 |
comment->name, comment->value);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
nb_fields++;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* framing bit */
|
|
Packit |
a38265 |
if (accum_length (&actual_length, 1) == 0)
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* NB. actual_length is not modified from here onwards */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (buf == NULL) return actual_length;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
remaining -= 4;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
writeint (c, 0, vendor_length);
|
|
Packit |
a38265 |
c += 4;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (stream->vendor) {
|
|
Packit |
a38265 |
field_length = oggz_comment_len (stream->vendor);
|
|
Packit |
a38265 |
memcpy (c, stream->vendor, MIN (field_length, remaining));
|
|
Packit |
a38265 |
c += field_length; remaining -= field_length;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
remaining -= 4;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
writeint (c, 0, nb_fields);
|
|
Packit |
a38265 |
c += 4;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (comment = oggz_comment_first (oggz, serialno); comment;
|
|
Packit |
a38265 |
comment = oggz_comment_next (oggz, serialno, comment)) {
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
field_length = oggz_comment_len (comment->name); /* [size]"name" */
|
|
Packit |
a38265 |
if (comment->value)
|
|
Packit |
a38265 |
field_length += 1 + oggz_comment_len (comment->value); /* "=value" */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
remaining -= 4;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
writeint (c, 0, field_length);
|
|
Packit |
a38265 |
c += 4;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
field_length = oggz_comment_len (comment->name);
|
|
Packit |
a38265 |
memcpy (c, comment->name, MIN (field_length, remaining));
|
|
Packit |
a38265 |
c += field_length; remaining -= field_length;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (comment->value) {
|
|
Packit |
a38265 |
remaining --;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
*c = '=';
|
|
Packit |
a38265 |
c++;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
field_length = oggz_comment_len (comment->value);
|
|
Packit |
a38265 |
memcpy (c, comment->value, MIN (field_length, remaining));
|
|
Packit |
a38265 |
c += field_length; remaining -= field_length;
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (remaining <= 0) return actual_length;
|
|
Packit |
a38265 |
*c = 0x01;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return actual_length;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* NB. Public use of this function is deprecated; the simpler
|
|
Packit |
a38265 |
* oggz_comments_generate() automatically determines the packet_type */
|
|
Packit |
a38265 |
ogg_packet *
|
|
Packit |
a38265 |
oggz_comment_generate(OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
OggzStreamContent packet_type,
|
|
Packit |
a38265 |
int FLAC_final_metadata_block)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
ogg_packet *c_packet;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
unsigned char *buffer;
|
|
Packit |
a38265 |
unsigned const char *preamble;
|
|
Packit |
a38265 |
long preamble_length, comment_length, buf_size;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Some types use preambles in the comment packet. FLAC is notable;
|
|
Packit |
a38265 |
n9-32 should contain the length of the comment data as 24bit unsigned
|
|
Packit |
a38265 |
BE, and the first octet should be ORed with 0x80 if this is the last
|
|
Packit |
a38265 |
(only) metadata block. Any user doing FLAC has to know how to do the
|
|
Packit |
a38265 |
encapsulation anyway. */
|
|
Packit |
a38265 |
const unsigned char preamble_vorbis[7] =
|
|
Packit |
a38265 |
{0x03, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73};
|
|
Packit |
a38265 |
const unsigned char preamble_theora[7] =
|
|
Packit |
a38265 |
{0x81, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x61};
|
|
Packit |
a38265 |
const unsigned char preamble_flac[4] =
|
|
Packit |
a38265 |
{0x04, 0x00, 0x00, 0x00};
|
|
Packit |
a38265 |
const unsigned char preamble_kate[9] =
|
|
Packit |
a38265 |
{0x81, 0x6b, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00};
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
switch(packet_type) {
|
|
Packit |
a38265 |
case OGGZ_CONTENT_VORBIS:
|
|
Packit |
a38265 |
preamble_length = sizeof preamble_vorbis;
|
|
Packit |
a38265 |
preamble = preamble_vorbis;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_THEORA:
|
|
Packit |
a38265 |
preamble_length = sizeof preamble_theora;
|
|
Packit |
a38265 |
preamble = preamble_theora;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_FLAC:
|
|
Packit |
a38265 |
preamble_length = sizeof preamble_flac;
|
|
Packit |
a38265 |
preamble = preamble_flac;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_KATE:
|
|
Packit |
a38265 |
preamble_length = sizeof preamble_kate;
|
|
Packit |
a38265 |
preamble = preamble_kate;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_PCM:
|
|
Packit |
a38265 |
case OGGZ_CONTENT_SPEEX:
|
|
Packit |
a38265 |
preamble_length = 0;
|
|
Packit |
a38265 |
preamble = 0;
|
|
Packit |
a38265 |
/* No preamble for these */
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
default:
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
comment_length = oggz_comments_encode (oggz, serialno, 0, 0);
|
|
Packit |
a38265 |
if(comment_length <= 0) {
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
buf_size = preamble_length + comment_length;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if(packet_type == OGGZ_CONTENT_FLAC && comment_length >= 0x00ffffff) {
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
c_packet = oggz_malloc(sizeof *c_packet);
|
|
Packit |
a38265 |
if(c_packet) {
|
|
Packit |
a38265 |
memset(c_packet, 0, sizeof *c_packet);
|
|
Packit |
a38265 |
c_packet->packetno = 1;
|
|
Packit |
a38265 |
c_packet->packet = oggz_malloc(buf_size);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if(c_packet && c_packet->packet) {
|
|
Packit |
a38265 |
buffer = c_packet->packet;
|
|
Packit |
a38265 |
if(preamble_length) {
|
|
Packit |
a38265 |
memcpy(buffer, preamble, preamble_length);
|
|
Packit |
a38265 |
if(packet_type == OGGZ_CONTENT_FLAC) {
|
|
Packit |
a38265 |
/* Use comment_length-1 as we will be stripping the Vorbis
|
|
Packit |
a38265 |
framing byte. */
|
|
Packit |
a38265 |
/* MACRO */
|
|
Packit |
a38265 |
writeint24be(c_packet->packet, 1, (comment_length-1) );
|
|
Packit |
a38265 |
if(FLAC_final_metadata_block)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
c_packet->packet[0] |= 0x80;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
buffer += preamble_length;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
oggz_comments_encode (oggz, serialno, buffer, comment_length);
|
|
Packit |
a38265 |
c_packet->bytes = buf_size;
|
|
Packit |
a38265 |
/* The framing byte for Vorbis shouldn't affect any of the other
|
|
Packit |
a38265 |
types, but strip it anyway. */
|
|
Packit |
a38265 |
if(packet_type != OGGZ_CONTENT_VORBIS)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
c_packet->bytes -= 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
oggz_free(c_packet);
|
|
Packit |
a38265 |
c_packet = 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return c_packet;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* In Flac, OggPCM, Speex, Theora Vorbis, and Kate the comment packet will
|
|
Packit |
a38265 |
be second in the stream, i.e. packetno=1, and it will have granulepos=0 */
|
|
Packit |
a38265 |
ogg_packet *
|
|
Packit |
a38265 |
oggz_comments_generate(OGGZ * oggz, long serialno,
|
|
Packit |
a38265 |
int FLAC_final_metadata_block)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OggzStreamContent packet_type;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
packet_type = oggz_stream_get_content (oggz, serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return oggz_comment_generate (oggz, serialno, packet_type,
|
|
Packit |
a38265 |
FLAC_final_metadata_block);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
void oggz_packet_destroy(ogg_packet *packet) {
|
|
Packit |
a38265 |
if(packet) {
|
|
Packit |
a38265 |
if(packet->packet)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
oggz_free(packet->packet);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
oggz_free(packet);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
return;
|
|
Packit |
a38265 |
}
|