TranscodingSetup : fix misspelling name.
[vuplus_dvbapp] / lib / base / rawfile.cpp
1 #include <cstdio>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <lib/base/rawfile.h>
5 #include <lib/base/eerror.h>
6
7 DEFINE_REF(eRawFile);
8
9 eRawFile::eRawFile()
10         :m_lock(false)
11 {
12         m_fd = -1;
13         m_file = 0;
14         m_splitsize = 0;
15         m_totallength = 0;
16         m_current_offset = 0;
17         m_base_offset = 0;
18         m_last_offset = 0;
19         m_nrfiles = 0;
20         m_current_file = 0;
21 }
22
23 eRawFile::~eRawFile()
24 {
25         close();
26 }
27
28 int eRawFile::open(const char *filename, int cached)
29 {
30         close();
31         m_cached = cached;
32         m_basename = filename;
33         scan();
34         m_current_offset = 0;
35         m_last_offset = 0;
36         if (!m_cached)
37         {
38                 m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
39                 return m_fd;
40         } else
41         {
42                 m_file = ::fopen64(filename, "rb");
43                 if (!m_file)
44                         return -1;
45                 return 0;
46         }
47 }
48
49 void eRawFile::setfd(int fd)
50 {
51         close();
52         m_cached = 0;
53         m_nrfiles = 1;
54         m_fd = fd;
55 }
56
57 off_t eRawFile::lseek(off_t offset, int whence)
58 {
59         eSingleLocker l(m_lock);
60         m_current_offset = lseek_internal(offset, whence);
61         return m_current_offset;
62 }
63
64 off_t eRawFile::lseek_internal(off_t offset, int whence)
65 {
66 //      eDebug("lseek: %lld, %d", offset, whence);
67                 /* if there is only one file, use the native lseek - the file could be growing! */
68         if (m_nrfiles < 2)
69         {
70                 if (!m_cached)
71                         return ::lseek(m_fd, offset, whence);
72                 else
73                 {
74                         if (::fseeko(m_file, offset, whence) < 0)
75                                 perror("fseeko");
76                         return ::ftello(m_file);
77                 }
78         }
79         switch (whence)
80         {
81         case SEEK_SET:
82                 m_current_offset = offset;
83                 break;
84         case SEEK_CUR:
85                 m_current_offset += offset;
86                 break;
87         case SEEK_END:
88                 m_current_offset = m_totallength + offset;
89                 break;
90         }
91
92         if (m_current_offset < 0)
93                 m_current_offset = 0;
94         return m_current_offset;
95 }
96
97 int eRawFile::close()
98 {
99         if (m_cached)
100         {
101                 if (!m_file)
102                         return -1;
103                 ::fclose(m_file);
104                 m_file = 0;
105                 return 0;
106         } else
107         {
108                 int ret = ::close(m_fd);
109                 m_fd = -1;
110                 return ret;
111         }
112 }
113
114 ssize_t eRawFile::read(off_t offset, void *buf, size_t count)
115 {
116         eSingleLocker l(m_lock);
117
118         if (offset != m_current_offset)
119         {
120                 m_current_offset = lseek_internal(offset, SEEK_SET);
121                 if (m_current_offset < 0)
122                         return m_current_offset;
123         }
124
125         switchOffset(m_current_offset);
126
127         if (m_nrfiles >= 2)
128         {
129                 if (m_current_offset + count > m_totallength)
130                         count = m_totallength - m_current_offset;
131                 if (count < 0)
132                         return 0;
133         }
134         
135         int ret;
136         
137         if (!m_cached)
138                 ret = ::read(m_fd, buf, count);
139         else
140                 ret = ::fread(buf, 1, count, m_file);
141
142         if (ret > 0)
143                 m_current_offset = m_last_offset += ret;
144         return ret;
145 }
146
147 int eRawFile::valid()
148 {
149         if (!m_cached)
150                 return m_fd != -1;
151         else
152                 return !!m_file;
153 }
154
155 void eRawFile::scan()
156 {
157         m_nrfiles = 0;
158         m_totallength = 0;
159         while (m_nrfiles < 1000) /* .999 is the last possible */
160         {
161                 if (!m_cached)
162                 {
163                         int f = openFileUncached(m_nrfiles);
164                         if (f < 0)
165                                 break;
166                         if (!m_nrfiles)
167                                 m_splitsize = ::lseek(f, 0, SEEK_END);
168                         m_totallength += ::lseek(f, 0, SEEK_END);
169                         ::close(f);
170                 } else
171                 {
172                         FILE *f = openFileCached(m_nrfiles);
173                         if (!f)
174                                 break;
175                         ::fseeko(f, 0, SEEK_END);
176                         if (!m_nrfiles)
177                                 m_splitsize = ::ftello(f);
178                         m_totallength += ::ftello(f);
179                         ::fclose(f);
180                 }
181                 
182                 ++m_nrfiles;
183         }
184 //      eDebug("found %d files, splitsize: %llx, totallength: %llx", m_nrfiles, m_splitsize, m_totallength);
185 }
186
187 int eRawFile::switchOffset(off_t off)
188 {
189         if (m_splitsize)
190         {
191                 int filenr = off / m_splitsize;
192                 if (filenr >= m_nrfiles)
193                         filenr = m_nrfiles - 1;
194                 if (filenr != m_current_file)
195                 {       
196 //                      eDebug("-> %d", filenr);
197                         close();
198                         if (!m_cached)
199                                 m_fd = openFileUncached(filenr);
200                         else
201                                 m_file = openFileCached(filenr);
202                         m_last_offset = m_base_offset = m_splitsize * filenr;
203                         m_current_file = filenr;
204                 }
205         } else
206                 m_base_offset = 0;
207         
208         if (off != m_last_offset)
209         {
210                 if (!m_cached)
211                         m_last_offset = ::lseek(m_fd, off - m_base_offset, SEEK_SET) + m_base_offset;
212                 else
213                 {
214                         ::fseeko(m_file, off - m_base_offset, SEEK_SET);
215                         m_last_offset = ::ftello(m_file) + m_base_offset;
216                 }
217                 return m_last_offset;
218         } else
219         {
220                 return m_last_offset;
221         }
222 }
223
224 /* m_cached */
225 FILE *eRawFile::openFileCached(int nr)
226 {
227         std::string filename = m_basename;
228         if (nr)
229         {
230                 char suffix[5];
231                 snprintf(suffix, 5, ".%03d", nr);
232                 filename += suffix;
233         }
234         return ::fopen64(filename.c_str(), "rb");
235 }
236
237 /* !m_cached */
238 int eRawFile::openFileUncached(int nr)
239 {
240         std::string filename = m_basename;
241         if (nr)
242         {
243                 char suffix[5];
244                 snprintf(suffix, 5, ".%03d", nr);
245                 filename += suffix;
246         }
247         return ::open(filename.c_str(), O_RDONLY | O_LARGEFILE);
248 }
249
250 off_t eRawFile::length()
251 {
252         return m_totallength;
253 }