00001
00006 #include <cassert>
00007
00008 #define TAGV1
00009 #include "mp3_format.h"
00010 #include "bitstream.h"
00011 #include "except.h"
00012
00013 #ifdef DEBUG
00014 #include <iostream>
00015 #endif
00016
00017 Bitstream::Bitstream(const char *filename, int mode) : m_stream()
00018 {
00019 m_leftbits = 0;
00020 m_char = 0;
00021 m_mode = mode;
00022 m_files = &m_NULL;
00023
00024 assert(filename);
00025 Open(filename);
00026 }
00027
00028 Bitstream::Bitstream(const char **files, int mode) : m_stream()
00029 {
00030 assert(files);
00031 m_leftbits = 0;
00032 m_char = 0;
00033 m_mode = mode;
00034 m_files = files + 1;
00035
00036 assert(*files);
00037 Open(*files);
00038 }
00039
00040 void Bitstream::Read(unsigned int *data, int numbits)
00041 {
00042 int havebits = 32;
00043 int i = -1;
00044
00045 assert(data);
00046 assert(numbits > 0);
00047
00048 while(numbits > 0)
00049 {
00050 if(havebits == 32)
00051 {
00052 data[++i] = m_char << 24;
00053 numbits -= m_leftbits;
00054 havebits = m_leftbits;
00055 m_char = 0;
00056 m_leftbits = 0;
00057 }
00058 else
00059 {
00060
00061 ReadBytes(reinterpret_cast<char*>(&m_char), 1);
00062
00063 if(havebits <= 24)
00064 {
00065 data[i] |= m_char << (24 - havebits);
00066 havebits += 8;
00067 numbits -= 8;
00068 m_char = 0;
00069 }
00070 else
00071 {
00072 m_leftbits = havebits - 24;
00073 data[i] |= m_char >> m_leftbits;
00074 m_char <<= 32 - havebits;
00075 numbits -= 32 - havebits;
00076 havebits = 32;
00077 }
00078 }
00079 }
00080
00081 if(numbits < 0)
00082 {
00083 m_char >>= -numbits;
00084 m_char |= data[i] << (havebits + numbits) >> 24;
00085 m_leftbits -= numbits;
00086 }
00087 }
00088
00089 void Bitstream::Write(const unsigned int *data, int numbits)
00090 {
00091 int i = 0;
00092 int havebits = (numbits < 32) ? numbits : 32;
00093 unsigned int dataword = data[0];
00094
00095 while(numbits > 0)
00096 {
00097 if(havebits + m_leftbits >= 8)
00098 {
00099 m_char |= dataword >> (24 + m_leftbits);
00100 WriteBytes(reinterpret_cast<char*>(&m_char), 1);
00101 dataword <<= 8 - m_leftbits;
00102 havebits -= 8 - m_leftbits;
00103 numbits -= 8 - m_leftbits;
00104 m_leftbits = 0;
00105 m_char = 0;
00106 }
00107 else
00108 {
00109 m_char |= dataword >> (24 + m_leftbits);
00110 m_leftbits += havebits;
00111 numbits -= havebits;
00112 havebits = (numbits < 32) ? numbits : 32;
00113 if(numbits > 0) dataword = data[++i];
00114 }
00115 }
00116 }
00117
00118 void Bitstream::Seek(int numbits)
00119 {
00120 assert(m_mode == in);
00121 assert(numbits > 0);
00122
00123 if(numbits <= m_leftbits)
00124 {
00125 m_leftbits -= numbits;
00126 m_char <<= numbits;
00127 }
00128 else
00129 {
00130 numbits -= m_leftbits;
00131 m_stream.seekg(numbits >> 3, std::ios::cur);
00132 numbits &= 7;
00133
00134 if(numbits)
00135 {
00136 ReadBytes(reinterpret_cast<char*>(&m_char), 1);
00137 m_char <<= numbits;
00138 m_leftbits = 8 - numbits;
00139 }
00140 else
00141 m_leftbits = 0;
00142 }
00143 }
00144
00145 int Bitstream::Find(unsigned int pattern, int numbits)
00146 {
00147 int aligned = (numbits + 7) & ~7;
00148 unsigned int mask = ~0 << (32 - numbits);
00149 unsigned int buffer = 0;
00150 int skipped = 0;
00151
00152 m_leftbits = 0;
00153 pattern <<= 32 - numbits;
00154
00155 Read(&buffer, aligned);
00156 while( (buffer & mask) != pattern )
00157 {
00158 ReadBytes(reinterpret_cast<char*>(&m_char), 1);
00159 skipped++;
00160 buffer <<= 8;
00161 buffer |= m_char << (32 - aligned);
00162 }
00163
00164 m_char = buffer >> (24 - numbits);
00165 m_leftbits = aligned - numbits;
00166
00167 return skipped;
00168 }
00169
00170 void Bitstream::ReadBytes(char *bytes, int num)
00171 {
00172 int newnum = num;
00173 assert(m_mode == in);
00174
00175 if(num + m_stream.tellg() >= m_size)
00176 newnum = m_size - m_stream.tellg();
00177
00178 if(!m_stream.read(bytes, newnum) || newnum < num)
00179 {
00180 newnum = m_stream.gcount();
00181
00182 #ifdef DEBUG
00183 std::cout << "read " << newnum << " bytes instead of " << num << "!" << std::endl;
00184 #endif
00185
00186 if(*m_files)
00187 {
00188 m_stream.close();
00189 m_stream.clear();
00190 m_leftbits = 0;
00191
00192 Open(*m_files);
00193 m_files++;
00194 throw eEOF(eEOF::partial, newnum);
00195 }
00196 else
00197 throw eEOF(eEOF::final, newnum);
00198 }
00199 }
00200
00201 void Bitstream::WriteBytes(const char *bytes, int num)
00202 {
00203 assert(m_mode == out);
00204 m_stream.write(bytes, num);
00205 }
00206
00207 void Bitstream::WriteNullBytes(int num)
00208 {
00209 assert(m_mode == out);
00210 for(int i = 0; i < num; i++)
00211 m_stream.put(0);
00212 }
00213
00214 void Bitstream::Open(const char *filename)
00215 {
00216 switch(m_mode)
00217 {
00218 case in: m_stream.open(filename, std::fstream::in | std::fstream::binary); break;
00219 case out: m_stream.open(filename, std::fstream::out | std::fstream::binary); break;
00220 }
00221
00222 if(!m_stream)
00223 throw eOpenFailed(filename);
00224
00225 if(m_mode == in)
00226 {
00227 m_stream.seekg(0, std::ios::end);
00228 m_size = m_stream.tellg();
00229
00230 CheckTag();
00231 m_stream.seekg(0, std::ios::beg);
00232
00233 #ifdef DEBUG
00234 std::cout << "File size " << m_size << " bytes" << std::endl;
00235 #endif
00236 }
00237 }
00238
00239 void Bitstream::CheckTag()
00240 {
00241 char tagheader[mp3_tag_v1::headersize];
00242
00243 if(m_size > mp3_tag_v1::size)
00244 {
00245 m_stream.seekg(-mp3_tag_v1::size, std::ios::end);
00246
00247 if(m_stream.read(tagheader, sizeof(tagheader)) && !memcmp(tagheader, mp3_tag_v1::header, sizeof(tagheader)))
00248 {
00249 #ifdef DEBUG
00250 std::cout << "ID3v1 tag detected" << std::endl;
00251 #endif
00252
00253 m_size -= mp3_tag_v1::size;
00254 }
00255 }
00256 }
00257
00258 const char *Bitstream::m_NULL = 0;