1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <stdlib.h>
29#include <string.h>
30#include <stdio.h>
31#include <limits.h>
32
33#include "containers/containers.h"
34#include "containers/core/containers_common.h"
35#include "containers/core/containers_io.h"
36#include "containers/core/containers_uri.h"
37
38/** Native byte order word */
39#define NATIVE_BYTE_ORDER 0x50415753
40/** Reverse of native byte order - need to swap bytes around */
41#define SWAP_BYTE_ORDER 0x53574150
42
43typedef struct VC_CONTAINER_IO_MODULE_T
44{
45 FILE *stream;
46 bool is_native_order;
47} VC_CONTAINER_IO_MODULE_T;
48
49/** List of recognised schemes.
50 * Note: always use lower case for the scheme name. */
51static const char * recognised_schemes[] = {
52 "rtp", "rtppkt", "rtsp", "rtsppkt", "pktfile",
53};
54
55VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *, const char *,
56 VC_CONTAINER_IO_MODE_T );
57
58/*****************************************************************************/
59static bool recognise_scheme(const char *scheme)
60{
61 size_t ii;
62
63 if (!scheme)
64 return false;
65
66 for (ii = 0; ii < countof(recognised_schemes); ii++)
67 {
68 if (strcmp(recognised_schemes[ii], scheme) == 0)
69 return true;
70 }
71
72 return false;
73}
74
75/*****************************************************************************/
76static uint32_t swap_byte_order( uint32_t value )
77{
78 /* Reverse the order of the bytes in the word */
79 return ((value << 24) | ((value & 0xFF00) << 8) | ((value >> 8) & 0xFF00) | (value >> 24));
80}
81
82/*****************************************************************************/
83static VC_CONTAINER_STATUS_T io_pktfile_close( VC_CONTAINER_IO_T *p_ctx )
84{
85 VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
86 fclose(module->stream);
87 free(module);
88 return VC_CONTAINER_SUCCESS;
89}
90
91/*****************************************************************************/
92static size_t io_pktfile_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
93{
94 VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
95 uint32_t length = 0;
96 size_t ret;
97
98 ret = fread(&length, 1, sizeof(length), module->stream);
99 if (ret != sizeof(length))
100 {
101 if( feof(module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
102 else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
103 return 0;
104 }
105
106 if (!module->is_native_order)
107 length = swap_byte_order(length);
108
109 if (length > 1<<20)
110 {
111 p_ctx->status = VC_CONTAINER_ERROR_FAILED;
112 return 0;
113 }
114
115 if (size > length)
116 size = length;
117 ret = fread(buffer, 1, size, module->stream);
118 if(ret != size)
119 {
120 if( feof(module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
121 else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
122 }
123 else if (length > size)
124 {
125 /* Not enough space to read all the packet, so skip to the next one. */
126 length -= size;
127 vc_container_assert((long)length > 0);
128 fseek(module->stream, (long)length, SEEK_CUR);
129 }
130
131 return ret;
132}
133
134/*****************************************************************************/
135static size_t io_pktfile_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
136{
137 uint32_t size_word;
138 size_t ret;
139
140 if (size >= 0xFFFFFFFFUL)
141 size_word = 0xFFFFFFFFUL;
142 else
143 size_word = (uint32_t)size;
144
145 ret = fwrite(&size_word, 1, sizeof(size_word), p_ctx->module->stream);
146 if (ret != sizeof(size_word))
147 {
148 p_ctx->status = VC_CONTAINER_ERROR_FAILED;
149 return 0;
150 }
151
152 ret = fwrite(buffer, 1, size_word, p_ctx->module->stream);
153 if (ret != size_word)
154 p_ctx->status = VC_CONTAINER_ERROR_FAILED;
155 if (fflush(p_ctx->module->stream) != 0)
156 p_ctx->status = VC_CONTAINER_ERROR_FAILED;
157
158 return ret;
159}
160
161/*****************************************************************************/
162static FILE *open_file(VC_CONTAINER_IO_T *ctx, VC_CONTAINER_IO_MODE_T mode,
163 VC_CONTAINER_STATUS_T *p_status)
164{
165 const char *psz_mode = mode == VC_CONTAINER_IO_MODE_WRITE ? "wb+" : "rb";
166 FILE *stream = 0;
167 const char *port, *path;
168
169 /* Treat empty port or path strings as not defined */
170 port = vc_uri_port(ctx->uri_parts);
171 if (port && !*port)
172 port = NULL;
173
174 path = vc_uri_path(ctx->uri_parts);
175 if (path && !*path)
176 path = NULL;
177
178 /* Require the port to be undefined and the path to be defined */
179 if (port || !path) { *p_status = VC_CONTAINER_ERROR_URI_OPEN_FAILED; goto error; }
180
181 if (!recognise_scheme(vc_uri_scheme(ctx->uri_parts)))
182 { *p_status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
183
184 stream = fopen(path, psz_mode);
185 if(!stream) { *p_status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
186
187 *p_status = VC_CONTAINER_SUCCESS;
188 return stream;
189
190error:
191 return NULL;
192}
193
194/*****************************************************************************/
195static VC_CONTAINER_STATUS_T write_byte_order(FILE *stream)
196{
197 /* Simple byte order header word */
198 uint32_t value = NATIVE_BYTE_ORDER;
199
200 if (fwrite(&value, 1, sizeof(value), stream) != sizeof(value))
201 return VC_CONTAINER_ERROR_OUT_OF_SPACE;
202
203 return VC_CONTAINER_SUCCESS;
204}
205
206/*****************************************************************************/
207static VC_CONTAINER_STATUS_T read_byte_order(FILE *stream, bool *is_native)
208{
209 uint32_t value;
210
211 if (fread(&value, 1, sizeof(value), stream) != sizeof(value))
212 return VC_CONTAINER_ERROR_EOS;
213
214 switch (value)
215 {
216 case NATIVE_BYTE_ORDER: *is_native = true; break;
217 case SWAP_BYTE_ORDER: *is_native = false; break;
218 default: return VC_CONTAINER_ERROR_CORRUPTED;
219 }
220
221 return VC_CONTAINER_SUCCESS;
222}
223
224/*****************************************************************************/
225VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *p_ctx,
226 const char *unused, VC_CONTAINER_IO_MODE_T mode )
227{
228 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
229 VC_CONTAINER_IO_MODULE_T *module = 0;
230 FILE *stream = 0;
231 bool is_native_order = true;
232 VC_CONTAINER_PARAM_UNUSED(unused);
233
234 stream = open_file(p_ctx, mode, &status);
235 if (status != VC_CONTAINER_SUCCESS) goto error;
236
237 if (mode == VC_CONTAINER_IO_MODE_WRITE)
238 status = write_byte_order(stream);
239 else
240 status = read_byte_order(stream, &is_native_order);
241 if (status != VC_CONTAINER_SUCCESS) goto error;
242
243 module = malloc( sizeof(*module) );
244 if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
245 memset(module, 0, sizeof(*module));
246
247 p_ctx->module = module;
248 module->stream = stream;
249 module->is_native_order = is_native_order;
250 p_ctx->pf_close = io_pktfile_close;
251 p_ctx->pf_read = io_pktfile_read;
252 p_ctx->pf_write = io_pktfile_write;
253
254 /* Do not allow caching by I/O core, as this will merge packets in the cache. */
255 p_ctx->capabilities = VC_CONTAINER_IO_CAPS_CANT_SEEK;
256 return VC_CONTAINER_SUCCESS;
257
258error:
259 if(stream) fclose(stream);
260 return status;
261}
262