]> git.vomp.tv Git - vompserver.git/blob - mediafile.c
15 years that line of code has been waiting to crash
[vompserver.git] / mediafile.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 <stdlib.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <dirent.h>
25 #include <iostream>
26 #include <stddef.h>
27
28 #include "mediafile.h"
29 #include "media.h"
30 #include "log.h"
31
32
33 MediaFile::MediaFile(ULONG pid){
34   providerid=pid;
35 }
36
37 MediaFile::~MediaFile(){
38   };
39
40
41
42 static struct mtype{
43    const char* extension;
44    ULONG type;
45    } mediatypes[]= {
46      {".mp3",MEDIA_TYPE_AUDIO},
47      {".MP3",MEDIA_TYPE_AUDIO},
48      {".jpg",MEDIA_TYPE_PICTURE},
49      {".JPG",MEDIA_TYPE_PICTURE},
50      {".jpeg",MEDIA_TYPE_PICTURE},
51      {".JPEG",MEDIA_TYPE_PICTURE},
52      {".mpg",MEDIA_TYPE_VIDEO},
53      {".MPG",MEDIA_TYPE_VIDEO}
54      };
55 //#define NUMTYPES (sizeof(mediatypes)/sizeof(mtype))
56 #define NUMTYPES 8
57
58 //helper from vdr tools.c
59 bool endswith(const char *s, const char *p)
60 {
61   const char *se = s + strlen(s) - 1;
62   const char *pe = p + strlen(p) - 1;
63   while (pe >= p) {
64         if (*pe-- != *se-- || (se < s && pe >= p))
65            return false;
66         }
67   return true;
68 }
69
70 MediaList* MediaFile::getRootList() {
71   //has to be implemented in the derived class
72   return NULL;
73 }
74
75 ULONG MediaFile::getMediaType(const char * filename) {
76  for (ULONG i=0;i<NUMTYPES;i++) {
77       if (endswith(filename,mediatypes[i].extension)) {
78         return mediatypes[i].type;
79         }
80      }
81  return MEDIA_TYPE_UNKNOWN;
82 }
83
84
85 Media * MediaFile::createMedia(const char * dirname, const char * filename, bool withURI) {
86   Media * rt=NULL;
87   char *buffer;
88   int blen = asprintf(&buffer, "%s/%s", dirname, filename);
89   if (blen); // keep compiler happy because of unused result and unread variable warnings
90   struct stat st;
91   ULONG mtype=MEDIA_TYPE_UNKNOWN;
92   if (stat(buffer, &st) == 0) {
93     if (S_ISDIR(st.st_mode)) {
94        mtype=MEDIA_TYPE_DIR;
95     }
96     else {
97        mtype=getMediaType(filename);
98     }
99   }
100   //only consider entries we accept by type here
101   if (mtype != MEDIA_TYPE_UNKNOWN) {
102     rt =new Media();
103     rt->setMediaType(mtype);
104     rt->setFileName(filename);
105     rt->setTime(st.st_mtime);
106     Log::getInstance()->log("Media",Log::DEBUG,"created Media %s, type=%d",filename,mtype);
107     if (withURI) {
108       MediaURI u(providerid,buffer,NULL);
109       rt->setURI(&u);
110     }
111   }
112   free(buffer);
113   return rt;
114 }
115
116 MediaList* MediaFile::getMediaList(const MediaURI * parent){
117   ULONG mediaType=parent->getAllowedTypes();
118   Log::getInstance()->log("MediaFile::getMediaList",Log::DEBUG,"parent %s,types=0x%0lx",parent->getName(),mediaType);
119   MediaList *rt=NULL;
120   rt=new MediaList(parent);
121   const char *dirname=parent->getName();
122   //open the directory and read out the entries
123   DIR *d=opendir(dirname);
124   if (d == NULL) return rt;
125   struct dirent *e;
126
127   /* readdir_r is now deprecated in favour of readdir (which is effectively thread safe)
128   union { // according to "The GNU C Library Reference Manual"
129     struct dirent d;
130     char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
131     } u;
132
133   while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) {
134   */
135
136   while (e = readdir(d)) {
137     const char * fname=e->d_name;
138     if ( fname == NULL) continue;
139     if (strcmp(fname,".") == 0) continue;
140     if (strcmp(fname,"..") == 0) continue;
141     Media *m=createMedia(dirname,fname);
142     if (m && ( m->getMediaType() & mediaType)) {
143       Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,m->getMediaType());
144       rt->push_back(m);
145     }
146     else {
147       if (m) delete m;
148     }
149   }
150   closedir(d);
151   return rt;
152 }
153
154
155 int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize) {
156   Log::getInstance()->log("Media::openMedium",Log::DEBUG,"fn=%s,chan=%u",uri->getName(),channel);
157   *size=0;
158   if (channel <0 || channel >= NUMCHANNELS) return -1;
159   struct ChannelInfo *info=&channels[channel];
160   if (info->file) info->reset();
161   FILE *fp=fopen(uri->getName(),"r");
162   if (! fp) {
163     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
164     return -1;
165   }
166   struct stat st;
167   ULLONG mysize=0;
168   if ( fstat(fileno(fp),&st) == 0) mysize=st.st_size;
169   if (mysize == 0) {
170     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
171     fclose(fp);
172     return -1;
173   }
174   info->setFilename(uri->getName());
175   info->file=fp;
176   info->size=mysize;
177   *size=mysize;
178   info->provider=providerid;
179   return 0;
180 }
181
182
183 int MediaFile::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen,
184         unsigned char ** buffer) {
185   Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"chan=%u,offset=%llu,len=%lu",channel,offset,len);
186   *outlen=0;
187   if (channel <0 || channel >= NUMCHANNELS) return -1;
188   struct ChannelInfo *info=&channels[channel];
189   if (! info->file) {
190     Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"not open chan=%u",channel);
191     return -1;
192   }
193   ULLONG cpos=ftell(info->file);
194   if (offset != cpos) {
195     fseek(info->file,offset-cpos,SEEK_CUR);
196   }
197   if (offset != (ULLONG)ftell(info->file)) {
198     Log::getInstance()->log("Client", Log::DEBUG, "getMediaBlock pos = %llu not available", offset);
199     return -1;
200   }
201   if (*buffer == NULL) *buffer=(UCHAR *)malloc(len);
202   if (*buffer == NULL) {
203     Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"uanble to allocate buffer");
204     return -1;
205   }
206   ULONG amount=fread(*buffer,1,len,info->file);
207   Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"readlen=%lu",amount);
208   *outlen=amount;
209   return 0;
210 }
211
212
213 int MediaFile::closeMediaChannel(ULONG channel){
214   Log::getInstance()->log("Media::closeMediaChannel",Log::DEBUG,"chan=%u",channel);
215   if (channel <0 || channel >= NUMCHANNELS) return -1;
216   struct ChannelInfo *info=&channels[channel];
217   info->reset();
218   return 0;
219 }
220
221 //TODO: fill in more info
222 int MediaFile::getMediaInfo(ULONG channel, MediaInfo * result){
223   Log::getInstance()->log("Media::getMediaInfo",Log::DEBUG,"chan=%u",channel);
224   if (channel <0 || channel >= NUMCHANNELS) return -1;
225   struct ChannelInfo *info=&channels[channel];
226   if (! info->file) return -1;
227   result->size=info->size;
228   result->canPosition=true;
229   return 0;
230 }