~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

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
 
 
239
  int newSize = target - targetBuffer;
 
240
  s.resize(newSize);
 
241
  targetBuffer[newSize] = 0;
 
242
 
 
243
  s = (char *) targetBuffer;
 
244
 
 
245
  delete [] sourceBuffer;
 
246
  delete [] targetBuffer;
 
247
 
 
248
  return s;
 
249
}
 
250
 
 
251
TagLib::wstring String::toWString() const
 
252
{
 
253
  return d->data;
 
254
}
 
255
 
 
256
const char *String::toCString(bool unicode) const
 
257
{
 
258
  delete [] d->CString;
 
259
 
 
260
  std::string buffer = to8Bit(unicode);
 
261
  d->CString = new char[buffer.size() + 1];
 
262
  strcpy(d->CString, buffer.c_str());
 
263
 
 
264
  return d->CString;
 
265
}
 
266
 
 
267
String::Iterator String::begin()
 
268
{
 
269
  return d->data.begin();
 
270
}
 
271
 
 
272
String::ConstIterator String::begin() const
 
273
{
 
274
  return d->data.begin();
 
275
}
 
276
 
 
277
String::Iterator String::end()
 
278
{
 
279
  return d->data.end();
 
280
}
 
281
 
 
282
String::ConstIterator String::end() const
 
283
{
 
284
  return d->data.end();
 
285
}
 
286
 
 
287
int String::find(const String &s, int offset) const
 
288
{
 
289
  wstring::size_type position = d->data.find(s.d->data, offset);
 
290
 
 
291
  if(position != wstring::npos)
 
292
    return position;
 
293
  else
 
294
    return -1;
 
295
}
 
296
 
 
297
bool String::startsWith(const String &s) const
 
298
{
 
299
  if(s.length() > length())
 
300
    return false;
 
301
 
 
302
  return substr(0, s.length()) == s;
 
303
}
 
304
 
 
305
String String::substr(uint position, uint n) const
 
306
{
 
307
  if(n > position + d->data.size())
 
308
    n = d->data.size() - position;
 
309
 
 
310
  String s;
 
311
  s.d->data = d->data.substr(position, n);
 
312
  return s;
 
313
}
 
314
 
 
315
String &String::append(const String &s)
 
316
{
 
317
  detach();
 
318
  d->data += s.d->data;
 
319
  return *this;
 
320
}
 
321
 
 
322
String String::upper() const
 
323
{
 
324
  String s;
 
325
 
 
326
  static int shift = 'A' - 'a';
 
327
 
 
328
  for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); ++it) {
 
329
    if(*it >= 'a' && *it <= 'z')
 
330
      s.d->data.push_back(*it + shift);
 
331
    else
 
332
      s.d->data.push_back(*it);
 
333
  }
 
334
 
 
335
  return s;
 
336
}
 
337
 
 
338
TagLib::uint String::size() const
 
339
{
 
340
  return d->data.size();
 
341
}
 
342
 
 
343
TagLib::uint String::length() const
 
344
{
 
345
  return size();
 
346
}
 
347
 
 
348
bool String::isEmpty() const
 
349
{
 
350
  return d->data.size() == 0;
 
351
}
 
352
 
 
353
bool String::isNull() const
 
354
{
 
355
  return d == null.d;
 
356
}
 
357
 
 
358
ByteVector String::data(Type t) const
 
359
{
 
360
  ByteVector v;
 
361
 
 
362
  switch(t) {
 
363
 
 
364
  case Latin1:
 
365
  {
 
366
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
 
367
      v.append(char(*it));
 
368
    break;
 
369
  }
 
370
  case UTF8:
 
371
  {
 
372
    std::string s = to8Bit(true);
 
373
    v.setData(s.c_str(), s.length());
 
374
    break;
 
375
  }
 
376
  case UTF16:
 
377
  {
 
378
    // Assume that if we're doing UTF16 and not UTF16BE that we want little
 
379
    // endian encoding.  (Byte Order Mark)
 
380
 
 
381
    v.append(char(0xff));
 
382
    v.append(char(0xfe));
 
383
 
 
384
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
 
385
 
 
386
      char c1 = *it & 0xff;
 
387
      char c2 = *it >> 8;
 
388
 
 
389
      v.append(c1);
 
390
      v.append(c2);
 
391
    }
 
392
    break;
 
393
  }
 
394
  case UTF16BE:
 
395
  {
 
396
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
 
397
 
 
398
      char c1 = *it >> 8;
 
399
      char c2 = *it & 0xff;
 
400
 
 
401
      v.append(c1);
 
402
      v.append(c2);
 
403
    }
 
404
    break;
 
405
  }
 
406
  case UTF16LE:
 
407
  {
 
408
    for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
 
409
 
 
410
      char c1 = *it & 0xff;
 
411
      char c2 = *it >> 8;
 
412
 
 
413
      v.append(c1);
 
414
      v.append(c2);
 
415
    }
 
416
    break;
 
417
  }
 
418
  }
 
419
 
 
420
  return v;
 
421
}
 
422
 
 
423
int String::toInt() const
 
424
{
 
425
  int value = 0;
 
426
 
 
427
  bool negative = d->data[0] == '-';
 
428
  uint i = negative ? 1 : 0;
 
429
 
 
430
  for(; i < d->data.size() && d->data[i] >= '0' && d->data[i] <= '9'; i++)
 
431
    value = value * 10 + (d->data[i] - '0');
 
432
 
 
433
  if(negative)
 
434
    value = value * -1;
 
435
 
 
436
  return value;
 
437
}
 
438
 
 
439
String String::stripWhiteSpace() const
 
440
{
 
441
  wstring::const_iterator begin = d->data.begin();
 
442
  wstring::const_iterator end = d->data.end();
 
443
 
 
444
  while(begin != end &&
 
445
        (*begin == '\t' || *begin == '\n' || *begin == '\f' ||
 
446
         *begin == '\r' || *begin == ' '))
 
447
  {
 
448
    ++begin;
 
449
  }
 
450
 
 
451
  if(begin == end)
 
452
    return null;
 
453
 
 
454
  // There must be at least one non-whitespace character here for us to have
 
455
  // gotten this far, so we should be safe not doing bounds checking.
 
456
 
 
457
  do {
 
458
    --end;
 
459
  } while(*end == '\t' || *end == '\n' ||
 
460
          *end == '\f' || *end == '\r' || *end == ' ');
 
461
 
 
462
  return String(wstring(begin, end + 1));
 
463
}
 
464
 
 
465
bool String::isLatin1() const
 
466
{
 
467
  for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
 
468
    if(*it >= 256)
 
469
      return false;
 
470
  }
 
471
  return true;
 
472
}
 
473
 
 
474
bool String::isAscii() const
 
475
{
 
476
  for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
 
477
    if(*it >= 128)
 
478
      return false;
 
479
  }
 
480
  return true;
 
481
}
 
482
 
 
483
String String::number(int n) // static
 
484
{
 
485
  if(n == 0)
 
486
    return String("0");
 
487
 
 
488
  String charStack;
 
489
 
 
490
  bool negative = n < 0;
 
491
 
 
492
  if(negative)
 
493
    n = n * -1;
 
494
 
 
495
  while(n > 0) {
 
496
    int remainder = n % 10;
 
497
    charStack += char(remainder + '0');
 
498
    n = (n - remainder) / 10;
 
499
  }
 
500
 
 
501
  String s;
 
502
 
 
503
  if(negative)
 
504
    s += '-';
 
505
 
 
506
  for(int i = charStack.d->data.size() - 1; i >= 0; i--)
 
507
    s += charStack.d->data[i];
 
508
 
 
509
  return s;
 
510
}
 
511
 
 
512
TagLib::wchar &String::operator[](int i)
 
513
{
 
514
  return d->data[i];
 
515
}
 
516
 
 
517
const TagLib::wchar &String::operator[](int i) const
 
518
{
 
519
  return d->data[i];
 
520
}
 
521
 
 
522
bool String::operator==(const String &s) const
 
523
{
 
524
  return d == s.d || d->data == s.d->data;
 
525
}
 
526
 
 
527
String &String::operator+=(const String &s)
 
528
{
 
529
  detach();
 
530
 
 
531
  d->data += s.d->data;
 
532
  return *this;
 
533
}
 
534
 
 
535
String &String::operator+=(const wchar_t *s)
 
536
{
 
537
  detach();
 
538
 
 
539
  d->data += s;
 
540
  return *this;
 
541
}
 
542
 
 
543
String &String::operator+=(const char *s)
 
544
{
 
545
  detach();
 
546
 
 
547
  for(int i = 0; s[i] != 0; i++)
 
548
    d->data += uchar(s[i]);
 
549
  return *this;
 
550
}
 
551
 
 
552
String &String::operator+=(wchar_t c)
 
553
{
 
554
  detach();
 
555
 
 
556
  d->data += c;
 
557
  return *this;
 
558
}
 
559
 
 
560
String &String::operator+=(char c)
 
561
{
 
562
  d->data += uchar(c);
 
563
  return *this;
 
564
}
 
565
 
 
566
String &String::operator=(const String &s)
 
567
{
 
568
  if(&s == this)
 
569
    return *this;
 
570
 
 
571
  if(d->deref())
 
572
    delete d;
 
573
  d = s.d;
 
574
  d->ref();
 
575
  return *this;
 
576
}
 
577
 
 
578
String &String::operator=(const std::string &s)
 
579
{
 
580
  if(d->deref())
 
581
    delete d;
 
582
 
 
583
  d = new StringPrivate;
 
584
 
 
585
  d->data.resize(s.size());
 
586
 
 
587
  wstring::iterator targetIt = d->data.begin();
 
588
  for(std::string::const_iterator it = s.begin(); it != s.end(); it++) {
 
589
    *targetIt = uchar(*it);
 
590
    ++targetIt;
 
591
  }
 
592
 
 
593
  return *this;
 
594
}
 
595
 
 
596
String &String::operator=(const wstring &s)
 
597
{
 
598
  if(d->deref())
 
599
    delete d;
 
600
  d = new StringPrivate(s);
 
601
  return *this;
 
602
}
 
603
 
 
604
String &String::operator=(const wchar_t *s)
 
605
{
 
606
  if(d->deref())
 
607
    delete d;
 
608
  d = new StringPrivate(s);
 
609
  return *this;
 
610
}
 
611
 
 
612
String &String::operator=(char c)
 
613
{
 
614
  if(d->deref())
 
615
    delete d;
 
616
  d = new StringPrivate;
 
617
  d->data += uchar(c);
 
618
  return *this;
 
619
}
 
620
 
 
621
String &String::operator=(wchar_t c)
 
622
{
 
623
  if(d->deref())
 
624
    delete d;
 
625
  d = new StringPrivate;
 
626
  d->data += c;
 
627
  return *this;
 
628
}
 
629
 
 
630
String &String::operator=(const char *s)
 
631
{
 
632
  if(d->deref())
 
633
    delete d;
 
634
 
 
635
  d = new StringPrivate;
 
636
 
 
637
  int length = ::strlen(s);
 
638
  d->data.resize(length);
 
639
 
 
640
  wstring::iterator targetIt = d->data.begin();
 
641
  for(int i = 0; i < length; i++) {
 
642
    *targetIt = uchar(s[i]);
 
643
    ++targetIt;
 
644
  }
 
645
 
 
646
  return *this;
 
647
}
 
648
 
 
649
String &String::operator=(const ByteVector &v)
 
650
{
 
651
  if(d->deref())
 
652
    delete d;
 
653
 
 
654
  d = new StringPrivate;
 
655
  d->data.resize(v.size());
 
656
  wstring::iterator targetIt = d->data.begin();
 
657
 
 
658
  uint i = 0;
 
659
 
 
660
  for(ByteVector::ConstIterator it = v.begin(); it != v.end() && (*it); ++it) {
 
661
    *targetIt = uchar(*it);
 
662
    ++targetIt;
 
663
    ++i;
 
664
  }
 
665
 
 
666
  // If we hit a null in the ByteVector, shrink the string again.
 
667
 
 
668
  d->data.resize(i);
 
669
 
 
670
  return *this;
 
671
}
 
672
 
 
673
bool String::operator<(const String &s) const
 
674
{
 
675
  return d->data < s.d->data;
 
676
}
 
677
 
 
678
////////////////////////////////////////////////////////////////////////////////
 
679
// protected members
 
680
////////////////////////////////////////////////////////////////////////////////
 
681
 
 
682
void String::detach()
 
683
{
 
684
  if(d->count() > 1) {
 
685
    d->deref();
 
686
    d = new StringPrivate(d->data);
 
687
  }
 
688
}
 
689
 
 
690
////////////////////////////////////////////////////////////////////////////////
 
691
// private members
 
692
////////////////////////////////////////////////////////////////////////////////
 
693
 
 
694
void String::prepare(Type t)
 
695
{
 
696
  switch(t) {
 
697
  case UTF16:
 
698
  {
 
699
    if(d->data.size() >= 1 && (d->data[0] == 0xfeff || d->data[0] == 0xfffe)) {
 
700
      bool swap = d->data[0] != 0xfeff;
 
701
      d->data.erase(d->data.begin(), d->data.begin() + 1);
 
702
      if(swap) {
 
703
        for(uint i = 0; i < d->data.size(); i++)
 
704
          d->data[i] = byteSwap((unsigned short)d->data[i]);
 
705
      }
 
706
    }
 
707
    else {
 
708
      debug("String::prepare() - Invalid UTF16 string.");
 
709
      d->data.erase(d->data.begin(), d->data.end());
 
710
    }
 
711
    break;
 
712
  }
 
713
  case UTF8:
 
714
  {
 
715
    int bufferSize = d->data.size() + 1;
 
716
    Unicode::UTF8  *sourceBuffer = new Unicode::UTF8[bufferSize];
 
717
    Unicode::UTF16 *targetBuffer = new Unicode::UTF16[bufferSize];
 
718
 
 
719
    unsigned int i = 0;
 
720
    for(; i < d->data.size(); i++)
 
721
      sourceBuffer[i] = Unicode::UTF8(d->data[i]);
 
722
    sourceBuffer[i] = 0;
 
723
 
 
724
    const Unicode::UTF8 *source = sourceBuffer;
 
725
    Unicode::UTF16 *target = targetBuffer;
 
726
 
 
727
    Unicode::ConversionResult result =
 
728
      Unicode::ConvertUTF8toUTF16(&source, sourceBuffer + bufferSize,
 
729
                                  &target, targetBuffer + bufferSize,
 
730
                                  Unicode::lenientConversion);
 
731
 
 
732
    if(result != Unicode::conversionOK) {
 
733
      debug("String::prepare() - Unicode conversion error.");
 
734
    }
 
735
 
 
736
 
 
737
    int newSize = target != targetBuffer ? target - targetBuffer - 1 : 0;
 
738
    d->data.resize(newSize);
 
739
 
 
740
    for(int i = 0; i < newSize; i++)
 
741
      d->data[i] = targetBuffer[i];
 
742
 
 
743
    delete [] sourceBuffer;
 
744
    delete [] targetBuffer;
 
745
 
 
746
    break;
 
747
  }
 
748
  case UTF16LE:
 
749
  {
 
750
    for(uint i = 0; i < d->data.size(); i++)
 
751
      d->data[i] = byteSwap((unsigned short)d->data[i]);
 
752
    break;
 
753
  }
 
754
  default:
 
755
    break;
 
756
  }
 
757
}
 
758
 
 
759
////////////////////////////////////////////////////////////////////////////////
 
760
// related functions
 
761
////////////////////////////////////////////////////////////////////////////////
 
762
 
 
763
const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2)
 
764
{
 
765
  String s(s1);
 
766
  s.append(s2);
 
767
  return s;
 
768
}
 
769
 
 
770
const TagLib::String operator+(const char *s1, const TagLib::String &s2)
 
771
{
 
772
  String s(s1);
 
773
  s.append(s2);
 
774
  return s;
 
775
}
 
776
 
 
777
const TagLib::String operator+(const TagLib::String &s1, const char *s2)
 
778
{
 
779
  String s(s1);
 
780
  s.append(s2);
 
781
  return s;
 
782
}
 
783
 
 
784
std::ostream &operator<<(std::ostream &s, const String &str)
 
785
{
 
786
  s << str.to8Bit();
 
787
  return s;
 
788
}