enable playback of multifile (split) movies
[enigma2.git] / 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_splitsize = 0;
10         m_totallength = 0;
11         m_current_offset = 0;
12         m_base_offset = 0;
13         m_nrfiles = 0;
14         m_current_file = 0;
15 }
16
17 eRawFile::~eRawFile()
18 {
19         close();
20 }
21
22 int eRawFile::open(const char *filename)
23 {
24         close();
25         m_basename = filename;
26         scan();
27         m_current_offset = 0;
28         m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
29         return m_fd;
30 }
31
32 void eRawFile::setfd(int fd)
33 {
34         close();
35         m_nrfiles = 1;
36         m_fd = fd;
37 }
38
39 off_t eRawFile::lseek(off_t offset, int whence)
40 {
41                 /* if there is only one file, use the native lseek - the file could be growing! */
42         if (!m_nrfiles)
43                 return ::lseek(m_fd, offset, whence);
44         switch (whence)
45         {
46         case SEEK_SET:
47                 m_current_offset = offset;
48                 break;
49         case SEEK_CUR:
50                 m_current_offset += offset;
51                 break;
52         case SEEK_END:
53                 m_current_offset = m_totallength + offset;
54                 break;
55         }
56         if (m_current_offset < 0)
57                 m_current_offset = 0;
58         return m_current_offset;
59 }
60
61 int eRawFile::close()
62 {
63         int ret = ::close(m_fd);
64         m_fd = -1;
65         return ret;
66 }
67
68 ssize_t eRawFile::read(void *buf, size_t count)
69 {
70         switchOffset(m_current_offset);
71         int ret = ::read(m_fd, buf, count);
72         if (ret > 0)
73                 m_current_offset += ret;
74         return ret;
75 }
76
77 int eRawFile::valid()
78 {
79         return m_fd != -1;
80 }
81
82 void eRawFile::scan()
83 {
84         m_nrfiles = 0;
85         m_totallength = 0;
86         while (m_nrfiles < 1000) /* .999 is the last possible */
87         {
88                 int f = openFile(m_nrfiles);
89                 if (f < 0)
90                         break;
91                 if (!m_nrfiles)
92                         m_splitsize = ::lseek(f, 0, SEEK_END);
93                 m_totallength += ::lseek(f, 0, SEEK_END);
94                 ::close(f);
95                 
96                 ++m_nrfiles;
97         }
98         eDebug("found %d files, splitsize: %llx, totallength: %llx", m_nrfiles, m_splitsize, m_totallength);
99 }
100
101 int eRawFile::switchOffset(off_t off)
102 {
103         if (m_splitsize)
104         {
105                 int filenr = off / m_splitsize;
106                 if (filenr >= m_nrfiles)
107                         filenr = m_nrfiles - 1;
108
109                 if (filenr != m_current_file)
110                 {
111                         close();
112                         setfd(openFile(filenr));
113                         m_base_offset = m_splitsize * filenr;
114                         eDebug("switched to file %d", filenr);
115                 }
116         } else
117                 m_base_offset = 0;
118         
119         return ::lseek(m_fd, off - m_base_offset, SEEK_SET) + m_base_offset;
120 }
121
122 int eRawFile::openFile(int nr)
123 {
124         std::string filename = m_basename;
125         if (m_nrfiles)
126         {
127                 char suffix[5];
128                 snprintf(suffix, 5, ".%03d", nr);
129                 filename += suffix;
130         }
131         return ::open(filename.c_str(), O_RDONLY);
132 }