id3lib  3.8.3
io_helpers.cpp
Go to the documentation of this file.
1 // $Id: io_helpers.cpp,v 1.13 2002/07/02 22:13:56 t1mpy Exp $
2 
3 // id3lib: a C++ library for creating and manipulating id3v1/v2 tags
4 // Copyright 1999, 2000 Scott Thomas Haug
5 
6 // This library is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU Library General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or (at your
9 // option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful, but WITHOUT
12 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14 // License for more details.
15 //
16 // You should have received a copy of the GNU Library General Public License
17 // along with this library; if not, write to the Free Software Foundation,
18 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 // The id3lib authors encourage improvements and optimisations to be sent to
21 // the id3lib coordinator. Please see the README file for details on where to
22 // send such submissions. See the AUTHORS file for a list of people who have
23 // contributed to id3lib. See the ChangeLog file for a list of changes to
24 // id3lib. These files are distributed with id3lib at
25 // http://download.sourceforge.net/id3lib/
26 
27 #if defined HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include "id3/io_decorators.h" //has "readers.h" "io_helpers.h" "utils.h"
32 
33 using namespace dami;
34 
35 String io::readString(ID3_Reader& reader)
36 {
37  String str;
38  while (!reader.atEnd())
39  {
40  ID3_Reader::char_type ch = reader.readChar();
41  if (ch == '\0')
42  {
43  break;
44  }
45  str += static_cast<char>(ch);
46  }
47  return str;
48 }
49 
50 String io::readText(ID3_Reader& reader, size_t len)
51 {
52  String str;
53  str.reserve(len);
54  const size_t SIZE = 1024;
55  ID3_Reader::char_type buf[SIZE];
56  size_t remaining = len;
57  while (remaining > 0 && !reader.atEnd())
58  {
59  size_t numRead = reader.readChars(buf, min(remaining, SIZE));
60  remaining -= numRead;
61  str.append(reinterpret_cast<String::value_type *>(buf), numRead);
62  }
63  return str;
64 }
65 
66 namespace
67 {
68  bool isNull(unsigned char ch1, unsigned char ch2)
69  {
70  return ch1 == '\0' && ch2 == '\0';
71  }
72 
73  int isBOM(unsigned char ch1, unsigned char ch2)
74  {
75  // The following is taken from the following URL:
76  // http://community.roxen.com/developers/idocs/rfc/rfc2781.html
77  /* The Unicode Standard and ISO 10646 define the character "ZERO WIDTH
78  NON-BREAKING SPACE" (0xFEFF), which is also known informally as
79  "BYTE ORDER MARK" (abbreviated "BOM"). The latter name hints at a
80  second possible usage of the character, in addition to its normal
81  use as a genuine "ZERO WIDTH NON-BREAKING SPACE" within text. This
82  usage, suggested by Unicode section 2.4 and ISO 10646 Annex F
83  (informative), is to prepend a 0xFEFF character to a stream of
84  Unicode characters as a "signature"; a receiver of such a serialized
85  stream may then use the initial character both as a hint that the
86  stream consists of Unicode characters and as a way to recognize the
87  serialization order. In serialized UTF-16 prepended with such a
88  signature, the order is big-endian if the first two octets are 0xFE
89  followed by 0xFF; if they are 0xFF followed by 0xFE, the order is
90  little-endian. Note that 0xFFFE is not a Unicode character,
91  precisely to preserve the usefulness of 0xFEFF as a byte-order
92  mark. */
93 
94  if (ch1 == 0xFE && ch2 == 0xFF)
95  {
96  return 1;
97  }
98  else if (ch1 == 0xFF && ch2 == 0xFE)
99  {
100  return -1;
101  }
102  return 0;
103  }
104 
105  bool readTwoChars(ID3_Reader& reader,
106  ID3_Reader::char_type& ch1,
108  {
109  if (reader.atEnd())
110  {
111  return false;
112  }
113  io::ExitTrigger et(reader);
114  ch1 = reader.readChar();
115  if (reader.atEnd())
116  {
117  return false;
118  }
119  et.release();
120  ch2 = reader.readChar();
121  return true;
122  }
123 }
124 
125 String io::readUnicodeString(ID3_Reader& reader)
126 {
127  String unicode;
128  ID3_Reader::char_type ch1, ch2;
129  if (!readTwoChars(reader, ch1, ch2) || isNull(ch1, ch2))
130  {
131  return unicode;
132  }
133  int bom = isBOM(ch1, ch2);
134  if (!bom)
135  {
136  unicode += static_cast<char>(ch1);
137  unicode += static_cast<char>(ch2);
138  }
139  while (!reader.atEnd())
140  {
141  if (!readTwoChars(reader, ch1, ch2) || isNull(ch1, ch2))
142  {
143  break;
144  }
145  if (bom == -1)
146  {
147  unicode += static_cast<char>(ch2);
148  unicode += static_cast<char>(ch1);
149  }
150  else
151  {
152  unicode += static_cast<char>(ch1);
153  unicode += static_cast<char>(ch2);
154  }
155  }
156  return unicode;
157 }
158 
159 String io::readUnicodeText(ID3_Reader& reader, size_t len)
160 {
161  String unicode;
162  ID3_Reader::char_type ch1, ch2;
163  if (!readTwoChars(reader, ch1, ch2))
164  {
165  return unicode;
166  }
167  len -= 2;
168  int bom = isBOM(ch1, ch2);
169  if (!bom)
170  {
171  unicode += ch1;
172  unicode += ch2;
173  unicode += readText(reader, len);
174  }
175  else if (bom == 1)
176  {
177  unicode = readText(reader, len);
178  }
179  else
180  {
181  for (size_t i = 0; i < len; i += 2)
182  {
183  if (!readTwoChars(reader, ch1, ch2))
184  {
185  break;
186  }
187  unicode += ch2;
188  unicode += ch1;
189  }
190  }
191  return unicode;
192 }
193 
194 BString io::readAllBinary(ID3_Reader& reader)
195 {
196  return readBinary(reader, reader.remainingBytes());
197 }
198 
199 BString io::readBinary(ID3_Reader& reader, size_t len)
200 {
201  BString binary;
202  binary.reserve(len);
203 
204  size_t remaining = len;
205  const size_t SIZE = 1024;
206  ID3_Reader::char_type buf[SIZE];
207  while (!reader.atEnd() && remaining > 0)
208  {
209  size_t numRead = reader.readChars(buf, min(remaining, SIZE));
210  remaining -= numRead;
211  binary.append(reinterpret_cast<BString::value_type *>(buf), numRead);
212  }
213 
214  return binary;
215 }
216 
217 uint32 io::readLENumber(ID3_Reader& reader, size_t len)
218 {
219  uint32 val = 0;
220  for (size_t i = 0; i < len; i++)
221  {
222  if (reader.atEnd())
223  {
224  break;
225  }
226  val += (static_cast<uint32>(0xFF & reader.readChar()) << (i * 8));
227  }
228  return val;
229 }
230 
231 uint32 io::readBENumber(ID3_Reader& reader, size_t len)
232 {
233  uint32 val = 0;
234 
235  for (ID3_Reader::size_type i = 0; i < len && !reader.atEnd(); ++i)
236  {
237  val *= 256; // 2^8
238  val += static_cast<uint32>(0xFF & reader.readChar());
239  }
240  return val;
241 }
242 
243 String io::readTrailingSpaces(ID3_Reader& reader, size_t len)
244 {
245  io::WindowedReader wr(reader, len);
246  String str;
247  String spaces;
248  str.reserve(len);
249  spaces.reserve(len);
250  while (!wr.atEnd())
251  {
252  ID3_Reader::char_type ch = wr.readChar();
253  if (ch == '\0' || ch == ' ')
254  {
255  spaces += ch;
256  }
257  else
258  {
259  str += spaces + (char) ch;
260  spaces.erase();
261  }
262  }
263  return str;
264 }
265 
266 uint32 io::readUInt28(ID3_Reader& reader)
267 {
268  uint32 val = 0;
269  const unsigned short BITSUSED = 7;
270  const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
271  // For each byte of the first 4 bytes in the string...
272  for (size_t i = 0; i < sizeof(uint32); ++i)
273  {
274  if (reader.atEnd())
275  {
276  break;
277  }
278  // ...append the last 7 bits to the end of the temp integer...
279  val = (val << BITSUSED) | static_cast<uint32>(reader.readChar()) & MASK(BITSUSED);
280  }
281 
282  // We should always parse 4 characters
283  return min(val, MAXVAL);
284 }
285 
286 size_t io::writeBENumber(ID3_Writer& writer, uint32 val, size_t len)
287 {
288  ID3_Writer::char_type bytes[sizeof(uint32)];
289  ID3_Writer::size_type size = min<ID3_Reader::size_type>(len, sizeof(uint32));
290  renderNumber(bytes, val, size);
291  return writer.writeChars(bytes, size);
292 }
293 
294 size_t io::writeTrailingSpaces(ID3_Writer& writer, String buf, size_t len)
295 {
296  ID3_Writer::pos_type beg = writer.getCur();
297  ID3_Writer::size_type strLen = buf.size();
298  ID3_Writer::size_type size = min((unsigned int)len, (unsigned int)strLen);
299  writer.writeChars(buf.data(), size);
300  for (; size < len; ++size)
301  {
302  writer.writeChar('\0');
303  }
304  return writer.getCur() - beg;
305 }
306 
307 size_t io::writeUInt28(ID3_Writer& writer, uint32 val)
308 {
309  uchar data[sizeof(uint32)];
310  const unsigned short BITSUSED = 7;
311  const uint32 MAXVAL = MASK(BITSUSED * sizeof(uint32));
312  val = min(val, MAXVAL);
313  // This loop renders the value to the character buffer in reverse order, as
314  // it is easy to extract the last 7 bits of an integer. This is why the
315  // loop shifts the value of the integer by 7 bits for each iteration.
316  for (size_t i = 0; i < sizeof(uint32); ++i)
317  {
318  // Extract the last BITSUSED bits from val and put it in its appropriate
319  // place in the data buffer
320  data[sizeof(uint32) - i - 1] = static_cast<uchar>(val & MASK(BITSUSED));
321 
322  // The last BITSUSED bits were extracted from the val. So shift it to the
323  // right by that many bits for the next iteration
324  val >>= BITSUSED;
325  }
326 
327  // Should always render 4 bytes
328  return writer.writeChars(data, sizeof(uint32));
329 }
330 
331 size_t io::writeString(ID3_Writer& writer, String data)
332 {
333  size_t size = writeText(writer, data);
334  writer.writeChar('\0');
335  return size + 1;
336 }
337 
338 size_t io::writeText(ID3_Writer& writer, String data)
339 {
340  ID3_Writer::pos_type beg = writer.getCur();
341  writer.writeChars(data.data(), data.size());
342  return writer.getCur() - beg;
343 }
344 
345 size_t io::writeUnicodeString(ID3_Writer& writer, String data, bool bom)
346 {
347  size_t size = writeUnicodeText(writer, data, bom);
348  unicode_t null = NULL_UNICODE;
349  writer.writeChars((const unsigned char*) &null, 2);
350  return size + 2;
351 }
352 
353 size_t io::writeUnicodeText(ID3_Writer& writer, String data, bool bom)
354 {
355  ID3_Writer::pos_type beg = writer.getCur();
356  size_t size = (data.size() / 2) * 2;
357  if (size == 0)
358  {
359  return 0;
360  }
361  if (bom)
362  {
363  // Write the BOM: 0xFEFF
364  unicode_t BOM = 0xFEFF;
365  writer.writeChars((const unsigned char*) &BOM, 2);
366  unsigned char *pdata = (unsigned char *) data.c_str();
367  unicode_t lastCh = BOM;
368  for (size_t i = 0; i < size; i += 2)
369  {
370  unicode_t ch = (pdata[i] << 8) | pdata[i+1];
371  if (lastCh == 0 && ch != BOM)
372  {
373  // Last character was NULL, so start next string with BOM.
374  writer.writeChars((const unsigned char*) &BOM, 2);
375  }
376  writer.writeChars((const unsigned char*) &ch, 2);
377  lastCh = ch;
378  }
379  }
380  return writer.getCur() - beg;
381 }
382 
virtual size_type readChars(char_type buf[], size_type len)=0
Read up to len characters into buf and advance the internal position accordingly.
virtual bool atEnd()
Definition: reader.h:125
virtual int_type readChar()
Read a single character and advance the internal position.
Definition: reader.h:65
virtual size_type remainingBytes()
Definition: reader.h:109
uint32 size_type
Definition: reader.h:36
uint8 char_type
Definition: reader.h:37
virtual size_type writeChars(const char_type buf[], size_type len)=0
Write up to len characters into buf and advance the internal position accordingly.
virtual int_type writeChar(char_type ch)
Write a single character and advance the internal position.
Definition: writer.h:71
uint8 char_type
Definition: writer.h:37
virtual pos_type getCur()=0
Return the next position that will be written to.
uint32 pos_type
Definition: writer.h:38
uint32 size_type
Definition: writer.h:36
#define MASK(bits)
Definition: globals.h:697
unsigned char uchar
Definition: globals.h:114
uint16 unicode_t
Definition: globals.h:117
#define NULL_UNICODE
Definition: globals.h:120
Definition: tag_impl.h:42
const T & min(const T &a, const T &b)
Definition: utils.h:51
size_t ID3_C_EXPORT renderNumber(uchar *buffer, uint32 val, size_t size=sizeof(uint32))
Definition: utils.cpp:92