src/io_helpers.cpp

Go to the documentation of this file.
00001 // $Id: io_helpers.cpp,v 1.13 2002/07/02 22:13:56 t1mpy Exp $
00002 
00003 // id3lib: a C++ library for creating and manipulating id3v1/v2 tags
00004 // Copyright 1999, 2000  Scott Thomas Haug
00005 
00006 // This library is free software; you can redistribute it and/or modify it
00007 // under the terms of the GNU Library General Public License as published by
00008 // the Free Software Foundation; either version 2 of the License, or (at your
00009 // option) any later version.
00010 //
00011 // This library is distributed in the hope that it will be useful, but WITHOUT
00012 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00014 // License for more details.
00015 //
00016 // You should have received a copy of the GNU Library General Public License
00017 // along with this library; if not, write to the Free Software Foundation,
00018 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019 
00020 // The id3lib authors encourage improvements and optimisations to be sent to
00021 // the id3lib coordinator.  Please see the README file for details on where to
00022 // send such submissions.  See the AUTHORS file for a list of people who have
00023 // contributed to id3lib.  See the ChangeLog file for a list of changes to
00024 // id3lib.  These files are distributed with id3lib at
00025 // http://download.sourceforge.net/id3lib/
00026 
00027 #if defined HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h"
00032 
00033 using namespace dami;
00034 
00035 String io::readString(ID3_Reader& reader)
00036 {
00037   String str;
00038   while (!reader.atEnd())
00039   {
00040     ID3_Reader::char_type ch = reader.readChar();
00041     if (ch == '\0')
00042     {
00043       break;
00044     }
00045     str += static_cast<char>(ch);
00046   }
00047   return str;
00048 }
00049 
00050 String io::readText(ID3_Reader& reader, size_t len)
00051 {
00052   String str;
00053   str.reserve(len);
00054   const size_t SIZE = 1024;
00055   ID3_Reader::char_type buf[SIZE];
00056   size_t remaining = len;
00057   while (remaining > 0 && !reader.atEnd())
00058   {
00059     size_t numRead = reader.readChars(buf, min(remaining, SIZE));
00060     remaining -= numRead;
00061     str.append(reinterpret_cast<String::value_type *>(buf), numRead);
00062   }
00063   return str;
00064 }
00065 
00066 namespace
00067 {
00068   bool isNull(unsigned char ch1, unsigned char ch2)
00069   {
00070     return ch1 == '\0' && ch2 == '\0';
00071   }
00072 
00073   int isBOM(unsigned char ch1, unsigned char ch2)
00074   {
00075   // The following is taken from the following URL:
00076   // http://community.roxen.com/developers/idocs/rfc/rfc2781.html
00077   /* The Unicode Standard and ISO 10646 define the character "ZERO WIDTH
00078      NON-BREAKING SPACE" (0xFEFF), which is also known informally as
00079      "BYTE ORDER MARK" (abbreviated "BOM"). The latter name hints at a
00080      second possible usage of the character, in addition to its normal
00081      use as a genuine "ZERO WIDTH NON-BREAKING SPACE" within text. This
00082      usage, suggested by Unicode section 2.4 and ISO 10646 Annex F
00083      (informative), is to prepend a 0xFEFF character to a stream of
00084      Unicode characters as a "signature"; a receiver of such a serialized
00085      stream may then use the initial character both as a hint that the
00086      stream consists of Unicode characters and as a way to recognize the
00087      serialization order. In serialized UTF-16 prepended with such a
00088      signature, the order is big-endian if the first two octets are 0xFE
00089      followed by 0xFF; if they are 0xFF followed by 0xFE, the order is
00090      little-endian. Note that 0xFFFE is not a Unicode character,
00091      precisely to preserve the usefulness of 0xFEFF as a byte-order
00092      mark. */
00093 
00094     if (ch1 == 0xFE && ch2 == 0xFF)
00095     {
00096       return 1;
00097     }
00098     else if (ch1 == 0xFF && ch2 == 0xFE)
00099     {
00100       return -1;
00101     }
00102     return 0;
00103   }
00104 
00105   bool readTwoChars(ID3_Reader& reader, 
00106                     ID3_Reader::char_type& ch1, 
00107                     ID3_Reader::char_type& ch2)
00108   {
00109     if (reader.atEnd())
00110     {
00111       return false;
00112     }
00113     io::ExitTrigger et(reader);
00114     ch1 = reader.readChar();
00115     if (reader.atEnd())
00116     {
00117       return false;
00118     }
00119     et.release();
00120     ch2 = reader.readChar();
00121     return true;
00122   }
00123 }
00124 
00125 String io::readUnicodeString(ID3_Reader& reader)
00126 {
00127   String unicode;
00128   ID3_Reader::char_type ch1, ch2;
00129   if (!readTwoChars(reader, ch1, ch2) || isNull(ch1, ch2))
00130   {
00131     return unicode;
00132   }
00133   int bom = isBOM(ch1, ch2);
00134   if (!bom)
00135   {
00136     unicode += static_cast<char>(ch1);
00137     unicode += static_cast<char>(ch2);
00138   }
00139   while (!reader.atEnd())
00140   {
00141     if (!readTwoChars(reader, ch1, ch2) || isNull(ch1, ch2))
00142     {
00143       break;
00144     }
00145     if (bom == -1)
00146     {
00147       unicode += static_cast<char>(ch2);
00148       unicode += static_cast<char>(ch1);
00149     }
00150     else
00151     {
00152       unicode += static_cast<char>(ch1);
00153       unicode += static_cast<char>(ch2);
00154     }
00155   }
00156   return unicode;
00157 }
00158 
00159 String io::readUnicodeText(ID3_Reader& reader, size_t len)
00160 {
00161   String unicode;
00162   ID3_Reader::char_type ch1, ch2;
00163   if (!readTwoChars(reader, ch1, ch2))
00164   {
00165     return unicode;
00166   }
00167   len -= 2;
00168   int bom = isBOM(ch1, ch2);
00169   if (!bom)
00170   {
00171     unicode += ch1;
00172     unicode += ch2;
00173     unicode += readText(reader, len);
00174   }
00175   else if (bom == 1)
00176   {
00177     unicode = readText(reader, len);
00178   }
00179   else
00180   {
00181     for (size_t i = 0; i < len; i += 2)
00182     {
00183       if (!readTwoChars(reader, ch1, ch2))
00184       {
00185         break;
00186       }
00187       unicode += ch2;
00188       unicode += ch1;
00189     }
00190   }
00191   return unicode;
00192 }
00193 
00194 BString io::readAllBinary(ID3_Reader& reader)
00195 {
00196   return readBinary(reader, reader.remainingBytes());
00197 }
00198 
00199 BString io::readBinary(ID3_Reader& reader, size_t len)
00200 {
00201   BString binary;
00202   binary.reserve(len);
00203   
00204   size_t remaining = len;
00205   const size_t SIZE = 1024;
00206   ID3_Reader::char_type buf[SIZE];
00207   while (!reader.atEnd() && remaining > 0)
00208   {
00209     size_t numRead = reader.readChars(buf, min(remaining, SIZE));
00210     remaining -= numRead;
00211     binary.append(reinterpret_cast<BString::value_type *>(buf), numRead);
00212   }
00213   
00214   return binary;
00215 }
00216 
00217 uint32 io::readLENumber(ID3_Reader& reader, size_t len)
00218 {
00219   uint32 val = 0;
00220   for (size_t i = 0; i < len; i++)
00221   {
00222     if (reader.atEnd())
00223     {
00224       break;
00225     }
00226     val += (static_cast<uint32>(0xFF & reader.readChar()) << (i * 8));
00227   }
00228   return val;
00229 }
00230 
00231 uint32 io::readBENumber(ID3_Reader& reader, size_t len)
00232 {
00233   uint32 val = 0;
00234   
00235   for (ID3_Reader::size_type i = 0; i < len && !reader.atEnd(); ++i)
00236   {
00237     val *= 256; // 2^8
00238     val += static_cast<uint32>(0xFF & reader.readChar());
00239   }
00240   return val;
00241 }
00242 
00243 String io::readTrailingSpaces(ID3_Reader& reader, size_t len)
00244 {
00245   io::WindowedReader wr(reader, len);
00246   String str;
00247   String spaces;
00248   str.reserve(len);
00249   spaces.reserve(len);
00250   while (!wr.atEnd())
00251   {
00252     ID3_Reader::char_type ch = wr.readChar();
00253     if (ch == '\0' || ch == ' ')
00254     {
00255       spaces += ch;
00256     }
00257     else
00258     {
00259       str += spaces + (char) ch;
00260       spaces.erase();
00261     }
00262   }
00263   return str;
00264 }
00265 
00266 uint32 io::readUInt28(ID3_Reader& reader)
00267 {
00268   uint32 val = 0;
00269   const unsigned short BITSUSED = 7;
00270   const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
00271   // For each byte of the first 4 bytes in the string...
00272   for (size_t i = 0; i < sizeof(uint32); ++i)
00273   {
00274     if (reader.atEnd())
00275     {
00276       break;
00277     }
00278     // ...append the last 7 bits to the end of the temp integer...
00279     val = (val << BITSUSED) | static_cast<uint32>(reader.readChar()) & MASK(BITSUSED);
00280   }
00281 
00282   // We should always parse 4 characters
00283   return min(val, MAXVAL);
00284 }
00285 
00286 size_t io::writeBENumber(ID3_Writer& writer, uint32 val, size_t len)
00287 {
00288   ID3_Writer::char_type bytes[sizeof(uint32)];
00289   ID3_Writer::size_type size = min<ID3_Reader::size_type>(len, sizeof(uint32));
00290   renderNumber(bytes, val, size);
00291   return writer.writeChars(bytes, size);
00292 }
00293 
00294 size_t io::writeTrailingSpaces(ID3_Writer& writer, String buf, size_t len)
00295 {
00296   ID3_Writer::pos_type beg = writer.getCur();
00297   ID3_Writer::size_type strLen = buf.size();
00298   ID3_Writer::size_type size = min((unsigned int)len, (unsigned int)strLen);
00299   writer.writeChars(buf.data(), size);
00300   for (; size < len; ++size)
00301   {
00302     writer.writeChar('\0');
00303   }
00304   return writer.getCur() - beg;
00305 }
00306 
00307 size_t io::writeUInt28(ID3_Writer& writer, uint32 val)
00308 {
00309   uchar data[sizeof(uint32)];
00310   const unsigned short BITSUSED = 7;
00311   const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
00312   val = min(val, MAXVAL);
00313   // This loop renders the value to the character buffer in reverse order, as 
00314   // it is easy to extract the last 7 bits of an integer.  This is why the
00315   // loop shifts the value of the integer by 7 bits for each iteration.
00316   for (size_t i = 0; i < sizeof(uint32); ++i)
00317   {
00318     // Extract the last BITSUSED bits from val and put it in its appropriate
00319     // place in the data buffer
00320     data[sizeof(uint32) - i - 1] = static_cast<uchar>(val & MASK(BITSUSED));
00321 
00322     // The last BITSUSED bits were extracted from the val.  So shift it to the
00323     // right by that many bits for the next iteration
00324     val >>= BITSUSED;
00325   }
00326   
00327   // Should always render 4 bytes
00328   return writer.writeChars(data, sizeof(uint32));
00329 }
00330 
00331 size_t io::writeString(ID3_Writer& writer, String data)
00332 {
00333   size_t size = writeText(writer, data);
00334   writer.writeChar('\0');
00335   return size + 1;
00336 }
00337 
00338 size_t io::writeText(ID3_Writer& writer, String data)
00339 {
00340   ID3_Writer::pos_type beg = writer.getCur();
00341   writer.writeChars(data.data(), data.size());
00342   return writer.getCur() - beg;
00343 }
00344 
00345 size_t io::writeUnicodeString(ID3_Writer& writer, String data, bool bom)
00346 {
00347   size_t size = writeUnicodeText(writer, data, bom);
00348   unicode_t null = NULL_UNICODE;
00349   writer.writeChars((const unsigned char*) &null, 2);
00350   return size + 2;
00351 }
00352 
00353 size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
00354 {
00355   ID3_Writer::pos_type beg = writer.getCur();
00356   size_t size = (data.size() / 2) * 2;
00357   if (size == 0)
00358   {
00359     return 0;
00360   }
00361   if (bom)
00362   {
00363     // Write the BOM: 0xFEFF
00364     unicode_t BOM = 0xFEFF;
00365     writer.writeChars((const unsigned char*) &BOM, 2);
00366     const unsigned char* pdata = (const unsigned char*)data.c_str();
00367     for (size_t i = 0; i < size; i += 2)
00368     {
00369       unicode_t ch = (pdata[i] << 8) | pdata[i+1];
00370       writer.writeChars((const unsigned char*) &ch, 2);
00371     }
00372   }
00373   return writer.getCur() - beg;
00374 }
00375 

Generated on Mon Aug 20 17:48:46 2007 for id3lib by  doxygen 1.5.2