1 /*****************************************************************************
2  *
3  * Copyright (c) 2008-2010, CoreCodec, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of CoreCodec, Inc. nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CoreCodec, Inc. ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL CoreCodec, Inc. BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  ****************************************************************************/
29 
30 #include "file.h"
31 
32 //TODO: include from somewhere else or not depend on them at all
33 #ifdef CONFIG_BLOCK_RDONLY
34 #include "common.h"
35 #endif
36 //end TODO
37 
DummySkip(void * p,intptr_t * Skip)38 static err_t DummySkip(void* p, intptr_t* Skip)
39 {
40     uint8_t Buf[1024];
41     size_t Readed;
42     intptr_t n = *Skip;
43     err_t Err = ERR_NONE;
44     while (n>0 && Err == ERR_NONE)
45     {
46         Err = Stream_Read(p,Buf,min(n,(intptr_t)sizeof(Buf)),&Readed);
47         n -= Readed;
48     }
49     *Skip = n;
50     return Err;
51 }
52 
DummyOpen(void * UNUSED_PARAM (p),const tchar_t * Name,int UNUSED_PARAM (Flags))53 static err_t DummyOpen(void* UNUSED_PARAM(p),const tchar_t* Name, int UNUSED_PARAM(Flags))
54 {
55     if (Name)
56         return ERR_NOT_SUPPORTED;
57     return ERR_NONE;
58 }
59 
DummyDuplicate(void * p,int Flags)60 static stream* DummyDuplicate(void* p,int Flags)
61 {
62     tchar_t URL[MAXPATHFULL];
63 
64 	if (Node_Get(p,STREAM_URL,URL,sizeof(URL)) != ERR_NONE)
65 		return NULL;
66 
67     return StreamOpen(p,URL,Flags);
68 }
69 
DummyBlocking(void * UNUSED_PARAM (p),bool_t State)70 static err_t DummyBlocking(void* UNUSED_PARAM(p),bool_t State)
71 {
72     if (!State)
73         return ERR_NOT_SUPPORTED;
74     return ERR_NONE;
75 }
76 
DummyRead(void * UNUSED_PARAM (p),void * UNUSED_PARAM (Data),size_t UNUSED_PARAM (Size),size_t * Readed)77 static err_t DummyRead(void* UNUSED_PARAM(p),void* UNUSED_PARAM(Data),size_t UNUSED_PARAM(Size),size_t* Readed)
78 {
79     if (Readed)
80         *Readed = 0;
81     return ERR_NOT_SUPPORTED;
82 }
83 
DummyReadOneOrMore(void * p,void * Data,size_t Size,size_t * Readed)84 static err_t DummyReadOneOrMore(void* p,void* Data,size_t Size,size_t* Readed)
85 {
86 	return Stream_Read(p,Data,Size,Readed);
87 }
88 
DummySeek(void * UNUSED_PARAM (p),filepos_t UNUSED_PARAM (Pos),int UNUSED_PARAM (SeekMode))89 static filepos_t DummySeek(void* UNUSED_PARAM(p),filepos_t UNUSED_PARAM(Pos),int UNUSED_PARAM(SeekMode))
90 {
91     return INVALID_FILEPOS_T;
92 }
93 
DummyWrite(void * UNUSED_PARAM (This),const void * UNUSED_PARAM (Data),size_t UNUSED_PARAM (Size),size_t * Written)94 static err_t DummyWrite(void* UNUSED_PARAM(This),const void* UNUSED_PARAM(Data),size_t UNUSED_PARAM(Size), size_t* Written)
95 {
96     if (Written)
97         *Written = 0;
98     return ERR_NOT_SUPPORTED;
99 }
100 
DummyOpenDir(void * UNUSED_PARAM (p),const tchar_t * UNUSED_PARAM (URL),int UNUSED_PARAM (Flags))101 static err_t DummyOpenDir(void* UNUSED_PARAM(p),const tchar_t* UNUSED_PARAM(URL), int UNUSED_PARAM(Flags))
102 {
103     return ERR_NOT_DIRECTORY;
104 }
105 
DummyEnumDir(void * UNUSED_PARAM (p),const tchar_t * UNUSED_PARAM (Exts),bool_t UNUSED_PARAM (ExtFilter),streamdir * UNUSED_PARAM (Item))106 static err_t DummyEnumDir(void* UNUSED_PARAM(p),const tchar_t* UNUSED_PARAM(Exts), bool_t UNUSED_PARAM(ExtFilter),streamdir* UNUSED_PARAM(Item))
107 {
108     return ERR_END_OF_FILE;
109 }
110 
DummyReadBlock(stream * p,block * Block,size_t Ofs,size_t Size,size_t * Readed)111 static err_t DummyReadBlock(stream* p,block* Block,size_t Ofs,size_t Size,size_t* Readed)
112 {
113 #ifdef CONFIG_BLOCK_RDONLY
114     uint8_t Buf[2048]; // MAX_NETWORK_PACKET has to fit...
115     err_t Err = ERR_NONE;
116     size_t Pos = 0;
117     size_t Left;
118 
119     while ((Left = (Size - Pos)) > 0)
120     {
121         if (Left > sizeof(Buf))
122             Left = sizeof(Buf);
123 
124 		Err = Stream_Read(p,Buf,Left,&Left);
125 		if (!Left)
126             break;
127 
128 		WriteBlock(Block,Ofs+Pos,Buf,Left);
129 		Pos += Left;
130 
131         if (Left < sizeof(Buf))
132             break;
133 	}
134 
135     if (Readed)
136         *Readed = Pos;
137 	return Err;
138 #else
139 	return Stream_Read(p,(uint8_t*)Block->Ptr+Ofs,Size,Readed);
140 #endif
141 }
142 
DummyWait(void * UNUSED_PARAM (p),bool_t UNUSED_PARAM (Read),streamselect * UNUSED_PARAM (Select))143 static err_t DummyWait(void* UNUSED_PARAM(p),bool_t UNUSED_PARAM(Read),streamselect* UNUSED_PARAM(Select))
144 {
145     return ERR_NOT_SUPPORTED;
146 }
147 
DummyFlush(void * UNUSED_PARAM (p))148 static err_t DummyFlush(void* UNUSED_PARAM(p))
149 {
150     return ERR_NOT_SUPPORTED;
151 }
152 
DummyResetReadTimeout(void * UNUSED_PARAM (p))153 static err_t DummyResetReadTimeout(void* UNUSED_PARAM(p))
154 {
155     return ERR_NOT_SUPPORTED;
156 }
157 
ProcessBlocking(void * p,bool_t State)158 static err_t ProcessBlocking(void* p,bool_t State)
159 {
160     stream* Input;
161     if (Node_GET(p,STREAMPROCESS_INPUT,&Input) == ERR_NONE && Input)
162         return Stream_Blocking(Input,State);
163     return DummyBlocking(p,State);
164 }
165 
ProcessWait(void * p,bool_t Read,streamselect * Select)166 static err_t ProcessWait(void* p,bool_t Read,streamselect* Select)
167 {
168     stream* Input;
169     if (Node_GET(p,STREAMPROCESS_INPUT,&Input) == ERR_NONE && Input)
170         return Stream_Wait(Input,Read,Select);
171     return ERR_NOT_SUPPORTED;
172 }
173 
META_START(Streams_Class,MEDIA_CLASS)174 META_START(Streams_Class,MEDIA_CLASS)
175 META_CLASS(FLAGS,CFLAG_ABSTRACT)
176 META_END_CONTINUE(NODE_CLASS)
177 
178 META_START_CONTINUE(STREAM_CLASS)
179 META_CLASS(VMT_SIZE,sizeof(stream_vmt))
180 META_CLASS(SIZE,sizeof(stream))
181 META_CLASS(FLAGS,CFLAG_ABSTRACT)
182 META_PARAM(TYPE,STREAM_KIND,TYPE_FOURCC|TFLAG_RDONLY)
183 META_PARAM(CUSTOM,STREAM_KIND,STREAM_KIND_LOCAL)
184 META_PARAM(NAME,STREAM_URL,T("URL"))
185 META_PARAM(TYPE,STREAM_URL,TYPE_STRING)
186 META_PARAM(NAME,STREAM_LENGTH,T("Length"))
187 META_PARAM(TYPE,STREAM_LENGTH,TYPE_FILEPOS)
188 META_PARAM(NAME,STREAM_FLAGS,T("Flags"))
189 META_PARAM(TYPE,STREAM_FLAGS,TYPE_INT)
190 META_PARAM(NAME,STREAM_CONTENTTYPE,T("ContentType"))
191 META_PARAM(TYPE,STREAM_CONTENTTYPE,TYPE_STRING|TFLAG_RDONLY)
192 META_PARAM(NAME,STREAM_PRAGMA_SEND,T("PragmaSet"))
193 META_PARAM(TYPE,STREAM_PRAGMA_SEND,TYPE_STRING|TFLAG_RDONLY)
194 META_PARAM(NAME,STREAM_PRAGMA_GET,T("PragmaGet"))
195 META_PARAM(TYPE,STREAM_PRAGMA_GET,TYPE_STRING|TFLAG_RDONLY)
196 META_PARAM(NAME,STREAM_META,T("Meta"))
197 META_PARAM(TYPE,STREAM_META,TYPE_META)
198 META_PARAM(NAME,STREAM_SCOUTING,T("Scouting"))
199 META_PARAM(TYPE,STREAM_SCOUTING,TYPE_BOOLEAN)
200 META_PARAM(NAME,STREAM_TIMEOUT,T("TimeOut"))
201 META_PARAM(TYPE,STREAM_TIMEOUT,TYPE_INT) // TODO: TYPE_SYSTICK
202 META_PARAM(TYPE,STREAM_DATE,TYPE_DATETIME)
203 META_PARAM(NAME,STREAM_FULL_URL,T("FullURL"))
204 META_PARAM(TYPE,STREAM_FULL_URL,TYPE_STRING)
205 META_PARAM(TYPE,STREAM_PLAYING,TYPE_BOOLEAN)
206 META_PARAM(TYPE,STREAM_ENUM_BASE,TYPE_STRING)
207 META_PARAM(TYPE,STREAM_TIME,TYPE_TICK)
208 META_PARAM(TYPE,STREAM_NATIVE_HANDLER,TYPE_PTR|TFLAG_RDONLY)
209 META_PARAM(TYPE,STREAM_CACHING,TYPE_BOOLEAN)
210 META_PARAM(TYPE,STREAM_USERNAME,TYPE_STRING)
211 META_DYNAMIC(TYPE_STRING,STREAM_USERNAME)
212 META_PARAM(TYPE,STREAM_PASSWORD,TYPE_STRING)
213 META_DYNAMIC(TYPE_STRING,STREAM_PASSWORD)
214 META_PARAM(TYPE,STREAM_PROXY_USERNAME,TYPE_STRING)
215 META_DYNAMIC(TYPE_STRING,STREAM_PROXY_USERNAME)
216 META_PARAM(TYPE,STREAM_PROXY_PASSWORD,TYPE_STRING)
217 META_DYNAMIC(TYPE_STRING,STREAM_PROXY_PASSWORD)
218 META_PARAM(TYPE,STREAM_CACHE_CLASS,TYPE_FOURCC|TFLAG_RDONLY)
219 META_VMT(TYPE_FUNC,stream_vmt,Open,DummyOpen)
220 META_VMT(TYPE_FUNC,stream_vmt,Duplicate,DummyDuplicate)
221 META_VMT(TYPE_FUNC,stream_vmt,Read,DummyRead)
222 META_VMT(TYPE_FUNC,stream_vmt,ReadOneOrMore,DummyReadOneOrMore)
223 META_VMT(TYPE_FUNC,stream_vmt,ReadBlock,DummyReadBlock)
224 META_VMT(TYPE_FUNC,stream_vmt,Write,DummyWrite)
225 META_VMT(TYPE_FUNC,stream_vmt,Seek,DummySeek)
226 META_VMT(TYPE_FUNC,stream_vmt,Blocking,DummyBlocking)
227 META_VMT(TYPE_FUNC,stream_vmt,OpenDir,DummyOpenDir)
228 META_VMT(TYPE_FUNC,stream_vmt,EnumDir,DummyEnumDir)
229 META_VMT(TYPE_FUNC,stream_vmt,Wait,DummyWait)
230 META_VMT(TYPE_FUNC,stream_vmt,Skip,DummySkip)
231 META_VMT(TYPE_FUNC,stream_vmt,Flush,DummyFlush)
232 META_VMT(TYPE_FUNC,stream_vmt,ResetReadTimeout,DummyResetReadTimeout)
233 META_END_CONTINUE(MEDIA_CLASS) // STREAMPROCESS_CLASS can have NODE_EXTS
234 
235 META_START_CONTINUE(STREAMPROCESS_CLASS)
236 META_CLASS(FLAGS,CFLAG_ABSTRACT)
237 META_PARAM(NAME,STREAMPROCESS_INPUT,T("Input"))
238 META_PARAM(TYPE,STREAMPROCESS_INPUT,TYPE_NODE)
239 META_PARAM(CLASS,STREAMPROCESS_INPUT,STREAM_CLASS)
240 META_VMT(TYPE_FUNC,stream_vmt,Blocking,ProcessBlocking)
241 META_VMT(TYPE_FUNC,stream_vmt,Wait,ProcessWait)
242 META_END(STREAM_CLASS)
243 
244 stream* StreamOpen(anynode *AnyNode, const tchar_t* Path, int Flags)
245 {
246 	stream* File = GetStream(AnyNode,Path,Flags);
247 	if (File)
248 	{
249 		err_t Err = Stream_Open(File,Path,Flags);
250         if (Err != ERR_NONE && Err != ERR_NEED_MORE_DATA)
251 		{
252 			NodeDelete((node*)File);
253 			File = NULL;
254 		}
255         else
256         {
257             stream* Buf;
258             if ((Flags & SFLAG_BUFFERED) && (Buf = (stream*)NodeCreate(AnyNode,BUFSTREAM_CLASS)) != NULL)
259             {
260                 Node_SET(Buf,BUFSTREAM_STREAM,&File);
261                 File = Buf;
262             }
263         }
264 	}
265 	return File;
266 }
267 
StreamClose(stream * File)268 void StreamClose(stream* File)
269 {
270 	NodeDelete((node*)File);
271 }
272 
StreamGenExts(anynode * AnyNode,array * Exts,fourcc_t ClassFilter,const tchar_t * TypeFilter)273 bool_t StreamGenExts(anynode* AnyNode,array* Exts, fourcc_t ClassFilter, const tchar_t* TypeFilter)
274 {
275 	fourcc_t* i;
276 	array List;
277     ArrayInit(Exts);
278 
279     if (TypeFilter && !TypeFilter[0])
280         TypeFilter = NULL;
281 
282 	NodeEnumClass(AnyNode,&List,ClassFilter);
283 	for (i=ARRAYBEGIN(List,fourcc_t);i!=ARRAYEND(List,fourcc_t);++i)
284 	{
285 		const tchar_t* s = NodeStr2(AnyNode,*i,NODE_EXTS);
286 		while (s && s[0])
287 		{
288             size_t n;
289             for (n=0;s[n] && s[n]!=';' && s[n]!=':';++n) {}
290 
291             if (!TypeFilter || (s[n]==':' && tcschr(TypeFilter,s[n+1])!=NULL))
292             {
293                 while (s[n] && s[n]!=';')
294                     ++n;
295 
296                 if (n)
297                 {
298                     if (!ARRAYEMPTY(*Exts))
299                         ArrayAppend(Exts,T(";"),sizeof(tchar_t),64);
300                     ArrayAppend(Exts,s,n*sizeof(tchar_t),64);
301                 }
302             }
303 
304             s = tcschr(s,';');
305             if (s) ++s;
306 		}
307 	}
308 	ArrayClear(&List);
309 
310     if (!ARRAYEMPTY(*Exts) && !ArrayAppend(Exts,T("\0"),sizeof(tchar_t),64))
311         ArrayClear(Exts);
312 
313     return !ARRAYEMPTY(*Exts);
314 }
315 
StreamExtType(anynode * AnyNode,fourcc_t ClassFilter,const tchar_t * Ext)316 char StreamExtType(anynode* AnyNode, fourcc_t ClassFilter, const tchar_t *Ext)
317 {
318     char Result = FTYPE_UNDEFINED;
319     tchar_t *s;
320     size_t i;
321     array List;
322     StreamGenExts(AnyNode,&List,ClassFilter,NULL);
323 
324     for (s=ARRAYBEGIN(List,tchar_t);s;)
325     {
326         for (i=0;s[i] && s[i]==Ext[i];i++) {}
327 
328         if (!Ext[i] && s[i] == ':')
329         {
330             Result = (char)s[i+1];
331             break;
332         }
333 
334         s = tcschr(s,';');
335         if (s) ++s;
336     }
337 
338     ArrayClear(&List);
339     return Result;
340 }
341 
GetStream(anynode * AnyNode,const tchar_t * URL,int Flags)342 stream* GetStream(anynode *AnyNode, const tchar_t* URL, int Flags)
343 {
344 	tchar_t Protocol[MAXPROTOCOL];
345 	stream* Stream = NULL;
346     fourcc_t FourCC;
347 
348     GetProtocol(URL,Protocol,TSIZEOF(Protocol),NULL);
349 
350     FourCC = NodeEnumClassStr(AnyNode,NULL,STREAM_CLASS,NODE_PROTOCOL,Protocol);
351 
352 #if defined(CONFIG_STREAM_CACHE)
353     if ((Flags & (SFLAG_NO_CACHING|SFLAG_WRONLY|SFLAG_CREATE))==0)
354         Stream = (stream*)NodeCreate(AnyNode,NodeClass_Meta(NodeContext_FindClass(AnyNode,FourCC),STREAM_CACHE_CLASS,META_PARAM_CUSTOM));
355 #endif
356 
357     if (!Stream)
358         Stream = (stream*)NodeCreate(AnyNode,FourCC);
359 
360     if (Stream && (Flags & SFLAG_NON_BLOCKING))
361         Stream_Blocking(Stream,0);
362 
363     if (!Stream && !(Flags & SFLAG_SILENT))
364     {
365 	    tcsupr(Protocol);
366 	    NodeReportError(AnyNode,NULL,ERR_ID,ERR_PROTO_NOT_FOUND,Protocol);
367     }
368 #if defined(CONFIG_DEBUGCHECKS)
369     if (Stream)
370         tcscpy_s(Stream->URL,TSIZEOF(Stream->URL),URL);
371 #endif
372 	return Stream;
373 }
374 
StreamProtocolPriority(anynode * AnyNode,const tchar_t * URL)375 int StreamProtocolPriority(anynode *AnyNode, const tchar_t* URL)
376 {
377 	tchar_t Protocol[MAXPROTOCOL];
378     GetProtocol(URL,Protocol,TSIZEOF(Protocol),NULL);
379     if (tcsicmp(Protocol,T("file"))==0) // override for local files
380         return PRI_MAXIMUM;
381     return NodeClass_Priority(NodeContext_FindClass(AnyNode,NodeEnumClassStr(AnyNode,NULL,STREAM_CLASS,NODE_PROTOCOL,Protocol)));
382 }
383