Code Coverage Report for src/api/open-buffer.c


Hit Total Coverage
Lines: 32 32 100.0%
Branches: 90 90 100.0%

1 /*
2 * libnogg: a decoder library for Ogg Vorbis streams
3 * Copyright (c) 2014-2023 Andrew Church <achurch@achurch.org>
4 *
5 * This software may be copied and redistributed under certain conditions;
6 * see the file "COPYING" in the source code distribution for details.
7 * NO WARRANTY is provided with this software.
8 */
9
10 #include "include/nogg.h"
11 #include "src/common.h"
12 #include "src/util/open.h"
13
14 #include <stdlib.h>
15 #include <string.h>
16
17 /*************************************************************************/
18 /******************** Buffer data type and callbacks *********************/
19 /*************************************************************************/
20
21 /* The argument to each of these callbacks is the stream handle itself. */
22
23 static int64_t buffer_length(void *opaque)
24 {
25 vorbis_t *vorbis = (vorbis_t *)opaque;
26 return vorbis->data_length;
27 }
28
29 static int64_t buffer_tell(void *opaque)
30 {
31 vorbis_t *vorbis = (vorbis_t *)opaque;
32 return vorbis->buffer_read_pos;
33 }
34
35 static void buffer_seek(void *opaque, int64_t offset)
36 {
37 vorbis_t *vorbis = (vorbis_t *)opaque;
38 vorbis->buffer_read_pos = offset;
39 }
40
41 static int32_t buffer_read(void *opaque, void *buffer, int32_t length)
42 {
43 vorbis_t *vorbis = (vorbis_t *)opaque;
44 (18/18) if (length > vorbis->data_length - vorbis->buffer_read_pos) {
45 length = (int32_t)(vorbis->data_length - vorbis->buffer_read_pos);
46 }
47 memcpy(buffer, vorbis->buffer_data + vorbis->buffer_read_pos, length);
48 vorbis->buffer_read_pos += length;
49 return length;
50 }
51
52 static const vorbis_callbacks_t buffer_callbacks = {
53 .length = buffer_length,
54 .tell = buffer_tell,
55 .seek = buffer_seek,
56 .read = buffer_read,
57 };
58
59 /*************************************************************************/
60 /*************************** Interface routine ***************************/
61 /*************************************************************************/
62
63 vorbis_t *vorbis_open_buffer(
64 const void *buffer, int64_t length, unsigned int options,
65 vorbis_error_t *error_ret)
66 {
67 (36/36) if (!buffer || length < 0) {
68 (18/18) if (error_ret) {
69 *error_ret = VORBIS_ERROR_INVALID_ARGUMENT;
70 }
71 return NULL;
72 }
73
74 /* We pass the stream handle as the opaque callback parameter, but
75 * that leads to a chicken-and-egg problem: open_callbacks() needs
76 * the callback parameter to read from the stream, but we don't know
77 * ahead of time where the stream handle will be allocated. We get
78 * around this by setting up a dummy handle on the stack with just the
79 * fields needed by the callbacks, then modify the actual handle after
80 * the open succeeds. */
81 vorbis_t dummy;
82 dummy.buffer_data = buffer;
83 dummy.buffer_read_pos = 0;
84 dummy.data_length = length;
85
86 vorbis_t *handle = open_common(
87 &(open_params_t){.callbacks = &buffer_callbacks,
88 .callback_data = &dummy,
89 .options = options,
90 .packet_mode = false},
91 error_ret);
92 (18/18) if (handle) {
93 handle->callback_data = handle;
94 handle->buffer_data = dummy.buffer_data;
95 handle->buffer_read_pos = dummy.buffer_read_pos;
96 }
97
98 return handle;
99 }
100
101 /*************************************************************************/
102 /*************************************************************************/