Merge branch 'master' of git://cadel.mutabah.net/acess2
[tpg/acess2.git] / Usermode / Libraries / liburi.so_src / main.c
1 /*
2  * Acess2 - URI Parser and opener
3  * By John Hodge (thePowersGang)
4  */
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <uri.h>
10
11 // === STRUCTURES ===
12 struct sURIFile
13 {
14         void    *Handle;
15          int    Mode;
16         tURIHandler     *Handler;
17          int    CurBlockOffset;
18         char    Buffer[];
19 };
20
21 // === PROTOTYPES ===
22  int    SoMain(void);
23 tURI    *URI_Parse(const char *String);
24 tURIFile        *URI_MakeHandle(int Mode, void *Handle, tURIHandler *Handler);
25 tURIFile        *URI_Open(int Mode, tURI *URI);
26 size_t  URI_Read(tURIFile *File, size_t Bytes, void *Buffer);
27 size_t  URI_Write(tURIFile *File, size_t Bytes, void *Buffer);
28 void    URI_Close(tURIFile *File);
29 // --- file:/// handler
30 void    *URI_file_Open(const char *Host, int Port, const char *Path, int Mode);
31 void    URI_file_Close(void *Handle);
32 size_t  URI_file_Read(void *Handle, size_t Bytes, void *Buffer);
33 size_t  URI_file_Write(void *Handle, size_t Bytes, const void *Buffer);
34 off_t   URI_file_GetSize(void *Handle);
35
36 // === CONSTANTS ===
37 // Builtin URI protocol handlers
38 tURIHandler     caBuiltinHandlers[] = {
39         {"file", 0,
40                 URI_file_Open, URI_file_Close,
41                 URI_file_Read, URI_file_Write,
42                 URI_file_GetSize
43         }
44 };
45 #define NUM_BUILTIN_HANDLERS    (sizeof(caBuiltinHandlers)/sizeof(caBuiltinHandlers[0]))
46
47 // === CODE ===
48 int SoMain(void)
49 {
50         return 0;
51 }
52
53 tURI *URI_Parse(const char *String)
54 {
55         const char      *tmp = String;
56         tURI    *ret;
57          int    protolen;
58         
59         if(!String)     return NULL;
60         
61         protolen = 0;
62         while( isalpha(*tmp) || isdigit(*tmp) ) tmp++, protolen++;
63         
64         // true URI
65         if(tmp[0] == ':' && tmp[1] == '/' && tmp[2] == '/')
66         {
67                  int    hostlen, portlen;
68                 tmp += 3;       // Eat '://'
69                 ret = malloc(sizeof(tURI) + protolen + 1 + strlen(tmp) + 1);
70                 
71                 ret->Proto = (char*)ret + sizeof(tURI);
72                 memcpy(ret->Proto, String, protolen);
73                 ret->Proto[protolen] = '\0';
74                 
75                 ret->Host = ret->Proto + protolen + 1;
76                 hostlen = 0;
77                 
78                 // IPv6
79                 if( *tmp == '[' )
80                 {
81                         tmp ++;
82                         while( *tmp && *tmp != ']' ) {
83                                 ret->Host[hostlen] = *tmp;
84                                 tmp ++;
85                                 hostlen ++;
86                         }
87                         tmp ++;
88                         ret->Host[hostlen] = '\0';
89                 }
90                 // IPv4/DNS
91                 else
92                 {
93                         while( *tmp && *tmp != '/' && *tmp != ':' )
94                         {
95                                 ret->Host[hostlen] = *tmp;
96                                 tmp ++;
97                                 hostlen ++;
98                         }
99                         ret->Host[hostlen] = '\0';
100                 }
101                 
102                 // Port
103                 if( *tmp == ':' ) {
104                         ret->PortStr = ret->Host + hostlen + 1;
105                         tmp ++;
106                         portlen = 0;
107                         while(isalpha(*tmp) || isdigit(*tmp))
108                         {
109                                 ret->PortStr[portlen] = *tmp;
110                                 portlen ++;
111                                 tmp ++;
112                         }
113                         ret->PortStr[portlen] = '\0';
114                         
115                         ret->PortNum = atoi(ret->PortStr);
116                         if(!ret->PortNum && !(ret->PortStr[0] == '0' && portlen == 1) )
117                         {
118                                 // error!
119                                 ret->Path = NULL;
120                                 return ret;
121                         }
122                 }
123                 else {
124                         ret->PortStr = NULL;
125                         ret->PortNum = -1;
126                         portlen = 0;
127                 }
128                 
129                 if(*tmp == '\0')
130                 {
131                         ret->Path = NULL;
132                         return ret;
133                 }
134                 
135                 // TODO: What to do on a parse error
136                 if(*tmp != '/') {
137                         ret->Path = NULL;
138                         return ret;
139                 }
140                 
141                 if(ret->PortStr)
142                         ret->Path = ret->PortStr + portlen + 1;
143                 else
144                         ret->Path = ret->Host + hostlen + 1;
145                 
146                 strcpy(ret->Path, tmp);
147                 
148                 return ret;
149         }
150         else
151         {
152 //              char    *cwd;
153 //               int    retlen;
154                 
155                 // Path
156                 // TODO: What to do?
157                 // Probably return file:///<path>
158                 // but should I get the CWD and use append that?
159                 ret = malloc( sizeof(tURI) + strlen(String) + 1 );
160                 ret->Path = (char*)ret + sizeof(tURI);
161                 strcpy(ret->Path, String);
162                 ret->Proto = "file";
163                 ret->Host = NULL;
164                 ret->PortNum = 0;
165                 ret->PortStr = NULL;
166                 return ret;
167         }
168 }
169
170 tURIFile *URI_MakeHandle(int Mode, void *Handle, tURIHandler *Handler)
171 {
172         tURIFile        *ret;
173         
174         ret = malloc(sizeof(tURIFile)+Handler->BlockSize);
175         if(!ret)        return NULL;
176         
177         ret->Handle = Handle;
178         ret->Mode = Mode;
179         ret->Handler = Handler;
180         ret->CurBlockOffset = 0;
181         
182         return ret;
183 }
184
185 tURIFile *URI_Open(int Mode, tURI *URI)
186 {
187         tURIHandler     *handler;
188         tURIFile        *ret;
189         void    *handle;
190          int    i;
191         
192         if(!URI)
193                 return NULL;
194         
195         for( i = 0; i < NUM_BUILTIN_HANDLERS; i ++ )
196         {
197                 if(strcmp(URI->Proto, caBuiltinHandlers[i].Name) == 0)
198                         break;
199         }
200         
201         if( i == NUM_BUILTIN_HANDLERS )
202         {
203                 // TODO: Dynamics
204                 printf("URI_Open: Warning - Unknown URI handler\n");
205                 return NULL;
206         }
207         else
208                 handler = &caBuiltinHandlers[i];
209         
210         printf("URI_Open: handler->Open = %p\n", handler->Open);
211         
212         handle = handler->Open(URI->Host, URI->PortNum, URI->Path, Mode);
213         printf("URI_Open: handle = %i\n", handle);
214         if(handle == NULL)      return NULL;
215         
216         printf("URI_MakeHandle(Mode=%i, handle=%i, handler=%p)\n",
217                 Mode, handle, handler);
218         ret = URI_MakeHandle(Mode, handle, handler);
219         if(!ret) {
220                 handler->Close( handle );
221                 return NULL;
222         }
223         return ret;
224 }
225
226 int URI_GetSize(tURIFile *File, size_t *Size)
227 {
228         if( !File || !Size )    return -1;
229         
230         if( File->Handler->GetSize )
231         {
232                 *Size = File->Handler->GetSize(File->Handle);
233                 return 0;       // Success
234         }
235         
236         return 1;       // Size not avaliable
237 }
238
239 /**
240  * \brief Read from a URI file
241  */
242 size_t URI_Read(tURIFile *File, size_t Bytes, void *Buffer)
243 {
244         size_t  rem = Bytes;
245         void    *buf = Buffer;
246         size_t  tmp;
247         
248         printf("URI_Read(File=%p, Bytes=%u, Buffer=%p)\n",
249                 File, (unsigned int)Bytes, Buffer);
250         
251         if(!File || !Buffer)    return -1;
252         if(Bytes == 0)  return 0;
253         
254         if( !(File->Mode & URI_MODE_READ) )     return -1;
255         
256         // Read from cache if avaliable
257         if(File->Handler->BlockSize && File->CurBlockOffset)
258         {
259                  int    avail;
260                 
261                 avail = File->Handler->BlockSize - File->CurBlockOffset;
262                 
263                 if(avail >= Bytes) {
264                         memcpy(Buffer, File->Buffer, Bytes);
265                         File->CurBlockOffset += Bytes;
266                         File->CurBlockOffset %= File->Handler->BlockSize;
267                         return Bytes;
268                 }
269                 
270                 rem -= avail;
271                 memcpy(Buffer, File->Buffer, avail);
272                 File->CurBlockOffset = 0;
273                 buf += avail;
274         }
275         
276         
277         if( File->Handler->BlockSize )
278         {
279                 // Read whole blocks
280                 while( rem >= File->Handler->BlockSize )
281                 {
282                         tmp = File->Handler->Read( File->Handle, File->Handler->BlockSize, buf );
283                         if(tmp < File->Handler->BlockSize)
284                                 return Bytes - rem - tmp;
285                         buf += File->Handler->BlockSize;
286                 }
287                 
288                 // Read the trailing part
289                 if(rem)
290                 {
291                         File->Handler->Read( File->Handle, File->Handler->BlockSize, File->Buffer );
292                         memcpy( buf, File->Buffer, rem );
293                         File->CurBlockOffset += rem;
294                 }
295                 return Bytes;
296         }
297         
298         return File->Handler->Read( File->Handle, Bytes, Buffer );
299 }
300
301 /**
302  * \brief Write to a URI file
303  */
304
305
306 // ====
307 // Builtin Handlers
308 // ====
309 void *URI_file_Open(const char *Host, int Port, const char *Path, int Mode)
310 {
311         const char      *smode = NULL;
312         if( (Mode & URI_MODE_READ) && (Mode & URI_MODE_WRITE))
313                 smode = "r+";
314         else if( (Mode & URI_MODE_READ) )
315                 smode = "r";
316         else if( (Mode & URI_MODE_WRITE) )
317                 smode = "w";
318         else
319                 smode = "";
320         
321 //      printf("URI_file_Open: open('%s', 0x%x)\n", Path, smode);
322         return fopen(Path, smode);
323 }
324 size_t URI_file_Read(void *Handle, size_t Bytes, void *Buffer)
325 {
326 //      printf("URI_file_Read: (Handle=%i, Buffer=%p, Bytes=%i)\n",
327 //              Handle, Buffer, (int)Bytes);
328         return fread(Buffer, Bytes, 1, Handle);
329 }
330 size_t URI_file_Write(void *Handle, size_t Bytes, const void *Buffer)
331 {
332         return fwrite(Buffer, Bytes, 1, Handle);
333 }
334 void URI_file_Close(void *Handle)
335 {
336         fclose(Handle);
337 }
338 off_t URI_file_GetSize(void *Handle)
339 {
340         off_t curpos = ftell(Handle);
341         off_t ret;
342         fseek(Handle, 0, SEEK_END);
343         ret = ftell(Handle);
344         fseek(Handle, curpos, SEEK_SET);
345         return ret;
346 }
347

UCC git Repository :: git.ucc.asn.au