]> git.vomp.tv Git - vompserver.git/blob - servermediafile.c
15 years that line of code has been waiting to crash
[vompserver.git] / servermediafile.c
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "servermediafile.h"
22 #include "mediaproviderids.h"
23 #include "media.h"
24 #include "medialauncher.h"
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <iostream>
29 #include "log.h"
30
31
32 /* input buffer for reading dir */
33 #define BUFSIZE 2048
34 /* how long to wait until a list has to be finished (100ms units)*/
35 #define MAXWAIT 50
36
37 ServerMediaFile::ServerMediaFile(Config *c,MediaPlayerRegister *distributor):MediaFile(MPROVIDERID_SERVERMEDIAFILE){
38   cfg=c;
39   distributor->registerMediaProvider(this,MPROVIDERID_SERVERMEDIAFILE);
40   dirhandler=new MediaLauncher(cfg);
41   dirhandler->init();
42   for (int i=0;i<NUMCHANNELS;i++) {
43     launchers[i]=new MediaLauncher(cfg);
44     launchers[i]->init(dirhandler);
45   }
46 }
47
48 ServerMediaFile::~ServerMediaFile(){
49   for (int i=0;i<NUMCHANNELS;i++) {
50     launchers[i]->closeStream();
51     delete launchers[i];
52   }
53   delete dirhandler;
54   }
55
56 MediaList* ServerMediaFile::getRootList() {
57   Log::getInstance()->log("MediaFile::getRootList",Log::DEBUG,"");
58   MediaURI *ru=new MediaURI(providerid,NULL,NULL);
59   MediaList *rt=new MediaList(ru);
60   delete ru;
61   //the configured Media List
62   //for the moment up to 50 entries [Media] Dir.1 ...Dir.10
63   struct stat st;
64   for (int nr=1;nr<=50;nr++){
65     char buffer[30];
66     sprintf(buffer,"Dir.%d",nr);
67     const char * dn=cfg->getValueString("Media",buffer);
68     if (dn != NULL) {
69       if (stat(dn,&st) != 0 || ! S_ISDIR(st.st_mode)) {
70         Log::getInstance()->log("MediaFile::getRootList",Log::ERR,"unable to open basedir %s",dn);
71       }
72       else {
73         Media *m=new Media();
74         m->setFileName(dn);
75         m->setMediaType(MEDIA_TYPE_DIR);
76         m->setTime(st.st_mtime);
77         sprintf(buffer,"Dir.Name.%d",nr);
78         m->setDisplayName(cfg->getValueString("Media",buffer));
79         rt->push_back(m);
80         Log::getInstance()->log("Media",Log::DEBUG,"added base dir %s",dn);
81       }
82      }
83    }
84   return rt;
85 }
86
87 ULONG ServerMediaFile::getMediaType(const char *filename) {
88   ULONG rt=dirhandler->getTypeForName(filename);
89   if (rt != MEDIA_TYPE_UNKNOWN) return rt;
90   return MediaFile::getMediaType(filename);
91 }
92
93 int ServerMediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize){
94   if (channel >= NUMCHANNELS) return -1;
95   launchers[channel]->closeStream();
96   ULONG rt=launchers[channel]->getTypeForName(uri->getName());
97   if (rt != MEDIA_TYPE_UNKNOWN) {
98     *size=0;
99     channels[channel].reset();
100     int rtstat=launchers[channel]->openStream(uri->getName(),xsize,ysize);
101     channels[channel].setFilename(uri->getName());
102     return rtstat>=0?0:1;
103   }
104   return MediaFile::openMedium(channel,uri,size,xsize,ysize);
105 }
106     
107 int ServerMediaFile::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen,
108         unsigned char ** buffer)
109 {
110   if (channel >= NUMCHANNELS) return -1;
111   if (launchers[channel]->isOpen()) {
112     return launchers[channel]->getNextBlock(len,buffer,outlen);
113   }
114   return MediaFile::getMediaBlock(channel,offset,len,outlen,buffer);
115 }
116 int ServerMediaFile::closeMediaChannel(ULONG channel){
117   if (channel >= NUMCHANNELS) return -1;
118   if (launchers[channel]->isOpen()) {
119     return launchers[channel]->closeStream();
120   }
121   return MediaFile::closeMediaChannel(channel);
122 }
123 int ServerMediaFile::getMediaInfo(ULONG channel, MediaInfo * result){
124   if (channel >= NUMCHANNELS) return -1;
125   if (launchers[channel]->isOpen()) {
126     result->canPosition=false;
127     result->type=launchers[channel]->getTypeForName(channels[channel].filename);
128     return 0;
129   }
130   return MediaFile::getMediaInfo(channel,result);
131 }
132
133
134 MediaList* ServerMediaFile::getMediaList(const MediaURI *parent) {
135   ULONG rt=dirhandler->getTypeForName(parent->getName());
136   if (rt == MEDIA_TYPE_UNKNOWN) return MediaFile::getMediaList(parent);
137   int op=dirhandler->openStream(parent->getName(),0,0);
138   if (op < 0) {
139     Log::getInstance()->log("Media",Log::ERR,"unable to open handler for %s",parent->getName());
140     dirhandler->closeStream();
141     return NULL;
142   }
143   int maxtries=0;
144   unsigned char *inbuf=NULL;
145   unsigned char linebuf[2*BUFSIZE];
146   unsigned char *wrp=linebuf;
147   ULONG outlen=0;
148   MediaList *ml=new MediaList(parent);
149   while (maxtries < MAXWAIT) {
150     int ert=dirhandler->getNextBlock(BUFSIZE,&inbuf,&outlen);
151     if (ert != 0) break;
152     if (outlen == 0) {
153       if (inbuf != NULL) free(inbuf);
154       inbuf=NULL;
155       maxtries++;
156       continue;
157     }
158     maxtries=0;
159     if (outlen > BUFSIZE) {
160       Log::getInstance()->log("Media",Log::ERR,"invalid read len %llu in getBlock for list %s",outlen,parent->getName());
161       free(inbuf);
162       inbuf=NULL;
163       continue;
164     }
165     memcpy(wrp,inbuf,outlen);
166     free(inbuf);
167     inbuf=NULL;
168     ULONG handledBytes=addDataToList(linebuf,outlen+(wrp-linebuf),ml,true);
169     memcpy(linebuf,wrp+outlen-handledBytes,wrp-linebuf+outlen-handledBytes);
170     if (handledBytes > outlen) wrp-=handledBytes-outlen;
171     if (wrp >= linebuf+BUFSIZE) {
172         Log::getInstance()->log("Media",Log::ERR,"line to long in getBlock for list %s",parent->getName());
173         wrp=linebuf;
174     }
175   }
176   dirhandler->closeStream();
177   return ml;
178 }
179
180
181 ULONG ServerMediaFile::addDataToList(unsigned char * buf, ULONG buflen,MediaList *list,bool extendedFormat) {
182   ULONG handledBytes=0;
183   char entrybuf[BUFSIZE+1];
184   char display[BUFSIZE+1];
185   int ebpos=0;
186   while (handledBytes < buflen) {
187     unsigned char c=buf[handledBytes];
188     if (c == '\n') {
189       entrybuf[ebpos]=0;
190       /* complete line */
191       /* handle # lines */
192       for (int i=0;i<ebpos;i++) {
193         if (entrybuf[i] == '#') {
194           entrybuf[i]=0;
195           break;
196         }
197         if (entrybuf[i] != ' ') break;
198       }
199       if (strlen(entrybuf) > 0) {
200         Log::getInstance()->log("Media",Log::DEBUG,"handle list line %s",entrybuf);
201         char *uriptr=entrybuf;
202         if (extendedFormat) {
203           /* search for a delimiter */
204           while (*uriptr != ';' && *uriptr != 0) uriptr++;
205           if (*uriptr == ';') uriptr++;
206           if (*uriptr == 0) uriptr=entrybuf;
207         }
208         ULONG mt=getMediaType(uriptr);
209         if (mt != MEDIA_TYPE_UNKNOWN) {
210           if (uriptr != entrybuf) {
211             memcpy(display,entrybuf,uriptr-entrybuf-1);
212             display[uriptr-entrybuf-1]=0;
213           }
214           else {
215             int i=strlen(entrybuf)-1;
216             int len=i+1;
217             for(;i>=0;i--) {
218               if (entrybuf[i]=='/') break;
219             }
220             i++;
221             if (entrybuf[i] != 0) {
222               memcpy(display,&entrybuf[i],len-i);
223               display[len-i]=0;
224             }
225             else {
226               memcpy(display,entrybuf,len);
227               display[len]=0;
228             }
229           }
230           Media *m=new Media();
231           MediaURI *u=NULL;
232           if (*uriptr != '/') {
233             /* add the directory of the list in front */
234             MediaURI *p=list->getParent(list->getRoot());
235             char ubuf[strlen(p->getName())+strlen(uriptr)+2];
236             sprintf(ubuf,"%s/%s",p->getName(),uriptr);
237             u=new MediaURI(providerid,ubuf,display);
238             delete p;
239           }
240           else {
241             u=new MediaURI(providerid,uriptr,display);
242           }
243           m->setFileName(display);
244           m->setURI(u);
245           delete u;
246           m->setMediaType(mt);
247           list->push_back(m);
248           Log::getInstance()->log("Media",Log::DEBUG,"added media display %s, type %lu",display,mt);
249         }
250       }
251
252
253       //do handling
254       ebpos=0;
255     }
256     else if (c != '\r') {
257       entrybuf[ebpos]=c;
258       ebpos++;
259       if (ebpos >= BUFSIZE) {
260         /* line too long - ignore */
261         Log::getInstance()->log("Media",Log::ERR,"line to long in add data");
262         ebpos=0;
263       }
264     }
265     handledBytes++;
266   }
267   return handledBytes-ebpos;
268 }