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