Main Page | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

bitstream.cpp

Go to the documentation of this file.
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; //No next file
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; //Store rest of files
00035   
00036   assert(*files);
00037   Open(*files); //Open first file
00038 }
00039 
00040 void Bitstream::Read(unsigned int *data, int numbits)
00041 {
00042   int havebits = 32; //Go to next (first) int
00043   int i = -1; //First operation is i++
00044 
00045   assert(data);
00046   assert(numbits > 0);
00047   
00048   while(numbits > 0) //While we need to read some more bits
00049   {  
00050     if(havebits == 32) //Int is full
00051     {
00052       data[++i] = m_char << 24; //Place the char to high-order bits
00053       numbits -= m_leftbits; //We have as much bits 
00054       havebits = m_leftbits; // as in m_char
00055       m_char = 0;
00056       m_leftbits = 0;
00057     }
00058     else
00059     {
00060       //This is ugly, but m_char muset be unsigned for shifts
00061       ReadBytes(reinterpret_cast<char*>(&m_char), 1);
00062       
00063       if(havebits <= 24) //We can read a full character
00064       {
00065         data[i] |= m_char << (24 - havebits); //Place the char after read bits
00066         havebits += 8;
00067         numbits -= 8;
00068         m_char = 0;
00069       }
00070       else //The character is on integer boundary
00071       {
00072         m_leftbits = havebits - 24; //Some bytes have to be kept in char
00073         data[i] |= m_char >> m_leftbits; //Other bits are appended to int
00074         m_char <<= 32 - havebits; //Remove appended bits 
00075         numbits -= 32 - havebits;
00076         havebits = 32; //Integer is full, move to next in next step
00077       }
00078     }
00079   }
00080   
00081   if(numbits < 0) //We have more bits than we need
00082   {
00083     m_char >>= -numbits; //Make place for these bits
00084     m_char |= data[i] << (havebits + numbits) >> 24; //Move the bits back
00085     m_leftbits -= numbits; //And remember how many are they
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; //Number of bits in first int
00093   unsigned int dataword = data[0]; //Copy bits (don't change input)
00094   
00095   while(numbits > 0) //While there's something to write
00096   {
00097     if(havebits + m_leftbits >= 8) //We have at least one byte
00098     {
00099       m_char |= dataword >> (24 + m_leftbits); //Complete the char with bits from dataword
00100       WriteBytes(reinterpret_cast<char*>(&m_char), 1);
00101       dataword <<= 8 - m_leftbits; //Remove written bits
00102       havebits -= 8 - m_leftbits; 
00103       numbits -= 8 - m_leftbits;
00104       m_leftbits = 0; 
00105       m_char = 0;
00106     }
00107     else //We don't have a full byte, we have to keep the bits
00108     {
00109       m_char |= dataword >> (24 + m_leftbits); //Append the bits to m_char
00110       m_leftbits += havebits;
00111       numbits -= havebits;
00112       havebits = (numbits < 32) ? numbits : 32; //Continue to next integer
00113       if(numbits > 0) dataword = data[++i]; //Check needed to prevent possible segfault
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) //Just a little seek in m_char
00124   {                         // (drop a few bits)
00125     m_leftbits -= numbits;
00126     m_char <<= numbits;
00127   }
00128   else
00129   {
00130     numbits -= m_leftbits; //Throw bits in m_char
00131     m_stream.seekg(numbits >> 3, std::ios::cur); //Real seek in stream
00132     numbits &= 7; //Left bits (modulo 8)
00133     
00134     if(numbits)
00135     {   //Read character so we can seek in it
00136         ReadBytes(reinterpret_cast<char*>(&m_char), 1);
00137         m_char <<= numbits; //Seek in m_char
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; //Align pattern to byte boundary
00148   unsigned int mask = ~0 << (32 - numbits); //Mask to select bits in pattern
00149   unsigned int buffer = 0; //Read bytes to compare with pattern
00150   int skipped = 0; //Bytes read before match was found
00151   
00152   m_leftbits = 0; //Match is always on byte boundary
00153   pattern <<= 32 - numbits; //Move the pattern to high-order bits
00154   
00155   Read(&buffer, aligned); //Reads enough bytes to try a first comparison
00156   while( (buffer & mask) != pattern ) //Until pattern is found
00157   {  
00158     ReadBytes(reinterpret_cast<char*>(&m_char), 1);
00159     skipped++;
00160     buffer <<= 8; //Add character to buffer
00161     buffer |= m_char << (32 - aligned);
00162   }  
00163   
00164   m_char = buffer >> (24 - numbits); //Remove bits left from pattern
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) //EOF
00179   {  
00180     newnum = m_stream.gcount(); //Number of bytes really read
00181     
00182     #ifdef DEBUG
00183     std::cout << "read " << newnum << " bytes instead of " << num << "!" << std::endl;
00184     #endif
00185     
00186     if(*m_files) //There's some next file
00187     {  
00188       m_stream.close();
00189       m_stream.clear(); //Must be here for some reason!
00190       m_leftbits = 0;
00191       
00192       Open(*m_files);
00193       m_files++;
00194       throw eEOF(eEOF::partial, newnum); //Report state by exception
00195     }
00196     else
00197       throw eEOF(eEOF::final, newnum); //Total EOF
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) //File not found, send filename in what()
00223     throw eOpenFailed(filename);
00224 
00225   if(m_mode == in) //Get file size (without ID3v1 tag)
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;

Generated on Wed Sep 6 00:17:56 2006 for Kraken by  doxygen 1.4.4