00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #if defined HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030
00031 #include "id3/io_decorators.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
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
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;
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
00272 for (size_t i = 0; i < sizeof(uint32); ++i)
00273 {
00274 if (reader.atEnd())
00275 {
00276 break;
00277 }
00278
00279 val = (val << BITSUSED) | static_cast<uint32>(reader.readChar()) & MASK(BITSUSED);
00280 }
00281
00282
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
00314
00315
00316 for (size_t i = 0; i < sizeof(uint32); ++i)
00317 {
00318
00319
00320 data[sizeof(uint32) - i - 1] = static_cast<uchar>(val & MASK(BITSUSED));
00321
00322
00323
00324 val >>= BITSUSED;
00325 }
00326
00327
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
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