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
38typedef struct VC_CONTAINER_IO_MODULE_T
39{
40 FILE *stream;
41
42} VC_CONTAINER_IO_MODULE_T;
43
44VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *, const char *,
45 VC_CONTAINER_IO_MODE_T );
46
47/*****************************************************************************/
48static VC_CONTAINER_STATUS_T io_file_close( VC_CONTAINER_IO_T *p_ctx )
49{
50 VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
51 fclose(module->stream);
52 free(module);
53 return VC_CONTAINER_SUCCESS;
54}
55
56/*****************************************************************************/
57static size_t io_file_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
58{
59 size_t ret = fread(buffer, 1, size, p_ctx->module->stream);
60 if(ret != size)
61 {
62 /* Sanity check return value. Some platforms (e.g. Android) can return -1 */
63 if( ((int)ret) < 0 ) ret = 0;
64
65 if( feof(p_ctx->module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
66 else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
67 }
68 return ret;
69}
70
71/*****************************************************************************/
72static size_t io_file_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
73{
74 return fwrite(buffer, 1, size, p_ctx->module->stream);
75}
76
77/*****************************************************************************/
78static VC_CONTAINER_STATUS_T io_file_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
79{
80 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
81 int ret;
82
83 //FIXME: large file support
84#ifdef _VIDEOCORE
85 extern int fseek64(FILE *fp, int64_t offset, int whence);
86 ret = fseek64(p_ctx->module->stream, offset, SEEK_SET);
87#else
88 if (offset > (int64_t)UINT_MAX)
89 {
90 p_ctx->status = VC_CONTAINER_ERROR_EOS;
91 return VC_CONTAINER_ERROR_EOS;
92 }
93 ret = fseek(p_ctx->module->stream, (long)offset, SEEK_SET);
94#endif
95 if(ret)
96 {
97 if( feof(p_ctx->module->stream) ) status = VC_CONTAINER_ERROR_EOS;
98 else status = VC_CONTAINER_ERROR_FAILED;
99 }
100
101 p_ctx->status = status;
102 return status;
103}
104
105/*****************************************************************************/
106VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *p_ctx,
107 const char *unused, VC_CONTAINER_IO_MODE_T mode )
108{
109 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
110 VC_CONTAINER_IO_MODULE_T *module = 0;
111 const char *psz_mode = mode == VC_CONTAINER_IO_MODE_WRITE ? "wb+" : "rb";
112 const char *uri = p_ctx->uri;
113 FILE *stream = 0;
114 VC_CONTAINER_PARAM_UNUSED(unused);
115
116 if(vc_uri_path(p_ctx->uri_parts))
117 uri = vc_uri_path(p_ctx->uri_parts);
118
119 stream = fopen(uri, psz_mode);
120 if(!stream) { status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
121
122 /* Turn off buffering. The container layer will provide its own cache */
123 setvbuf(stream, NULL, _IONBF, 0);
124
125 module = malloc( sizeof(*module) );
126 if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
127 memset(module, 0, sizeof(*module));
128
129 p_ctx->module = module;
130 module->stream = stream;
131 p_ctx->pf_close = io_file_close;
132 p_ctx->pf_read = io_file_read;
133 p_ctx->pf_write = io_file_write;
134 p_ctx->pf_seek = io_file_seek;
135
136 if(mode == VC_CONTAINER_IO_MODE_WRITE)
137 {
138 p_ctx->max_size = (1UL<<31)-1; /* For now limit to 2GB */
139 }
140 else
141 {
142 //FIXME: large file support, platform-specific file size
143 fseek(p_ctx->module->stream, 0, SEEK_END);
144 p_ctx->size = ftell(p_ctx->module->stream);
145 fseek(p_ctx->module->stream, 0, SEEK_SET);
146 }
147
148 p_ctx->capabilities = VC_CONTAINER_IO_CAPS_NO_CACHING;
149 return VC_CONTAINER_SUCCESS;
150
151 error:
152 if(stream) fclose(stream);
153 return status;
154}
155