#ifdef HAVE_CONFIG_H # include #endif #ifdef HAVE_OGG #include #include #include #include #include #include #include #include #include #include "lopster.h" #include #define CHUNKSIZE 4096 static int read32bits(ogg_packet *op, int off) { unsigned char *buf = op->packet; return (buf[off])|(buf[off+1]<<8)|(buf[off+2]<<16)|(buf[off+3]<<24); } /* Try to find the final page. Can be slightly off (but not enough to cause * problems) for non-standard page lengths */ static int get_final_page(int fd, ogg_sync_state *oy, int len, ogg_page *og) { int size = 0; unsigned char *buffer; int bytes; int found=0; int seekp; int tlen=len; while(1) { len -= CHUNKSIZE; size += CHUNKSIZE; if(lseek(fd, len, SEEK_SET) == -1) return -1; ogg_sync_reset(oy); buffer = ogg_sync_buffer(oy, size); bytes = read(fd, buffer, size); if(bytes<=0) return -1; ogg_sync_wrote(oy, bytes); found = ogg_sync_pageseek(oy, og); seekp = len; while(found && seekp <= len+CHUNKSIZE && seekp-found0) return 0; } } return -1; } // shamelessly stolen from gnapster (Good work, Jasta) by the_turner void file_parse_ogg_header(file_t * file) { int fd; ogg_sync_state oy; ogg_stream_state os; ogg_page og; ogg_packet op; unsigned char *buffer; int bytes; int serial; int streaminit=0; int length; struct stat st; ogg_sync_init(&oy); buffer = ogg_sync_buffer(&oy, CHUNKSIZE); fd=open(file->longname, O_RDONLY); if (fd == -1) { printf("could not open file for reading header [%s]\n", file->longname); return; } else { if ( fstat(fd, &st) == 0) { file->size=st.st_size; } else { fprintf(stderr, "Could not stat \"%s\" -> Error: %u \n", file->longname, fd); goto close; } fprintf(stderr, "File: \"%s\" successfully opened with size: %ld\n", file->longname, file->size); } bytes = read(fd, buffer, CHUNKSIZE); ogg_sync_wrote(&oy, bytes); if(ogg_sync_pageout(&oy, &og)!=1) { fprintf(stderr, "WARNING: Could not do ogg_sync_pageout "); goto failure; } serial = ogg_page_serialno(&og); ogg_stream_init(&os, serial); streaminit=1; if(ogg_stream_pagein(&os, &og)<0) { fprintf(stderr, "WARNING: Could not do ogg_stream_pagein "); goto failure; } if(ogg_stream_packetout(&os, &op)!=1) { fprintf(stderr, "WARNING: Could not do ogg_packet_out "); goto failure; } if(read32bits(&op,7) != 0) { fprintf(stderr, "WARNING: Bits could not be read "); goto failure; } file->frequency = read32bits(&op, 12); ogg_stream_clear(&os); /* We're done with that, now. */ streaminit=0; if(get_final_page(fd, &oy, file->size, &og) != 0) { fprintf(stderr, "WARNING: Could not get final page of size %ld ", file->size); goto failure; } if(serial != ogg_page_serialno(&og)) fprintf(stderr, "WARNING: \"%s\" is a chained stream. The napster protocol doesn't\n" "have any provision for such a concept. As a result, the output\n" "file length and bitrate will be inaccurate.\n", file->longname); length = ogg_page_granulepos(&og); if (file->frequency <= 0) goto failure; file->duration = (time_t)(length/file->frequency); if (file->duration <= 0) goto failure; file->bitrate = (int)(file->size/file->duration*8/1000); ogg_sync_clear(&oy); goto close; failure: fprintf(stderr, "\"%s\" wasn't a valid vorbis file\n", file->longname); if(streaminit) ogg_stream_clear(&os); ogg_sync_clear(&oy); close: close(fd); } #endif /* HAVE_OGG */