~njh-aelius/maxosx/musicbrainz-tags

« back to all changes in this revision

Viewing changes to Frameworks/taglib/taglib/taglib/toolkit/tstring.cpp

  • Committer: stephen_booth
  • Date: 2008-04-30 01:48:01 UTC
  • Revision ID: svn-v4:6b6cea13-1402-0410-9567-a7afb52bf336:trunk:1371
Fixing the taglib source tree

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
    copyright            : (C) 2002 - 2008 by Scott Wheeler
3
 
    email                : wheeler@kde.org
4
 
 ***************************************************************************/
5
 
 
6
 
/***************************************************************************
7
 
 *   This library is free software; you can redistribute it and/or modify  *
8
 
 *   it under the terms of the GNU Lesser General Public License version   *
9
 
 *   2.1 as published by the Free Software Foundation.                     *
10
 
 *                                                                         *
11
 
 *   This library is distributed in the hope that it will be useful, but   *
12
 
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
13
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14
 
 *   Lesser General Public License for more details.                       *
15
 
 *                                                                         *
16
 
 *   You should have received a copy of the GNU Lesser General Public      *
17
 
 *   License along with this library; if not, write to the Free Software   *
18
 
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19
 
 *   USA                                                                   *
20
 
 *                                                                         *
21
 
 *   Alternatively, this file is available under the Mozilla Public        *
22
 
 *   License Version 1.1.  You may obtain a copy of the License at         *
23
 
 *   http://www.mozilla.org/MPL/                                           *
24
 
 ***************************************************************************/
25
 
 
26
 
#include "tstring.h"
27
 
#include "unicode.h"
28
 
#include "tdebug.h"
29
 
 
30
 
#include <iostream>
31
 
 
32
 
#include <string.h>
33
 
 
34
 
namespace TagLib {
35
 
 
36
 
  inline unsigned short byteSwap(unsigned short x)
37
 
  {
38
 
    return ((x) >> 8) & 0xff | ((x) & 0xff) << 8;
39
 
  }
40
 
 
41
 
  inline unsigned short combine(unsigned char c1, unsigned char c2)
42
 
  {
43
 
    return (c1 << 8) | c2;
44
 
  }
45
 
}
46
 
 
47
 
using namespace TagLib;
48
 
 
49
 
class String::StringPrivate : public RefCounter
50
 
{
51
 
public:
52
 
  StringPrivate(const wstring &s) :
53
 
    RefCounter(),
54
 
    data(s),
55
 
    CString(0) {}
56
 
 
57
 
  StringPrivate() :
58
 
    RefCounter(),
59
 
    CString(0) {}
60
 
 
61
 
  ~StringPrivate() {
62
 
    delete [] CString;
63
 
  }
64
 
 
65
 
  wstring data;
66
 
 
67
 
  /*!
68
 
   * This is only used to hold the a pointer to the most recent value of
69
 
   * toCString.
70
 
   */
71
 
  char *CString;
72
 
};
73
 
 
74
 
String String::null;
75
 
 
76
 
////////////////////////////////////////////////////////////////////////////////
77
 
 
78
 
String::String()
79
 
{
80
 
  d = new StringPrivate;
81
 
}
82
 
 
83
 
String::String(const String &s) : d(s.d)
84
 
{
85
 
  d->ref();
86
 
}
87
 
 
88
 
String::String(const std::string &s, Type t)
89
 
{
90
 
  d = new StringPrivate;
91
 
 
92
 
  if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
93
 
    debug("String::String() -- A std::string should not contain UTF16.");
94
 
    return;
95
 
  }
96
 
 
97
 
  int length = s.length();
98
 
  d->data.resize(length);
99
 
  wstring::iterator targetIt = d->data.begin();
100
 
 
101
 
  for(std::string::const_iterator it = s.begin(); it != s.end(); it++) {
102
 
    *targetIt = uchar(*it);
103
 
    ++targetIt;
104
 
  }
105
 
 
106
 
  prepare(t);
107
 
}
108
 
 
109
 
String::String(const wstring &s, Type t)
110
 
{
111
 
  d = new StringPrivate(s);
112
 
  prepare(t);
113
 
}
114
 
 
115
 
String::String(const wchar_t *s, Type t)
116
 
{
117
 
  d = new StringPrivate(s);
118
 
  prepare(t);
119
 
}
120
 
 
121
 
String::String(const char *s, Type t)
122
 
{
123
 
  d = new StringPrivate;
124
 
 
125
 
  if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
126
 
    debug("String::String() -- A const char * should not contain UTF16.");
127
 
    return;
128
 
  }
129
 
 
130
 
  int length = ::strlen(s);
131
 
  d->data.resize(length);
132
 
 
133
 
  wstring::iterator targetIt = d->data.begin();
134
 
 
135
 
  for(int i = 0; i < length; i++) {
136
 
    *targetIt = uchar(s[i]);
137
 
    ++targetIt;
138
 
  }
139
 
 
140
 
  prepare(t);
141
 
}
142
 
 
143
 
String::String(wchar_t c, Type t)
144
 
{
145
 
  d = new StringPrivate;
146
 
  d->data += c;
147
 
  prepare(t);
148
 
}
149
 
 
150
 
String::String(char c, Type t)
151
 
{
152
 
  d = new StringPrivate;
153
 
 
154
 
  if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
155
 
    debug("String::String() -- A std::string should not contain UTF16.");
156
 
    return;
157
 
  }
158
 
 
159
 
  d->data += uchar(c);
160
 
  prepare(t);
161
 
}
162
 
 
163
 
String::String(const ByteVector &v, Type t)
164
 
{
165
 
  d = new StringPrivate;
166
 
 
167
 
  if(v.isEmpty())
168
 
    return;
169
 
 
170
 
  if(t == Latin1 || t == UTF8) {
171
 
 
172
 
    int length = 0;
173
 
    d->data.resize(v.size());
174
 
    wstring::iterator targetIt = d->data.begin();
175
 
    for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
176
 
      *targetIt = uchar(*it);
177
 
      ++targetIt;
178
 
      ++length;
179
 
    }
180
 
    d->data.resize(length);
181
 
  }
182
 
  else  {
183
 
    d->data.resize(v.size() / 2);
184
 
    wstring::iterator targetIt = d->data.begin();
185
 
 
186
 
    for(ByteVector::ConstIterator it = v.begin();
187
 
        it != v.end() && it + 1 != v.end() && combine(*it, *(it + 1));
188
 
        it += 2)
189
 
    {
190
 
      *targetIt = combine(*it, *(it + 1));
191
 
      ++targetIt;
192
 
    }
193
 
  }
194
 
  prepare(t);
195
 
}
196
 
 
197
 
////////////////////////////////////////////////////////////////////////////////
198
 
 
199
 
String::~String()
200
 
{
201
 
  if(d->deref())
202
 
    delete d;
203
 
}
204
 
 
205
 
std::string String::to8Bit(bool unicode) const
206
 
{
207
 
  std::string s;
208
 
  s.resize(d->data.size());
209
 
 
210
 
  if(!unicode) {
211
 
    std::string::iterator targetIt = s.begin();
212
 
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
213
 
      *targetIt = char(*it);
214
 
      ++targetIt;
215
 
    }
216
 
    return s;
217
 
  }
218
 
 
219
 
  const int outputBufferSize = d->data.size() * 3 + 1;
220
 
 
221
 
  Unicode::UTF16 *sourceBuffer = new Unicode::UTF16[d->data.size() + 1];
222
 
  Unicode::UTF8  *targetBuffer = new Unicode::UTF8[outputBufferSize];
223
 
 
224
 
  for(unsigned int i = 0; i < d->data.size(); i++)
225
 
    sourceBuffer[i] = Unicode::UTF16(d->data[i]);
226
 
 
227
 
  const Unicode::UTF16 *source = sourceBuffer;
228
 
  Unicode::UTF8 *target = targetBuffer;
229
 
 
230
 
  Unicode::ConversionResult result =
231
 
    Unicode::ConvertUTF16toUTF8(&source, sourceBuffer + d->data.size(),
232
 
                                &target, targetBuffer + outputBufferSize,
233
 
                                Unicode::lenientConversion);
234
 
 
235
 
  if(result != Unicode::conversionOK)
236
 
    debug("String::to8Bit() - Unicode conversion error.");
237
 
 
238
 
  int newSize = target - targetBuffer;
239
 
  s.resize(newSize);
240
 
  targetBuffer[newSize] = 0;
241
 
 
242
 
  s = (char *) targetBuffer;
243
 
 
244
 
  delete [] sourceBuffer;
245
 
  delete [] targetBuffer;
246
 
 
247
 
  return s;
248
 
}
249
 
 
250
 
TagLib::wstring String::toWString() const
251
 
{
252
 
  return d->data;
253
 
}
254
 
 
255
 
const char *String::toCString(bool unicode) const
256
 
{
257
 
  delete [] d->CString;
258
 
 
259
 
  std::string buffer = to8Bit(unicode);
260
 
  d->CString = new char[buffer.size() + 1];
261
 
  strcpy(d->CString, buffer.c_str());
262
 
 
263
 
  return d->CString;
264
 
}
265
 
 
266
 
String::Iterator String::begin()
267
 
{
268
 
  return d->data.begin();
269
 
}
270
 
 
271
 
String::ConstIterator String::begin() const
272
 
{
273
 
  return d->data.begin();
274
 
}
275
 
 
276
 
String::Iterator String::end()
277
 
{
278
 
  return d->data.end();
279
 
}
280
 
 
281
 
String::ConstIterator String::end() const
282
 
{
283
 
  return d->data.end();
284
 
}
285
 
 
286
 
int String::find(const String &s, int offset) const
287
 
{
288
 
  wstring::size_type position = d->data.find(s.d->data, offset);
289
 
 
290
 
  if(position != wstring::npos)
291
 
    return position;
292
 
  else
293
 
    return -1;
294
 
}
295
 
 
296
 
bool String::startsWith(const String &s) const
297
 
{
298
 
  if(s.length() > length())
299
 
    return false;
300
 
 
301
 
  return substr(0, s.length()) == s;
302
 
}
303
 
 
304
 
String String::substr(uint position, uint n) const
305
 
{
306
 
  if(n > position + d->data.size())
307
 
    n = d->data.size() - position;
308
 
 
309
 
  String s;
310
 
  s.d->data = d->data.substr(position, n);
311
 
  return s;
312
 
}
313
 
 
314
 
String &String::append(const String &s)
315
 
{
316
 
  detach();
317
 
  d->data += s.d->data;
318
 
  return *this;
319
 
}
320
 
 
321
 
String String::upper() const
322
 
{
323
 
  String s;
324
 
 
325
 
  static int shift = 'A' - 'a';
326
 
 
327
 
  for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); ++it) {
328
 
    if(*it >= 'a' && *it <= 'z')
329
 
      s.d->data.push_back(*it + shift);
330
 
    else
331
 
      s.d->data.push_back(*it);
332
 
  }
333
 
 
334
 
  return s;
335
 
}
336
 
 
337
 
TagLib::uint String::size() const
338
 
{
339
 
  return d->data.size();
340
 
}
341
 
 
342
 
TagLib::uint String::length() const
343
 
{
344
 
  return size();
345
 
}
346
 
 
347
 
bool String::isEmpty() const
348
 
{
349
 
  return d->data.size() == 0;
350
 
}
351
 
 
352
 
bool String::isNull() const
353
 
{
354
 
  return d == null.d;
355
 
}
356
 
 
357
 
ByteVector String::data(Type t) const
358
 
{
359
 
  ByteVector v;
360
 
 
361
 
  switch(t) {
362
 
 
363
 
  case Latin1:
364
 
  {
365
 
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
366
 
      v.append(char(*it));
367
 
    break;
368
 
  }
369
 
  case UTF8:
370
 
  {
371
 
    std::string s = to8Bit(true);
372
 
    v.setData(s.c_str(), s.length());
373
 
    break;
374
 
  }
375
 
  case UTF16:
376
 
  {
377
 
    // Assume that if we're doing UTF16 and not UTF16BE that we want little
378
 
    // endian encoding.  (Byte Order Mark)
379
 
 
380
 
    v.append(char(0xff));
381
 
    v.append(char(0xfe));
382
 
 
383
 
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
384
 
 
385
 
      char c1 = *it & 0xff;
386
 
      char c2 = *it >> 8;
387
 
 
388
 
      v.append(c1);
389
 
      v.append(c2);
390
 
    }
391
 
    break;
392
 
  }
393
 
  case UTF16BE:
394
 
  {
395
 
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
396
 
 
397
 
      char c1 = *it >> 8;
398
 
      char c2 = *it & 0xff;
399
 
 
400
 
      v.append(c1);
401
 
      v.append(c2);
402
 
    }
403
 
    break;
404
 
  }
405
 
  case UTF16LE:
406
 
  {
407
 
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
408
 
 
409
 
      char c1 = *it & 0xff;
410
 
      char c2 = *it >> 8;
411
 
 
412
 
      v.append(c1);
413
 
      v.append(c2);
414
 
    }
415
 
    break;
416
 
  }
417
 
  }
418
 
 
419
 
  return v;
420
 
}
421
 
 
422
 
int String::toInt() const
423
 
{
424
 
  int value = 0;
425
 
 
426
 
  bool negative = d->data[0] == '-';
427
 
  uint i = negative ? 1 : 0;
428
 
 
429
 
  for(; i < d->data.size() && d->data[i] >= '0' && d->data[i] <= '9'; i++)
430
 
    value = value * 10 + (d->data[i] - '0');
431
 
 
432
 
  if(negative)
433
 
    value = value * -1;
434
 
 
435
 
  return value;
436
 
}
437
 
 
438
 
String String::stripWhiteSpace() const
439
 
{
440
 
  wstring::const_iterator begin = d->data.begin();
441
 
  wstring::const_iterator end = d->data.end();
442
 
 
443
 
  while(begin != end &&
444
 
        (*begin == '\t' || *begin == '\n' || *begin == '\f' ||
445
 
         *begin == '\r' || *begin == ' '))
446
 
  {
447
 
    ++begin;
448
 
  }
449
 
 
450
 
  if(begin == end)
451
 
    return null;
452
 
 
453
 
  // There must be at least one non-whitespace character here for us to have
454
 
  // gotten this far, so we should be safe not doing bounds checking.
455
 
 
456
 
  do {
457
 
    --end;
458
 
  } while(*end == '\t' || *end == '\n' ||
459
 
          *end == '\f' || *end == '\r' || *end == ' ');
460
 
 
461
 
  return String(wstring(begin, end + 1));
462
 
}
463
 
 
464
 
bool String::isLatin1() const
465
 
{
466
 
  for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
467
 
    if(*it >= 256)
468
 
      return false;
469
 
  }
470
 
  return true;
471
 
}
472
 
 
473
 
bool String::isAscii() const
474
 
{
475
 
  for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
476
 
    if(*it >= 128)
477
 
      return false;
478
 
  }
479
 
  return true;
480
 
}
481
 
 
482
 
String String::number(int n) // static
483
 
{
484
 
  if(n == 0)
485
 
    return String("0");
486
 
 
487
 
  String charStack;
488
 
 
489
 
  bool negative = n < 0;
490
 
 
491
 
  if(negative)
492
 
    n = n * -1;
493
 
 
494
 
  while(n > 0) {
495
 
    int remainder = n % 10;
496
 
    charStack += char(remainder + '0');
497
 
    n = (n - remainder) / 10;
498
 
  }
499
 
 
500
 
  String s;
501
 
 
502
 
  if(negative)
503
 
    s += '-';
504
 
 
505
 
  for(int i = charStack.d->data.size() - 1; i >= 0; i--)
506
 
    s += charStack.d->data[i];
507
 
 
508
 
  return s;
509
 
}
510
 
 
511
 
TagLib::wchar &String::operator[](int i)
512
 
{
513
 
  return d->data[i];
514
 
}
515
 
 
516
 
const TagLib::wchar &String::operator[](int i) const
517
 
{
518
 
  return d->data[i];
519
 
}
520
 
 
521
 
bool String::operator==(const String &s) const
522
 
{
523
 
  return d == s.d || d->data == s.d->data;
524
 
}
525
 
 
526
 
String &String::operator+=(const String &s)
527
 
{
528
 
  detach();
529
 
 
530
 
  d->data += s.d->data;
531
 
  return *this;
532
 
}
533
 
 
534
 
String &String::operator+=(const wchar_t *s)
535
 
{
536
 
  detach();
537
 
 
538
 
  d->data += s;
539
 
  return *this;
540
 
}
541
 
 
542
 
String &String::operator+=(const char *s)
543
 
{
544
 
  detach();
545
 
 
546
 
  for(int i = 0; s[i] != 0; i++)
547
 
    d->data += uchar(s[i]);
548
 
  return *this;
549
 
}
550
 
 
551
 
String &String::operator+=(wchar_t c)
552
 
{
553
 
  detach();
554
 
 
555
 
  d->data += c;
556
 
  return *this;
557
 
}
558
 
 
559
 
String &String::operator+=(char c)
560
 
{
561
 
  d->data += uchar(c);
562
 
  return *this;
563
 
}
564
 
 
565
 
String &String::operator=(const String &s)
566
 
{
567
 
  if(&s == this)
568
 
    return *this;
569
 
 
570
 
  if(d->deref())
571
 
    delete d;
572
 
  d = s.d;
573
 
  d->ref();
574
 
  return *this;
575
 
}
576
 
 
577
 
String &String::operator=(const std::string &s)
578
 
{
579
 
  if(d->deref())
580
 
    delete d;
581
 
 
582
 
  d = new StringPrivate;
583
 
 
584
 
  d->data.resize(s.size());
585
 
 
586
 
  wstring::iterator targetIt = d->data.begin();
587
 
  for(std::string::const_iterator it = s.begin(); it != s.end(); it++) {
588
 
    *targetIt = uchar(*it);
589
 
    ++targetIt;
590
 
  }
591
 
 
592
 
  return *this;
593
 
}
594
 
 
595
 
String &String::operator=(const wstring &s)
596
 
{
597
 
  if(d->deref())
598
 
    delete d;
599
 
  d = new StringPrivate(s);
600
 
  return *this;
601
 
}
602
 
 
603
 
String &String::operator=(const wchar_t *s)
604
 
{
605
 
  if(d->deref())
606
 
    delete d;
607
 
  d = new StringPrivate(s);
608
 
  return *this;
609
 
}
610
 
 
611
 
String &String::operator=(char c)
612
 
{
613
 
  if(d->deref())
614
 
    delete d;
615
 
  d = new StringPrivate;
616
 
  d->data += uchar(c);
617
 
  return *this;
618
 
}
619
 
 
620
 
String &String::operator=(wchar_t c)
621
 
{
622
 
  if(d->deref())
623
 
    delete d;
624
 
  d = new StringPrivate;
625
 
  d->data += c;
626
 
  return *this;
627
 
}
628
 
 
629
 
String &String::operator=(const char *s)
630
 
{
631
 
  if(d->deref())
632
 
    delete d;
633
 
 
634
 
  d = new StringPrivate;
635
 
 
636
 
  int length = ::strlen(s);
637
 
  d->data.resize(length);
638
 
 
639
 
  wstring::iterator targetIt = d->data.begin();
640
 
  for(int i = 0; i < length; i++) {
641
 
    *targetIt = uchar(s[i]);
642
 
    ++targetIt;
643
 
  }
644
 
 
645
 
  return *this;
646
 
}
647
 
 
648
 
String &String::operator=(const ByteVector &v)
649
 
{
650
 
  if(d->deref())
651
 
    delete d;
652
 
 
653
 
  d = new StringPrivate;
654
 
  d->data.resize(v.size());
655
 
  wstring::iterator targetIt = d->data.begin();
656
 
 
657
 
  uint i = 0;
658
 
 
659
 
  for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
660
 
    *targetIt = uchar(*it);
661
 
    ++targetIt;
662
 
    ++i;
663
 
  }
664
 
 
665
 
  // If we hit a null in the ByteVector, shrink the string again.
666
 
 
667
 
  d->data.resize(i);
668
 
 
669
 
  return *this;
670
 
}
671
 
 
672
 
bool String::operator<(const String &s) const
673
 
{
674
 
  return d->data < s.d->data;
675
 
}
676
 
 
677
 
////////////////////////////////////////////////////////////////////////////////
678
 
// protected members
679
 
////////////////////////////////////////////////////////////////////////////////
680
 
 
681
 
void String::detach()
682
 
{
683
 
  if(d->count() > 1) {
684
 
    d->deref();
685
 
    d = new StringPrivate(d->data);
686
 
  }
687
 
}
688
 
 
689
 
////////////////////////////////////////////////////////////////////////////////
690
 
// private members
691
 
////////////////////////////////////////////////////////////////////////////////
692
 
 
693
 
void String::prepare(Type t)
694
 
{
695
 
  switch(t) {
696
 
  case UTF16:
697
 
  {
698
 
    if(d->data.size() >= 1 && (d->data[0] == 0xfeff || d->data[0] == 0xfffe)) {
699
 
      bool swap = d->data[0] != 0xfeff;
700
 
      d->data.erase(d->data.begin(), d->data.begin() + 1);
701
 
      if(swap) {
702
 
        for(uint i = 0; i < d->data.size(); i++)
703
 
          d->data[i] = byteSwap((unsigned short)d->data[i]);
704
 
      }
705
 
    }
706
 
    else {
707
 
      debug("String::prepare() - Invalid UTF16 string.");
708
 
      d->data.erase(d->data.begin(), d->data.end());
709
 
    }
710
 
    break;
711
 
  }
712
 
  case UTF8:
713
 
  {
714
 
    int bufferSize = d->data.size() + 1;
715
 
    Unicode::UTF8  *sourceBuffer = new Unicode::UTF8[bufferSize];
716
 
    Unicode::UTF16 *targetBuffer = new Unicode::UTF16[bufferSize];
717
 
 
718
 
    unsigned int i = 0;
719
 
    for(; i < d->data.size(); i++)
720
 
      sourceBuffer[i] = Unicode::UTF8(d->data[i]);
721
 
    sourceBuffer[i] = 0;
722
 
 
723
 
    const Unicode::UTF8 *source = sourceBuffer;
724
 
    Unicode::UTF16 *target = targetBuffer;
725
 
 
726
 
    Unicode::ConversionResult result =
727
 
      Unicode::ConvertUTF8toUTF16(&source, sourceBuffer + bufferSize,
728
 
                                  &target, targetBuffer + bufferSize,
729
 
                                  Unicode::lenientConversion);
730
 
 
731
 
    if(result != Unicode::conversionOK)
732
 
      debug("String::prepare() - Unicode conversion error.");
733
 
 
734
 
 
735
 
    int newSize = target != targetBuffer ? target - targetBuffer - 1 : 0;
736
 
    d->data.resize(newSize);
737
 
 
738
 
    for(int i = 0; i < newSize; i++)
739
 
      d->data[i] = targetBuffer[i];
740
 
 
741
 
    delete [] sourceBuffer;
742
 
    delete [] targetBuffer;
743
 
 
744
 
    break;
745
 
  }
746
 
  case UTF16LE:
747
 
  {
748
 
    for(uint i = 0; i < d->data.size(); i++)
749
 
      d->data[i] = byteSwap((unsigned short)d->data[i]);
750
 
    break;
751
 
  }
752
 
  default:
753
 
    break;
754
 
  }
755
 
}
756
 
 
757
 
////////////////////////////////////////////////////////////////////////////////
758
 
// related functions
759
 
////////////////////////////////////////////////////////////////////////////////
760
 
 
761
 
const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2)
762
 
{
763
 
  String s(s1);
764
 
  s.append(s2);
765
 
  return s;
766
 
}
767
 
 
768
 
const TagLib::String operator+(const char *s1, const TagLib::String &s2)
769
 
{
770
 
  String s(s1);
771
 
  s.append(s2);
772
 
  return s;
773
 
}
774
 
 
775
 
const TagLib::String operator+(const TagLib::String &s1, const char *s2)
776
 
{
777
 
  String s(s1);
778
 
  s.append(s2);
779
 
  return s;
780
 
}
781
 
 
782
 
std::ostream &operator<<(std::ostream &s, const String &str)
783
 
{
784
 
  s << str.to8Bit();
785
 
  return s;
786
 
}