1 /*****************************************************************
2 |
3 |    AP4 - Android File Byte Stream implementation
4 |
5 |    Copyright 2002-2016 Axiomatic Systems, LLC
6 |
7 |
8 |    This file is part of Bento4/AP4 (MP4 Atom Processing Library).
9 |
10 |    Unless you have obtained Bento4 under a difference license,
11 |    this version of Bento4 is Bento4|GPL.
12 |    Bento4|GPL is free software; you can redistribute it and/or modify
13 |    it under the terms of the GNU General Public License as published by
14 |    the Free Software Foundation; either version 2, or (at your option)
15 |    any later version.
16 |
17 |    Bento4|GPL is distributed in the hope that it will be useful,
18 |    but WITHOUT ANY WARRANTY; without even the implied warranty of
19 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 |    GNU General Public License for more details.
21 |
22 |    You should have received a copy of the GNU General Public License
23 |    along with Bento4|GPL; see the file COPYING.  If not, write to the
24 |    Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 |    02111-1307, USA.
26 |
27 ****************************************************************/
28 
29 /*----------------------------------------------------------------------
30 |   includes
31 +---------------------------------------------------------------------*/
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 
39 #include "Ap4FileByteStream.h"
40 
41 /*----------------------------------------------------------------------
42 |   AP4_AndroidFileByteStream
43 +---------------------------------------------------------------------*/
44 class AP4_AndroidFileByteStream: public AP4_ByteStream
45 {
46 public:
47     // class methods
48     static AP4_Result Create(AP4_FileByteStream*      delegator,
49                              const char*              name,
50                              AP4_FileByteStream::Mode mode,
51                              AP4_ByteStream*&         stream);
52 
53     // methods
54     AP4_AndroidFileByteStream(AP4_FileByteStream* delegator,
55                               int                 fd,
56                               AP4_LargeSize       size);
57 
58     ~AP4_AndroidFileByteStream();
59 
60     // AP4_ByteStream methods
61     AP4_Result ReadPartial(void*     buffer,
62                            AP4_Size  bytesToRead,
63                            AP4_Size& bytesRead);
64     AP4_Result WritePartial(const void* buffer,
65                             AP4_Size    bytesToWrite,
66                             AP4_Size&   bytesWritten);
67     AP4_Result Seek(AP4_Position position);
68     AP4_Result Tell(AP4_Position& position);
69     AP4_Result GetSize(AP4_LargeSize& size);
70     AP4_Result Flush();
71 
72     // AP4_Referenceable methods
73     void AddReference();
74     void Release();
75 
76 private:
77     // members
78     AP4_ByteStream* m_Delegator;
79     AP4_Cardinal    m_ReferenceCount;
80     int             m_FD;
81     AP4_Position    m_Position;
82     AP4_LargeSize   m_Size;
83 };
84 
85 /*----------------------------------------------------------------------
86 |   AP4_AndroidFileByteStream::Create
87 +---------------------------------------------------------------------*/
88 AP4_Result
Create(AP4_FileByteStream * delegator,const char * name,AP4_FileByteStream::Mode mode,AP4_ByteStream * & stream)89 AP4_AndroidFileByteStream::Create(AP4_FileByteStream*      delegator,
90                                   const char*              name,
91                                   AP4_FileByteStream::Mode mode,
92                                   AP4_ByteStream*&         stream)
93 {
94     // default value
95     stream = NULL;
96 
97     // check arguments
98     if (name == NULL) return AP4_ERROR_INVALID_PARAMETERS;
99 
100     // open the file
101     int fd = 0;
102     AP4_Position size = 0;
103     if (!strcmp(name, "-stdin")) {
104         fd = STDIN_FILENO;
105     } else if (!strcmp(name, "-stdout")) {
106         fd = STDOUT_FILENO;
107     } else if (!strcmp(name, "-stderr")) {
108         fd = STDERR_FILENO;
109     } else {
110         int open_flags = 0;
111         int create_perm = 0;
112         switch (mode) {
113           case AP4_FileByteStream::STREAM_MODE_READ:
114             open_flags = O_RDONLY;
115             break;
116 
117           case AP4_FileByteStream::STREAM_MODE_WRITE:
118             open_flags = O_RDWR | O_CREAT | O_TRUNC;
119             break;
120 
121           case AP4_FileByteStream::STREAM_MODE_READ_WRITE:
122             open_flags = O_RDWR;
123             break;
124 
125           default:
126             return AP4_ERROR_INVALID_PARAMETERS;
127         }
128 
129         fd = open(name, open_flags, create_perm);
130         if (fd < 0) {
131             if (errno == ENOENT) {
132                 return AP4_ERROR_NO_SUCH_FILE;
133             } else if (errno == EACCES) {
134                 return AP4_ERROR_PERMISSION_DENIED;
135             } else {
136                 return AP4_ERROR_CANNOT_OPEN_FILE;
137             }
138         }
139 
140         // get the size
141         struct stat info;
142         if (stat(name, &info) == 0) {
143             size = info.st_size;
144         }
145     }
146 
147     stream = new AP4_AndroidFileByteStream(delegator, fd, size);
148     return AP4_SUCCESS;
149 }
150 
151 /*----------------------------------------------------------------------
152 |   AP4_AndroidFileByteStream::AP4_AndroidFileByteStream
153 +---------------------------------------------------------------------*/
AP4_AndroidFileByteStream(AP4_FileByteStream * delegator,int fd,AP4_LargeSize size)154 AP4_AndroidFileByteStream::AP4_AndroidFileByteStream(AP4_FileByteStream* delegator,
155                                                      int                 fd,
156                                                      AP4_LargeSize       size) :
157     m_Delegator(delegator),
158     m_ReferenceCount(1),
159     m_FD(fd),
160     m_Position(0),
161     m_Size(size)
162 {
163 }
164 
165 /*----------------------------------------------------------------------
166 |   AP4_AndroidFileByteStream::~AP4_AndroidFileByteStream
167 +---------------------------------------------------------------------*/
~AP4_AndroidFileByteStream()168 AP4_AndroidFileByteStream::~AP4_AndroidFileByteStream()
169 {
170     if (m_FD && m_FD != STDERR_FILENO && m_FD != STDOUT_FILENO && m_FD != STDERR_FILENO) {
171         close(m_FD);
172     }
173 }
174 
175 /*----------------------------------------------------------------------
176 |   AP4_AndroidFileByteStream::AddReference
177 +---------------------------------------------------------------------*/
178 void
AddReference()179 AP4_AndroidFileByteStream::AddReference()
180 {
181     m_ReferenceCount++;
182 }
183 
184 /*----------------------------------------------------------------------
185 |   AP4_AndroidFileByteStream::Release
186 +---------------------------------------------------------------------*/
187 void
Release()188 AP4_AndroidFileByteStream::Release()
189 {
190     if (--m_ReferenceCount == 0) {
191         if (m_Delegator) {
192             delete m_Delegator;
193         } else {
194             delete this;
195         }
196     }
197 }
198 
199 /*----------------------------------------------------------------------
200 |   AP4_AndroidFileByteStream::ReadPartial
201 +---------------------------------------------------------------------*/
202 AP4_Result
ReadPartial(void * buffer,AP4_Size bytes_to_read,AP4_Size & bytes_read)203 AP4_AndroidFileByteStream::ReadPartial(void*     buffer,
204                                        AP4_Size  bytes_to_read,
205                                        AP4_Size& bytes_read)
206 {
207     ssize_t nb_read = read(m_FD, buffer, bytes_to_read);
208 
209     if (nb_read > 0) {
210         bytes_read = (AP4_Size)nb_read;
211         m_Position += nb_read;
212         return AP4_SUCCESS;
213     } else if (nb_read == 0) {
214         bytes_read = 0;
215         return AP4_ERROR_EOS;
216     } else {
217         bytes_read = 0;
218         return AP4_ERROR_READ_FAILED;
219     }
220 }
221 
222 /*----------------------------------------------------------------------
223 |   AP4_AndroidFileByteStream::WritePartial
224 +---------------------------------------------------------------------*/
225 AP4_Result
WritePartial(const void * buffer,AP4_Size bytes_to_write,AP4_Size & bytes_written)226 AP4_AndroidFileByteStream::WritePartial(const void* buffer,
227                                         AP4_Size    bytes_to_write,
228                                         AP4_Size&   bytes_written)
229 {
230     if (bytes_to_write == 0) {
231         bytes_written = 0;
232         return AP4_SUCCESS;
233     }
234     ssize_t nb_written = write(m_FD, buffer, bytes_to_write);
235 
236     if (nb_written > 0) {
237         bytes_written = (AP4_Size)nb_written;
238         m_Position += nb_written;
239         return AP4_SUCCESS;
240     } else {
241         bytes_written = 0;
242         return AP4_ERROR_WRITE_FAILED;
243     }
244 }
245 
246 /*----------------------------------------------------------------------
247 |   AP4_AndroidFileByteStream::Seek
248 +---------------------------------------------------------------------*/
249 AP4_Result
Seek(AP4_Position position)250 AP4_AndroidFileByteStream::Seek(AP4_Position position)
251 {
252     // shortcut
253     if (position == m_Position) return AP4_SUCCESS;
254 
255     off64_t result = lseek64(m_FD, position, SEEK_SET);
256     if (result >= 0) {
257         m_Position = position;
258         return AP4_SUCCESS;
259     } else {
260         return AP4_FAILURE;
261     }
262 }
263 
264 /*----------------------------------------------------------------------
265 |   AP4_AndroidFileByteStream::Tell
266 +---------------------------------------------------------------------*/
267 AP4_Result
Tell(AP4_Position & position)268 AP4_AndroidFileByteStream::Tell(AP4_Position& position)
269 {
270     position = m_Position;
271     return AP4_SUCCESS;
272 }
273 
274 /*----------------------------------------------------------------------
275 |   AP4_AndroidFileByteStream::GetSize
276 +---------------------------------------------------------------------*/
277 AP4_Result
GetSize(AP4_LargeSize & size)278 AP4_AndroidFileByteStream::GetSize(AP4_LargeSize& size)
279 {
280     size = m_Size;
281     return AP4_SUCCESS;
282 }
283 
284 /*----------------------------------------------------------------------
285 |   AP4_AndroidFileByteStream::Flush
286 +---------------------------------------------------------------------*/
287 AP4_Result
Flush()288 AP4_AndroidFileByteStream::Flush()
289 {
290     return AP4_SUCCESS;
291 }
292 
293 /*----------------------------------------------------------------------
294 |   AP4_FileByteStream::Create
295 +---------------------------------------------------------------------*/
296 AP4_Result
Create(const char * name,AP4_FileByteStream::Mode mode,AP4_ByteStream * & stream)297 AP4_FileByteStream::Create(const char*              name,
298                            AP4_FileByteStream::Mode mode,
299                            AP4_ByteStream*&         stream)
300 {
301     return AP4_AndroidFileByteStream::Create(NULL, name, mode, stream);
302 }
303 
304 #if !defined(AP4_CONFIG_NO_EXCEPTIONS)
305 /*----------------------------------------------------------------------
306 |   AP4_FileByteStream::AP4_FileByteStream
307 +---------------------------------------------------------------------*/
AP4_FileByteStream(const char * name,AP4_FileByteStream::Mode mode)308 AP4_FileByteStream::AP4_FileByteStream(const char*              name,
309                                        AP4_FileByteStream::Mode mode)
310 {
311     AP4_ByteStream* stream = NULL;
312     AP4_Result result = AP4_AndroidFileByteStream::Create(this, name, mode, stream);
313     if (AP4_FAILED(result)) throw AP4_Exception(result);
314 
315     m_Delegate = stream;
316 }
317 #endif
318 
319 
320 
321 
322 
323 
324 
325 
326 
327 
328 
329