00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libmadplugin.h"
00023
00024
00025 #include <qpe/config.h>
00026 #include <opie2/odebug.h>
00027
00028
00029 #include <qapplication.h>
00030 #include <qmessagebox.h>
00031 #include <qregexp.h>
00032
00033
00034 #include <stdio.h>
00035 #include <stdarg.h>
00036 #include <stdlib.h>
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <fcntl.h>
00040 #include <unistd.h>
00041 #include <string.h>
00042 #include <ctype.h>
00043 #include <errno.h>
00044 #include <time.h>
00045 #include <locale.h>
00046 #include <math.h>
00047 #include <assert.h>
00048
00049
00050 #include <netinet/in.h>
00051 #include <netdb.h>
00052 #include <linux/limits.h>
00053 #include <sys/socket.h>
00054 #include <arpa/inet.h>
00055 #include <unistd.h>
00056
00057
00058
00059
00060 #if defined(HAVE_MMAP)
00061 # include <sys/mman.h>
00062 #endif
00063
00064
00065 extern "C" {
00066 #include "mad.h"
00067 }
00068
00069
00070 #define MPEG_BUFFER_SIZE 65536
00071
00072
00073 #define debugMsg(a)
00074
00075
00076 class Input {
00077 public:
00078 char const *path;
00079 int fd;
00080 #if defined(HAVE_MMAP)
00081 void *fdm;
00082 #endif
00083 unsigned long fileLength;
00084 unsigned char *data;
00085 unsigned long length;
00086 int eof;
00087 };
00088
00089
00090 class Output {
00091 public:
00092 mad_fixed_t attenuate;
00093 struct filter *filters;
00094 unsigned int channels_in;
00095 unsigned int channels_out;
00096 unsigned int speed_in;
00097 unsigned int speed_out;
00098 const char *path;
00099 };
00100
00101
00102 # if defined(HAVE_MMAP)
00103 static void *map_file(int fd, unsigned long *length)
00104 {
00105 void *fdm;
00106
00107 *length += MAD_BUFFER_GUARD;
00108
00109 fdm = mmap(0, *length, PROT_READ, MAP_SHARED, fd, 0);
00110 if (fdm == MAP_FAILED)
00111 return 0;
00112
00113 # if defined(HAVE_MADVISE)
00114 madvise(fdm, *length, MADV_SEQUENTIAL);
00115 # endif
00116
00117 return fdm;
00118 }
00119
00120
00121 static int unmap_file(void *fdm, unsigned long length)
00122 {
00123 if (munmap(fdm, length) == -1)
00124 return -1;
00125
00126 return 0;
00127 }
00128 # endif
00129
00130
00131 static inline QString tr( const char *str ) {
00132
00133 return qApp->translate( "OpiePlayer", str, "libmad strings for mp3 file info" );
00134 }
00135
00136
00137 class LibMadPluginData {
00138 public:
00139 Input input;
00140 Output output;
00141 int bad_last_frame;
00142 struct mad_stream stream;
00143 struct mad_frame frame;
00144 struct mad_synth synth;
00145 bool flush;
00146 };
00147
00148
00149 LibMadPlugin::LibMadPlugin() {
00150 d = new LibMadPluginData;
00151 d->input.fd = 0;
00152 #if defined(HAVE_MMAP)
00153 d->input.fdm = 0;
00154 #endif
00155 d->input.data = 0;
00156 d->flush = TRUE;
00157 info = tr( "No Song Open" );
00158 }
00159
00160
00161 LibMadPlugin::~LibMadPlugin() {
00162 close();
00163 delete d;
00164 }
00165
00166
00167 bool LibMadPlugin::isFileSupported( const QString& path ) {
00168 debugMsg( "LibMadPlugin::isFileSupported" );
00169
00170
00171
00172
00173
00174
00175 char *ext = strrchr( path.latin1(), '.' );
00176
00177
00178 if ( ext ) {
00179 if ( strncasecmp(ext, ".mp2", 4) == 0 )
00180 return TRUE;
00181 if ( strncasecmp(ext, ".mp3", 4) == 0 )
00182 return TRUE;
00183 }
00184
00185
00186 if ( path.left(4) == "http") {
00187 return TRUE;
00188 }
00189
00190 return FALSE;
00191 }
00192
00193
00194
00195 int LibMadPlugin::is_address_multicast(unsigned long address) {
00196 if ((address & 255) >= 224 && (address & 255) <= 239)
00197 return (1);
00198 return (0);
00199 }
00200
00201
00202 int LibMadPlugin::udp_open(char *address, int port) {
00203
00204 int enable = 1L;
00205 struct sockaddr_in stAddr;
00206 struct sockaddr_in stLclAddr;
00207 struct ip_mreq stMreq;
00208 struct hostent *host;
00209 int sock;
00210
00211 stAddr.sin_family = AF_INET;
00212 stAddr.sin_port = htons(port);
00213
00214 if ((host = gethostbyname(address)) == NULL) {
00215 return (0);
00216 }
00217
00218 stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
00219
00220
00221 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00222 return (0);
00223 }
00224
00225
00226 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(unsigned long int)) < 0) {
00227 return (0);
00228 }
00229
00230
00231 if (is_address_multicast(stAddr.sin_addr.s_addr)) {
00232
00233 stLclAddr.sin_family = AF_INET;
00234 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00235 stLclAddr.sin_port = stAddr.sin_port;
00236 if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) {
00237 return (0);
00238 }
00239
00240
00241 stMreq.imr_multiaddr.s_addr = stAddr.sin_addr.s_addr;
00242 stMreq.imr_interface.s_addr = INADDR_ANY;
00243 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq, sizeof(stMreq)) < 0) {
00244 return (0);
00245 }
00246 } else {
00247
00248 stLclAddr.sin_family = AF_INET;
00249 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00250 stLclAddr.sin_port = htons(0);
00251 if (bind(sock, (struct sockaddr *)&stLclAddr, sizeof(stLclAddr)) < 0) {
00252 return (0);
00253 }
00254 }
00255 return (sock);
00256 }
00257
00258 int LibMadPlugin::tcp_open(char *address, int port) {
00259 struct sockaddr_in stAddr;
00260 struct hostent *host;
00261 int sock;
00262 struct linger l;
00263
00264 memset(&stAddr, 0, sizeof(stAddr));
00265 stAddr.sin_family = AF_INET;
00266 stAddr.sin_port = htons(port);
00267
00268 if ((host = gethostbyname(address)) == NULL) {
00269 return (0);
00270 }
00271
00272 stAddr.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
00273
00274 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
00275 return (0);
00276 }
00277
00278 l.l_onoff = 1;
00279 l.l_linger = 5;
00280 if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&l, sizeof(l)) < 0) {
00281 return (0);
00282 }
00283
00284 if (connect(sock, (struct sockaddr *)&stAddr, sizeof(stAddr)) < 0) {
00285 return (0);
00286 }
00287
00288 return (sock);
00289 }
00290
00291
00300 int LibMadPlugin::http_read_line(int tcp_sock, char *buf, int size) {
00301 int offset = 0;
00302
00303 do {
00304 if (::read(tcp_sock, buf + offset, 1) < 0)
00305 return -1;
00306 if (buf[offset] != '\r')
00307 offset++;
00308 } while (offset < size - 1 && buf[offset - 1] != '\n');
00309
00310 buf[offset] = 0;
00311 return offset;
00312 }
00313
00314 int LibMadPlugin::http_open(const QString& path ) {
00315 char *host;
00316 int port;
00317 char *request;
00318 int tcp_sock;
00319 char http_request[PATH_MAX];
00320 char filename[PATH_MAX];
00321
00322 char *arg =strdup(path.latin1());
00323
00324
00325 if (strncmp(arg, "http://", strlen("http://"))) {
00326 return (0);
00327 }
00328
00329
00330 port = 80;
00331 host = arg + strlen("http://");
00332 if ((request = strchr(host, '/')) == NULL) {
00333 return (0);
00334 }
00335
00336 *request++ = 0;
00337
00338 if (strchr(host, ':') != NULL) {
00339 port = atoi(strchr(host, ':') + 1);
00340 *strchr(host, ':') = 0;
00341 }
00342
00343
00344 if (!(tcp_sock = tcp_open(host, port))) {
00345 perror("http_open");
00346 return (0);
00347 }
00348
00349 snprintf(filename, sizeof(filename) - strlen(host) - 75, "%s", request);
00350
00351
00352
00353
00354 snprintf(http_request, sizeof(http_request), "GET /%s HTTP/1.0\r\n"
00355
00356 "Pragma: no-cache\r\n" "Host: %s\r\n" "Accept: */*\r\n" "\r\n", filename, host);
00357
00358 send(tcp_sock, http_request, strlen(http_request), 0);
00359
00360
00361 #if 0
00362 do
00363 read(tcp_sock, &c, sizeof(char));
00364 while (c != ' ');
00365 read(tcp_sock, http_request, 4 * sizeof(char));
00366 http_request[4] = 0;
00367 if (strcmp(http_request, "200 ")) {
00368 fprintf(stderr, "http_open: ");
00369 do {
00370 read(tcp_sock, &c, sizeof(char));
00371 fprintf(stderr, "%c", c);
00372 } while (c != '\r');
00373 fprintf(stderr, "\n");
00374 return (0);
00375 }
00376 #endif
00377
00378 QString name;
00379 QString genre;
00380 QString bitrate;
00381 QString url;
00382 QString message = tr("Info: ");
00383 do {
00384
00385 int len;
00386
00387 len = http_read_line(tcp_sock, http_request, sizeof(http_request));
00388
00389 if (len == -1) {
00390
00391 return 0;
00392 }
00393
00394 if (QString(http_request).left(9) == "Location:") {
00395
00396 ::close(tcp_sock);
00397 http_request[strlen(http_request) - 1] = '\0';
00398 return http_open(&http_request[10]);
00399 }
00400
00401 if (QString(http_request).left(4) == "ICY ") {
00402
00403 if (strncmp(http_request + 4, "200 ", 4)) {
00404
00405 return 0;
00406 }
00407 } else if (QString(http_request).left(4) == "icy-") {
00408
00409 if ( QString( http_request ).left( 8 ) == "icy-name" ) {
00410 name = tr("Name: ") + QString(http_request).mid(9, (QString(http_request).length())- 9 );
00411 } else if ( QString( http_request ).left( 9 ) == "icy-genre" ) {
00412 genre = tr("Genre: ") + QString(http_request).mid(10, (QString(http_request).length())-10 );
00413 } else if ( QString( http_request ).left( 6 ) == "icy-br" ) {
00414 bitrate = tr("Bitrate: ") + QString(http_request).mid(7, (QString(http_request).length())- 7 );
00415 } else if ( QString( http_request ).left( 7 ) == "icy-url" ) {
00416 url = tr("URL: ") + QString(http_request).mid(8, (QString(http_request).length())- 8 );
00417 } else if ( QString( http_request ).left( 10 ) == "icy-notice" ) {
00418 message += QString(http_request).mid(11, QString(http_request).length()-11 ) ;
00419 }
00420 }
00421 } while (strcmp(http_request, "\n") != 0);
00422
00423 info = QString(name + genre + url + bitrate + message).replace( QRegExp("\n"), " : " );
00424
00425
00426
00427 return (tcp_sock);
00428 }
00429
00430
00431
00432 bool LibMadPlugin::open( const QString& path ) {
00433 debugMsg( "LibMadPlugin::open" );
00434 Config cfg("OpiePlayer");
00435 cfg.setGroup("Options");
00436 bufferSize = cfg.readNumEntry("MPeg_BufferSize",MPEG_BUFFER_SIZE);
00437
00438 d->bad_last_frame = 0;
00439 d->flush = TRUE;
00440 info = QString( "" );
00441
00442
00443
00444 if (path.left( 4 ) == "http" ) {
00445
00446 if ( !(http_open(path) == 0) ) {
00447 d->input.fd = http_open(path);
00448 } else {
00449 return FALSE;
00450 }
00451 } else {
00452 d->input.path = path.latin1();
00453 d->input.fd = ::open( d->input.path, O_RDONLY );
00454
00455 printID3Tags();
00456 }
00457 if (d->input.fd == -1) {
00458
00459 return FALSE;
00460 }
00461
00462 struct stat stat;
00463 if (fstat(d->input.fd, &stat) == -1) {
00464
00465 }
00466 if (S_ISREG(stat.st_mode) && stat.st_size > 0)
00467 d->input.fileLength = stat.st_size;
00468 else
00469 d->input.fileLength = 0;
00470
00471 #if defined(HAVE_MMAP)
00472 if (S_ISREG(stat.st_mode) && stat.st_size > 0) {
00473 d->input.length = stat.st_size;
00474 d->input.fdm = map_file(d->input.fd, &d->input.length);
00475 if (d->input.fdm == 0) {
00476
00477 }
00478 d->input.data = (unsigned char *)d->input.fdm;
00479 }
00480 #endif
00481
00482 if (d->input.data == 0) {
00483 d->input.data = (unsigned char *)malloc( bufferSize );
00484 if (d->input.data == 0) {
00485
00486 return FALSE;
00487 }
00488 d->input.length = 0;
00489 }
00490
00491 d->input.eof = 0;
00492
00493 mad_stream_init(&d->stream);
00494 mad_frame_init(&d->frame);
00495 mad_synth_init(&d->synth);
00496
00497 return TRUE;
00498 }
00499
00500
00501 bool LibMadPlugin::close() {
00502 debugMsg( "LibMadPlugin::close" );
00503
00504 int result = TRUE;
00505
00506 mad_synth_finish(&d->synth);
00507 mad_frame_finish(&d->frame);
00508 mad_stream_finish(&d->stream);
00509
00510 #if defined(HAVE_MMAP)
00511 if (d->input.fdm) {
00512 if (unmap_file(d->input.fdm, d->input.length) == -1) {
00513
00514 result = FALSE;
00515 }
00516 d->input.fdm = 0;
00517 d->input.data = 0;
00518 }
00519 #endif
00520
00521 if (d->input.data) {
00522 free(d->input.data);
00523 d->input.data = 0;
00524 }
00525
00526 if (::close(d->input.fd) == -1) {
00527
00528 result = FALSE;
00529 }
00530
00531 d->input.fd = 0;
00532
00533 return result;
00534 }
00535
00536
00537 bool LibMadPlugin::isOpen() {
00538 debugMsg( "LibMadPlugin::isOpen" );
00539 return ( d->input.fd != 0 );
00540 }
00541
00542
00543 int LibMadPlugin::audioStreams() {
00544 debugMsg( "LibMadPlugin::audioStreams" );
00545 return 1;
00546 }
00547
00548
00549 int LibMadPlugin::audioChannels( int ) {
00550 debugMsg( "LibMadPlugin::audioChannels" );
00551
00552
00553
00554
00555
00556 return 2;
00557 }
00558
00559
00560 int LibMadPlugin::audioFrequency( int ) {
00561 debugMsg( "LibMadPlugin::audioFrequency" );
00562 long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 );
00563
00564 return d->frame.header.samplerate;
00565 }
00566
00567
00568 int LibMadPlugin::audioSamples( int ) {
00569 debugMsg( "LibMadPlugin::audioSamples" );
00570
00571 long t; short t1[5]; audioReadSamples( t1, 2, 1, t, 0 );
00572 mad_header_decode( (struct mad_header *)&d->frame.header, &d->stream );
00573
00574
00575
00576
00577 if ( d->frame.header.bitrate == 0 )
00578 return 0;
00579 int samples = (d->input.fileLength / (d->frame.header.bitrate/8)) * d->frame.header.samplerate;
00580
00581
00582
00583
00584
00585 return samples;
00586
00587
00588 }
00589
00590
00591 bool LibMadPlugin::audioSetSample( long, int ) {
00592 debugMsg( "LibMadPlugin::audioSetSample" );
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 debugMsg( "LibMadPlugin::audioSetSample" );
00609 return FALSE;
00610 }
00611
00612
00613 long LibMadPlugin::audioGetSample( int ) {
00614 debugMsg( "LibMadPlugin::audioGetSample" );
00615 return 0;
00616 }
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 bool LibMadPlugin::read() {
00632 debugMsg( "LibMadPlugin::read" );
00633 int len;
00634
00635 if (d->input.eof)
00636 return FALSE;
00637
00638 #if defined(HAVE_MMAP)
00639 if (d->input.fdm) {
00640 unsigned long skip = 0;
00641
00642 if (d->stream.next_frame) {
00643 struct stat stat;
00644
00645 if (fstat(d->input.fd, &stat) == -1)
00646 return FALSE;
00647
00648 if (stat.st_size + MAD_BUFFER_GUARD <= (signed)d->input.length)
00649 return FALSE;
00650
00651
00652 skip = d->stream.next_frame - d->input.data;
00653
00654 if (unmap_file(d->input.fdm, d->input.length) == -1) {
00655 d->input.fdm = 0;
00656 d->input.data = 0;
00657 return FALSE;
00658 }
00659
00660 d->input.length = stat.st_size;
00661
00662 d->input.fdm = map_file(d->input.fd, &d->input.length);
00663 if (d->input.fdm == 0) {
00664 d->input.data = 0;
00665 return FALSE;
00666 }
00667
00668 d->input.data = (unsigned char *)d->input.fdm;
00669 }
00670
00671 mad_stream_buffer(&d->stream, d->input.data + skip, d->input.length - skip);
00672
00673 } else
00674 #endif
00675 {
00676 if (d->stream.next_frame) {
00677 memmove(d->input.data, d->stream.next_frame,
00678 d->input.length = &d->input.data[d->input.length] - d->stream.next_frame);
00679 }
00680
00681 do {
00682 len = ::read(d->input.fd, d->input.data + d->input.length, bufferSize - d->input.length);
00683 }
00684 while (len == -1 && errno == EINTR);
00685
00686 if (len == -1) {
00687
00688 return FALSE;
00689 }
00690 else if (len == 0) {
00691 d->input.eof = 1;
00692
00693 assert(bufferSize - d->input.length >= MAD_BUFFER_GUARD);
00694
00695 while (len < MAD_BUFFER_GUARD)
00696 d->input.data[d->input.length + len++] = 0;
00697 }
00698
00699 mad_stream_buffer(&d->stream, d->input.data, d->input.length += len);
00700 }
00701
00702 return TRUE;
00703 }
00704
00705
00706 static mad_fixed_t left_err, right_err;
00707 static const int bits = 16;
00708 static const int shift = MAD_F_FRACBITS + 1 - bits;
00709
00710
00711 inline long audio_linear_dither( mad_fixed_t sample, mad_fixed_t& error ) {
00712 sample += error;
00713 mad_fixed_t quantized = (sample >= MAD_F_ONE) ? MAD_F_ONE - 1 : ( (sample < -MAD_F_ONE) ? -MAD_F_ONE : sample );
00714 quantized &= ~((1L << shift) - 1);
00715 error = sample - quantized;
00716 return quantized >> shift;
00717 }
00718
00719
00720 inline void audio_pcm( short *data, unsigned int nsamples, mad_fixed_t *left, mad_fixed_t *right ) {
00721 if ( right ) {
00722 while (nsamples--) {
00723 data[0] = audio_linear_dither( *left++, left_err );
00724 data[1] = audio_linear_dither( *right++, right_err );
00725 data += 2;
00726 }
00727 } else {
00728 while (nsamples--) {
00729 data[0] = data[1] = audio_linear_dither( *left++, left_err );
00730 data += 2;
00731 }
00732 }
00733 }
00734
00735
00736 bool LibMadPlugin::decode( short *output, long samples, long& samplesMade ) {
00737 debugMsg( "LibMadPlugin::decode" );
00738
00739 static int buffered = 0;
00740 static mad_fixed_t buffer[2][65536 * 2];
00741 int offset = buffered;
00742 samplesMade = 0;
00743
00744 static int maxBuffered = 8000;
00745
00746 if ( samples > maxBuffered ) {
00747 samples = maxBuffered;
00748 }
00749
00750 if ( d->flush ) {
00751 buffered = 0;
00752 offset = 0;
00753 d->flush = FALSE;
00754 }
00755
00756 while ( buffered < maxBuffered ) {
00757
00758 while (mad_frame_decode(&d->frame, &d->stream) == -1) {
00759 if (!MAD_RECOVERABLE(d->stream.error)) {
00760 debugMsg( "feed me" );
00761 return FALSE;
00762 }
00763 if ( d->stream.error == MAD_ERROR_BADCRC ) {
00764 mad_frame_mute(&d->frame);
00765
00766 }
00767 }
00768
00769 mad_synth_frame(&d->synth, &d->frame);
00770 int decodedSamples = d->synth.pcm.length;
00771 memcpy( &(buffer[0][offset]), d->synth.pcm.samples[0], decodedSamples * sizeof(mad_fixed_t) );
00772 if ( d->synth.pcm.channels == 2 )
00773 memcpy( &(buffer[1][offset]), d->synth.pcm.samples[1], decodedSamples * sizeof(mad_fixed_t) );
00774 offset += decodedSamples;
00775 buffered += decodedSamples;
00776 }
00777
00778
00779 audio_pcm( output, samples, buffer[0], (d->synth.pcm.channels == 2) ? buffer[1] : 0 );
00780
00781
00782 samplesMade = samples;
00783 memmove( buffer[0], &(buffer[0][samples]), (buffered - samples) * sizeof(mad_fixed_t) );
00784 if ( d->synth.pcm.channels == 2 ) {
00785 memmove( buffer[1], &(buffer[1][samples]), (buffered - samples) * sizeof(mad_fixed_t) );
00786 }
00787 buffered -= samples;
00788
00789 return TRUE;
00790 }
00791
00792
00793
00794 bool LibMadPlugin::audioReadSamples( short *output, int , long samples, long& samplesMade, int ) {
00795 debugMsg( "LibMadPlugin::audioReadStereoSamples" );
00796
00797 static bool needInput = TRUE;
00798
00799 if ( samples == 0 )
00800 return FALSE;
00801
00802 do {
00803 if ( needInput )
00804 if ( !read() ) {
00805 return FALSE;
00806 }
00807
00808 needInput = FALSE;
00809
00810 if ( decode( output, samples, samplesMade ) )
00811 return TRUE;
00812 else
00813 needInput = TRUE;
00814 }
00815 while ( ( samplesMade < samples ) && ( !d->input.eof ) );
00816
00817 return FALSE;
00818 }
00819
00820
00821 double LibMadPlugin::getTime() {
00822 debugMsg( "LibMadPlugin::getTime" );
00823 return 0.0;
00824 }
00825
00826
00827 void LibMadPlugin::printID3Tags() {
00828
00829
00830 char id3v1[128 + 1];
00831
00832 if ( ::lseek( d->input.fd, -128, SEEK_END ) == -1 ) {
00833
00834 return;
00835 }
00836
00837 if ( ::read( d->input.fd, id3v1, 128 ) != 128 ) {
00838
00839 return;
00840 }
00841
00842 if ( ::strncmp( (const char *)id3v1, "TAG", 3 ) != 0 ) {
00843 debugMsg( "sorry, no id3 tags" );
00844 } else {
00845 int len[5] = { 30, 30, 30, 4, 30 };
00846 QString label[5] = { tr( "Title" ), tr( "Artist" ), tr( "Album" ), tr( "Year" ), tr( "Comment" ) };
00847 char *ptr = id3v1 + 3, *ptr2 = ptr + len[0];
00848
00849 info = "";
00850 for ( int i = 0; i < 5; ptr += len[i], i++, ptr2 += len[i] ) {
00851 char push = *ptr2;
00852 *ptr2 = '\0';
00853 char *ptr3 = ptr2;
00854 while ( ptr3-1 >= ptr && isspace(ptr3[-1]) ) ptr3--;
00855 char push2 = *ptr3; *ptr3 = '\0';
00856 if ( strcmp( ptr, "" ) ) {
00857 if( ((QString)ptr).find(" ") == -1)
00858 info += ( i != 0 ? ", " : "" ) + label[i] + ": " + ptr;
00859 }
00860
00861 *ptr3 = push2;
00862 *ptr2 = push;
00863 }
00864 if (id3v1[126] == 0 && id3v1[127] != 0)
00865 info += tr( ", Track: " ) + id3v1[127];
00866 }
00867
00868 if ( ::lseek(d->input.fd, 0, SEEK_SET) == -1 ) {
00869
00870 return;
00871 }
00872 }
00873