]> git.vomp.tv Git - vompclient.git/blob - mediafile.cc
Rewritten vomp discovery protocol
[vompclient.git] / mediafile.cc
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #ifndef WIN32
22 #include <dirent.h>
23 #else
24 #include "threadwin.h"
25 #include <io.h>
26 #endif
27
28 #include "mediafile.h"
29 #include "media.h"
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <stdlib.h>
33
34 #include <iostream>
35 #include "log.h"
36
37
38
39
40 MediaFile::MediaFile(ULONG pid){
41   providerid=pid;
42 }
43
44 MediaFile::~MediaFile(){
45   };
46
47
48
49 static struct mtype{
50    const char* extension;
51    ULONG type;
52    } mediatypes[]= {
53      {".mp3",MEDIA_TYPE_AUDIO},
54      {".MP3",MEDIA_TYPE_AUDIO},
55      {".jpg",MEDIA_TYPE_PICTURE},
56      {".JPG",MEDIA_TYPE_PICTURE},
57      {".jpeg",MEDIA_TYPE_PICTURE},
58      {".JPEG",MEDIA_TYPE_PICTURE},
59      {".mpg",MEDIA_TYPE_VIDEO},
60      {".MPG",MEDIA_TYPE_VIDEO}
61      };
62 //#define NUMTYPES (sizeof(mediatypes)/sizeof(mtype))
63 #define NUMTYPES 8
64
65 //helper from vdr tools.c
66 bool endswith(const char *s, const char *p)
67 {
68   const char *se = s + strlen(s) - 1;
69   const char *pe = p + strlen(p) - 1;
70   while (pe >= p) {
71         if (*pe-- != *se-- || (se < s && pe >= p))
72            return false;
73         }
74   return true;
75 }
76
77 MediaList* MediaFile::getRootList() {
78   //has to be implemented in the derived class
79   return NULL;
80 }
81
82 ULONG MediaFile::getMediaType(const char * filename) {
83  for (ULONG i=0;i<NUMTYPES;i++) {
84       if (endswith(filename,mediatypes[i].extension)) {
85         return mediatypes[i].type;
86         }
87      }
88  return MEDIA_TYPE_UNKNOWN;
89 }
90
91
92 Media * MediaFile::createMedia(const char * dirname, const char * filename, bool withURI) {
93   Media * rt=NULL;
94   char *buffer=(char*)malloc(strlen(dirname)+strlen(filename)+2);
95   sprintf(buffer, "%s/%s", dirname, filename);
96
97   ULONG mtype=MEDIA_TYPE_UNKNOWN;
98 #ifndef WIN32
99   struct stat st;
100   if (stat(buffer, &st) == 0) {
101     if (S_ISDIR(st.st_mode)) {
102        mtype=MEDIA_TYPE_DIR;
103     }
104     else {
105        mtype=getMediaType(filename);
106     }
107   }
108 #else 
109   WIN32_FILE_ATTRIBUTE_DATA att;
110   GetFileAttributesEx(buffer,GetFileExInfoStandard,&att);
111   if (att.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {    
112        mtype=MEDIA_TYPE_DIR;
113   } else {
114        mtype=getMediaType(filename);
115   }
116 #endif
117
118   //only consider entries we accept by type here
119   if (mtype != MEDIA_TYPE_UNKNOWN) {
120     rt =new Media();
121     rt->setMediaType(mtype);
122     rt->setFileName(filename);
123 #ifndef WIN32
124     rt->setTime(st.st_mtime);
125 #else
126     struct timespec targetTime;
127     targetTime.tv_sec=(*((__int64*) &att.ftCreationTime)-WINDOWS_TIME_BASE_OFFSET)/(10*1000*1000);
128     targetTime.tv_nsec=((*((__int64*)&att.ftCreationTime)-WINDOWS_TIME_BASE_OFFSET)%(10*1000*1000))*100;
129     rt->setTime(targetTime.tv_sec);
130 #endif
131     Log::getInstance()->log("Media",Log::DEBUG,"created Media %s, type=%d",filename,mtype);
132     if (withURI) {
133       MediaURI u(providerid,buffer,NULL);
134       rt->setURI(&u);
135     }
136   }
137   free(buffer);
138   return rt;
139 }
140
141 MediaList* MediaFile::getMediaList(const MediaURI * parent){
142   ULONG mediaType=parent->getAllowedTypes();
143   Log::getInstance()->log("MediaFile::getMediaList",Log::DEBUG,"parent %s,types=0x%0lx",parent->getName(),mediaType);
144   MediaList *rt=NULL;
145   rt=new MediaList(parent);
146   const char *dirname=parent->getName();
147   //open the directory and read out the entries
148 #ifndef WIN32
149   DIR *d=opendir(dirname);
150   struct dirent *e;
151   union { // according to "The GNU C Library Reference Manual"
152     struct dirent d;
153     char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
154     } u;
155   while (d != NULL && (readdir_r(d,&u.d,&e) == 0) && e != NULL) {
156       const char * fname=e->d_name;
157 #else
158   WIN32_FIND_DATA  e;
159   HANDLE d;
160   d=FindFirstFile(dirname,&e);
161   if (d==INVALID_HANDLE_VALUE) {
162       return rt;
163   }
164   do  {
165       const char * fname=e.cFileName;
166 #endif    
167     if ( fname == NULL) continue;
168     if (strcmp(fname,".") == 0) continue;
169     if (strcmp(fname,"..") == 0) continue;
170     Media *m=createMedia(dirname,fname);
171     if (m && ( m->getMediaType() & mediaType)) {
172       Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,m->getMediaType());
173       rt->push_back(m);
174     }
175     else {
176       if (m) delete m;
177     }
178 #ifndef WIN32
179   }
180   if (d != NULL) closedir(d);
181 #else
182   } while (FindNextFile(d,&e));
183   FindClose(d);
184 #endif
185   return rt;
186 }
187
188
189 int MediaFile::openMedium(ULONG channel, const MediaURI * uri, ULLONG * size, ULONG xsize, ULONG ysize) {
190   Log::getInstance()->log("Media::openMedium",Log::DEBUG,"fn=%s,chan=%u",uri->getName(),channel);
191   *size=0;
192   if (channel <0 || channel >= NUMCHANNELS) return -1;
193   struct ChannelInfo *info=&channels[channel];
194   if (info->file) info->reset();
195   FILE *fp=fopen(uri->getName(),"r");
196   if (! fp) {
197     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
198     return -1;
199   }
200   
201   ULLONG mysize=0;
202 #ifndef WIN32 
203   struct stat st;
204   if ( fstat(fileno(fp),&st) == 0) mysize=st.st_size;
205 #else 
206   mysize=_filelength(_fileno(fp));
207 #endif
208   if (mysize == 0) {
209     Log::getInstance()->log("Media::openMedium",Log::ERR,"unable to open file fn=%s,chan=%u",uri->getName(),channel);
210     fclose(fp);
211     return -1;
212   }
213   info->setFilename(uri->getName());
214   info->file=fp;
215   info->size=mysize;
216   *size=mysize;
217   info->provider=providerid;
218   return 0;
219 }
220
221
222 int MediaFile::getMediaBlock(ULONG channel, ULLONG offset, ULONG len, ULONG * outlen,
223         unsigned char ** buffer) {
224   Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"chan=%u,offset=%llu,len=%lu",channel,offset,len);
225   *outlen=0;
226   if (channel <0 || channel >= NUMCHANNELS) return -1;
227   struct ChannelInfo *info=&channels[channel];
228   if (! info->file) {
229     Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"not open chan=%u",channel);
230     return -1;
231   }
232   ULLONG cpos=ftell(info->file);
233   if (offset != cpos) {
234     fseek(info->file,offset-cpos,SEEK_CUR);
235   }
236   if (offset != (ULLONG)ftell(info->file)) {
237     Log::getInstance()->log("Client", Log::DEBUG, "getMediaBlock pos = %llu not available", offset);
238     return -1;
239   }
240   if (*buffer == NULL) *buffer=(UCHAR *)malloc(len);
241   if (*buffer == NULL) {
242     Log::getInstance()->log("Media::getMediaBlock",Log::ERR,"uanble to allocate buffer");
243     return -1;
244   }
245   ULONG amount=fread(*buffer,1,len,info->file);
246   Log::getInstance()->log("Media::getMediaBlock",Log::DEBUG,"readlen=%lu",amount);
247   *outlen=amount;
248   return 0;
249 }
250
251
252 int MediaFile::closeMediaChannel(ULONG channel){
253   Log::getInstance()->log("Media::closeMediaChannel",Log::DEBUG,"chan=%u",channel);
254   if (channel <0 || channel >= NUMCHANNELS) return -1;
255   struct ChannelInfo *info=&channels[channel];
256   info->reset();
257   return 0;
258 }
259
260 //TODO: fill in more info
261 int MediaFile::getMediaInfo(ULONG channel, MediaInfo * result){
262   Log::getInstance()->log("Media::getMediaInfo",Log::DEBUG,"chan=%u",channel);
263   if (channel <0 || channel >= NUMCHANNELS) return -1;
264   struct ChannelInfo *info=&channels[channel];
265   if (! info->file) return -1;
266   result->size=info->size;
267   result->canPosition=true;
268   return 0;
269 }