Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

src/io_helpers.cpp

Go to the documentation of this file.
00001 // $Id: io_helpers.cpp,v 1.8 2001/09/08 21:19:49 shadrack 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 
00032 
00033 #include "io_decorators.h"
00034 #include "io_helpers.h"
00035 #include "utils.h"
00036 
00037 using namespace dami;
00038 
00039 String io::readString(ID3_Reader& reader)
00040 {
00041   String str;
00042   while (!reader.atEnd())
00043   {
00044     ID3_Reader::char_type ch = reader.readChar();
00045     if (ch == '\0')
00046     {
00047       break;
00048     }
00049     str += static_cast<char>(ch);
00050   }
00051   return str;
00052 }
00053 
00054 String io::readText(ID3_Reader& reader, size_t len)
00055 {
00056   String str;
00057   str.reserve(len);
00058   const size_t SIZE = 1024;
00059   ID3_Reader::char_type buf[SIZE];
00060   size_t remaining = len;
00061   while (remaining > 0 && !reader.atEnd())
00062   {
00063     size_t numRead = reader.readChars(buf, min(remaining, SIZE));
00064     remaining -= numRead;
00065     str.append(reinterpret_cast<String::value_type *>(buf), numRead);
00066   }
00067   return str;
00068 }
00069 
00070 namespace
00071 {
00072   bool isNull(unsigned char ch1, unsigned char ch2)
00073   {
00074     return ch1 == '\0' && ch2 == '\0';
00075   }
00076 
00077   int isBOM(unsigned char ch1, unsigned char ch2)
00078   {
00079   // The following is taken from the following URL:
00080   // http://community.roxen.com/developers/idocs/rfc/rfc2781.html
00081   /* The Unicode Standard and ISO 10646 define the character "ZERO WIDTH
00082      NON-BREAKING SPACE" (0xFEFF), which is also known informally as
00083      "BYTE ORDER MARK" (abbreviated "BOM"). The latter name hints at a
00084      second possible usage of the character, in addition to its normal
00085      use as a genuine "ZERO WIDTH NON-BREAKING SPACE" within text. This
00086      usage, suggested by Unicode section 2.4 and ISO 10646 Annex F
00087      (informative), is to prepend a 0xFEFF character to a stream of
00088      Unicode characters as a "signature"; a receiver of such a serialized
00089      stream may then use the initial character both as a hint that the
00090      stream consists of Unicode characters and as a way to recognize the
00091      serialization order. In serialized UTF-16 prepended with such a
00092      signature, the order is big-endian if the first two octets are 0xFE
00093      followed by 0xFF; if they are 0xFF followed by 0xFE, the order is
00094      little-endian. Note that 0xFFFE is not a Unicode character,
00095      precisely to preserve the usefulness of 0xFEFF as a byte-order
00096      mark. */
00097 
00098     if (ch1 == 0xFE && ch2 == 0xFF)
00099     {
00100       return 1;
00101     }
00102     else if (ch1 == 0xFF && ch2 == 0xFE)
00103     {
00104       return -1;
00105     }
00106     return 0;
00107   }
00108 
00109   bool readTwoChars(ID3_Reader& reader, 
00110                     ID3_Reader::char_type& ch1, 
00111                     ID3_Reader::char_type& ch2)
00112   {
00113     if (reader.atEnd())
00114     {
00115       return false;
00116     }
00117     io::ExitTrigger et(reader);
00118     ch1 = reader.readChar();
00119     if (reader.atEnd())
00120     {
00121       return false;
00122     }
00123     et.release();
00124     ch2 = reader.readChar();
00125     return true;
00126   }
00127 }
00128 
00129 String io::readUnicodeString(ID3_Reader& reader)
00130 {
00131   String unicode;
00132   ID3_Reader::char_type ch1, ch2;
00133   if (!readTwoChars(reader, ch1, ch2) || isNull(ch1, ch2))
00134   {
00135     return unicode;
00136   }
00137   int bom = isBOM(ch1, ch2);
00138   if (!bom)
00139   {
00140     unicode += static_cast<char>(ch1);
00141     unicode += static_cast<char>(ch2);
00142   }
00143   while (!reader.atEnd())
00144   {
00145     if (!readTwoChars(reader, ch1, ch2) || isNull(ch1, ch2))
00146     {
00147       break;
00148     }
00149     if (bom == -1)
00150     {
00151       unicode += static_cast<char>(ch2);
00152       unicode += static_cast<char>(ch1);
00153     }
00154     else
00155     {
00156       unicode += static_cast<char>(ch1);
00157       unicode += static_cast<char>(ch2);
00158     }
00159   }
00160   return unicode;
00161 }
00162 
00163 String io::readUnicodeText(ID3_Reader& reader, size_t len)
00164 {
00165   String unicode;
00166   ID3_Reader::char_type ch1, ch2;
00167   if (!readTwoChars(reader, ch1, ch2))
00168   {
00169     return unicode;
00170   }
00171   len -= 2;
00172   int bom = isBOM(ch1, ch2);
00173   if (!bom)
00174   {
00175     unicode += ch1;
00176     unicode += ch2;
00177     unicode += readText(reader, len);
00178   }
00179   else if (bom == 1)
00180   {
00181     unicode = readText(reader, len);
00182   }
00183   else
00184   {
00185     for (index_t i = 0; i < len; i += 2)
00186     {
00187       if (!readTwoChars(reader, ch1, ch2))
00188       {
00189         break;
00190       }
00191       unicode += ch2;
00192       unicode += ch1;
00193     }
00194   }
00195   return unicode;
00196 }
00197 
00198 BString io::readAllBinary(ID3_Reader& reader)
00199 {
00200   return readBinary(reader, reader.remainingBytes());
00201 }
00202 
00203 BString io::readBinary(ID3_Reader& reader, size_t len)
00204 {
00205   BString binary;
00206   binary.reserve(len);
00207   
00208   size_t remaining = len;
00209   const size_t SIZE = 1024;
00210   ID3_Reader::char_type buf[SIZE];
00211   while (!reader.atEnd() && remaining > 0)
00212   {
00213     size_t numRead = reader.readChars(buf, min(remaining, SIZE));
00214     remaining -= numRead;
00215     binary.append(reinterpret_cast<BString::value_type *>(buf), numRead);
00216   }
00217   
00218   return binary;
00219 }
00220 
00221 uint32 io::readLENumber(ID3_Reader& reader, size_t len)
00222 {
00223   uint32 val = 0;
00224   for (size_t i = 0; i < len; i++)
00225   {
00226     if (reader.atEnd())
00227     {
00228       break;
00229     }
00230     val += (static_cast<uint32>(0xFF & reader.readChar()) << (i * 8));
00231   }
00232   return val;
00233 }
00234 
00235 uint32 io::readBENumber(ID3_Reader& reader, size_t len)
00236 {
00237   uint32 val = 0;
00238   
00239   for (ID3_Reader::size_type i = 0; i < len && !reader.atEnd(); ++i)
00240   {
00241     val *= 256; // 2^8
00242     val += static_cast<uint32>(0xFF & reader.readChar());
00243   }
00244   return val;
00245 }
00246 
00247 String io::readTrailingSpaces(ID3_Reader& reader, size_t len)
00248 {
00249   io::WindowedReader wr(reader, len);
00250   String str;
00251   String spaces;
00252   str.reserve(len);
00253   spaces.reserve(len);
00254   while (!wr.atEnd())
00255   {
00256     ID3_Reader::char_type ch = wr.readChar();
00257     if (ch == '\0' || ch == ' ')
00258     {
00259       spaces += ch;
00260     }
00261     else
00262     {
00263       str += spaces + (char) ch;
00264       spaces.erase();
00265     }
00266   }
00267   return str;
00268 }
00269 
00270 uint32 io::readUInt28(ID3_Reader& reader)
00271 {
00272   uint32 val = 0;
00273   const unsigned short BITSUSED = 7;
00274   const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
00275   // For each byte of the first 4 bytes in the string...
00276   for (size_t i = 0; i < sizeof(uint32); ++i)
00277   {
00278     if (reader.atEnd())
00279     {
00280       break;
00281     }
00282     // ...append the last 7 bits to the end of the temp integer...
00283     val = (val << BITSUSED) | static_cast<uint32>(reader.readChar()) & MASK(BITSUSED);
00284   }
00285 
00286   // We should always parse 4 characters
00287   return min(val, MAXVAL);
00288 }
00289 
00290 size_t io::writeBENumber(ID3_Writer& writer, uint32 val, size_t len)
00291 {
00292   ID3_Writer::char_type bytes[sizeof(uint32)];
00293   ID3_Writer::size_type size = min<ID3_Reader::size_type>(len, sizeof(uint32));
00294   renderNumber(bytes, val, size);
00295   return writer.writeChars(bytes, size);
00296 }
00297 
00298 size_t io::writeTrailingSpaces(ID3_Writer& writer, String buf, size_t len)
00299 {
00300   ID3_Writer::pos_type beg = writer.getCur();
00301   ID3_Writer::size_type strLen = buf.size();
00302   ID3_Writer::size_type size = min(len,strLen);
00303   writer.writeChars(buf.data(), size);
00304   for (; size < len; ++size)
00305   {
00306     writer.writeChar(' ');
00307   }
00308   return writer.getCur() - beg;
00309 }
00310 
00311 size_t io::writeUInt28(ID3_Writer& writer, uint32 val)
00312 {
00313   uchar data[sizeof(uint32)];
00314   const unsigned short BITSUSED = 7;
00315   const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
00316   val = min(val, MAXVAL);
00317   // This loop renders the value to the character buffer in reverse order, as 
00318   // it is easy to extract the last 7 bits of an integer.  This is why the
00319   // loop shifts the value of the integer by 7 bits for each iteration.
00320   for (size_t i = 0; i < sizeof(uint32); ++i)
00321   {
00322     // Extract the last BITSUSED bits from val and put it in its appropriate
00323     // place in the data buffer
00324     data[sizeof(uint32) - i - 1] = static_cast<uchar>(val & MASK(BITSUSED));
00325 
00326     // The last BITSUSED bits were extracted from the val.  So shift it to the
00327     // right by that many bits for the next iteration
00328     val >>= BITSUSED;
00329   }
00330   
00331   // Should always render 4 bytes
00332   return writer.writeChars(data, sizeof(uint32));
00333 }
00334 
00335 size_t io::writeString(ID3_Writer& writer, String data)
00336 {
00337   size_t size = writeText(writer, data);
00338   writer.writeChar('\0');
00339   return size + 1;
00340 }
00341 
00342 size_t io::writeText(ID3_Writer& writer, String data)
00343 {
00344   ID3_Writer::pos_type beg = writer.getCur();
00345   writer.writeChars(data.data(), data.size());
00346   return writer.getCur() - beg;
00347 }
00348 
00349 size_t io::writeUnicodeString(ID3_Writer& writer, String data, bool bom)
00350 {
00351   size_t size = writeUnicodeText(writer, data, bom);
00352   unicode_t null = NULL_UNICODE;
00353   writer.writeChars((const unsigned char*) &null, 2);
00354   return size + 2;
00355 }
00356 
00357 size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
00358 {
00359   ID3_Writer::pos_type beg = writer.getCur();
00360   size_t size = (data.size() / 2) * 2;
00361   if (size == 0)
00362   {
00363     return 0;
00364   }
00365   if (bom)
00366   {
00367     // Write the BOM: 0xFEFF
00368     unicode_t BOM = 0xFEFF;
00369     writer.writeChars((const unsigned char*) &BOM, 2);
00370     for (size_t i = 0; i < size; i += 2)
00371     {
00372       unicode_t ch = (data[i] << 8) | data[i+1];
00373       writer.writeChars((const unsigned char*) &ch, 2);
00374     }
00375   }
00376   return writer.getCur() - beg;
00377 }

Generated at Sat Sep 8 15:51:09 2001 for id3lib by doxygen1.2.8 written by Dimitri van Heesch, © 1997-2001