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