/* * Dump the contents of the player. Takes a single parameter: the * mount-point of the player. */ #include #include #include #include #include #include #include #include #include #include #include #include "mple.h" /* * convert a UTF16BE string to UTF8 and print it. Because iconv messes * with the i/o pointers, we need to keep two copies of each. */ void print_as_utf8( FILE *handle, char *inbuffer, size_t maxlen ) { iconv_t cd = (iconv_t) -1; size_t outbytesleft, inbytesleft; size_t status; char *outbuffer = NULL, *outbuf; char *inbuf = inbuffer; /* Find out how many bytes to convert. Inbound data will be an array of 16bit values, either null-terminated or running right up against maxlen. */ for ( inbytesleft = 0; inbytesleft < maxlen; inbytesleft++ ) { if ( inbuf[inbytesleft * 2 + 1] == 0 && inbuf[inbytesleft * 2] == 0 ) { break; } } /* insane, but possible: UTF8 can use up to six bytes to represent a character. The +1 is for a trailing NULL */ outbytesleft = inbytesleft * 6 + 1; outbuffer = g_malloc( outbytesleft ); memset( outbuffer, 0, outbytesleft ); outbuf = outbuffer; /* convert 16bit size to 8bit size */ inbytesleft *= 2; cd = iconv_open( "UTF8", "UTF16BE" ); if ( cd != (iconv_t)(-1)) { status = iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); if ( status != -1 ) { fprintf( handle, "%s", outbuffer ); goto out; } else { perror( "conv" ); exit( 1 ); } } /* if we get here, some part of the conversion failed */ perror( "conv" ); exit( 1 ); out: if ( cd != (iconv_t) -1 ) { iconv_close( cd ); } if ( outbuffer != NULL ) { g_free( outbuffer ); } } int main( int argc, char *argv[] ) { gchar *mountpoint = NULL, *devicepath = NULL; guint8 verbose = 0; int val; mple_device *dev; while (( val = getopt( argc, argv, "m:d:v" )) != -1 ) { switch( val ) { case '?': case ':': /* getopt will produce an error for me, thanks */ exit( 1 ); break; case 'm': mountpoint = optarg; break; case 'd': devicepath = optarg; break; case 'v': verbose++; break; default: fprintf( stderr, "wtf %c\n", val ); exit( 1 ); break; } } /* old usage: sole parameter is the mountpoint */ if ( optind == argc - 1 ) { mountpoint = argv[optind]; } if ( mountpoint == NULL && devicepath == NULL ) { /* Go for auto-probe */ GList *devs = mple_get_nw_devs( NULL ); guint32 d = 0; fprintf( stderr, "no device specified, auto-probing :\n" ); if ( g_list_length( devs ) == 0 ) { fprintf( stderr, "no device found\n" ); exit( 1 ); } if ( g_list_length( devs ) > 1 ) { fprintf( stderr, "More than one device found, please be more specific : \n" ); while( g_list_nth( devs, d )) { mple_device *dv = g_list_nth_data( devs, d ); fprintf( stderr, " %s", dv->device ); if ( dv->path != NULL ) { fprintf( stderr, " (mounted at %s)", dv->path ); } fprintf( stderr, "\n" ); mple_dev_free( dv ); d++; } g_list_free( devs ); exit( 1 ); } else { dev = g_list_nth_data( devs, d ); fprintf( stderr, "Using device %s", dev->device ); if ( dev->path != NULL ) { fprintf( stderr, " (mounted at %s)", dev->path ); } fprintf( stderr, "\n" ); } } else { dev = mple_dev_init( mountpoint ); } if ( dev != NULL ) { guint32 folder = 0; mple_folder *fptr; if ( mountpoint == NULL ) { dev->device = g_strdup( devicepath ); } if ( !mple_get_media_serial_number( dev )) { if ( dev->path == NULL ) { fprintf( stderr, "unable to identify device %s\n", devicepath ); exit( 1 ); } } if ( mple_parse_pblist( dev ) == NULL ) { if ( errno ) { fprintf( stderr, "error getting pblist: %s\n", strerror( errno )); exit( 1 ); } /* otherwise it's just an empty device */ } /* print out header info */ if ( verbose ) { fprintf( stderr, "device: %s\n", dev->path ); fprintf( stderr, "serial: %08X\n", dev->msn ); fprintf( stderr, "tstamp: %ld -> %s", dev->timestamp, ctime( &(dev->timestamp ))); fprintf( stderr, "magic : %08x\n", dev->magic ); fprintf( stderr, "\n" ); } if ( dev->folderlist == NULL ) { fprintf( stderr, "No files on device.\n" ); } else { while(( fptr = g_list_nth_data( dev->folderlist, folder++ )) != NULL ) { guint32 track = 0; mple_track *tptr; fprintf( stderr, "Folder: " ); print_as_utf8( stderr, (char *)&(fptr->folderdata.foldername), 126 ); fprintf( stderr, "\n" ); if ( fptr->tracklist == NULL ) { fprintf( stderr, " empty folder\n" ); continue; } while (( tptr = g_list_nth_data( fptr->tracklist, track++ )) != NULL ) { char *mpdatname; FILE *mpdat; mpdat_hdr header; fprintf( stderr, " Track %d: ", tptr->tracknum ); print_as_utf8( stderr, (char *)&(tptr->trackdata.filename ), 128 ); fprintf( stderr, "\n" ); if ( verbose ) { fprintf( stderr, " Title: " ); print_as_utf8( stderr, (char *)&(tptr->trackdata.title ), 128 ); fprintf( stderr, "\n" ); fprintf( stderr, " Artist: " ); print_as_utf8( stderr, (char *)&(tptr->trackdata.artist ), 128 ); fprintf( stderr, "\n" ); /* now dig out the data from the file's header */ mpdatname = g_strdup_printf( dev->mptemplate, dev->path, tptr->tracknum ); if (( mpdat = fopen( mpdatname, "rb" )) != NULL ) { if ( fread( &header, sizeof( mpdat_hdr ), 1, mpdat ) == 1 ) { guint32 time = GUINT32_FROM_BE( header.time ); fprintf( stderr, " %ub / %02u:%02u.%03u / %u frames\n", GUINT32_FROM_BE( header.size ), time / ( 60 * 1000 ), ( time / 1000 ) % 60, time % 1000, GUINT32_FROM_BE( header.frames )); } else { fprintf( stderr, " error reading header\n" ); } fclose( mpdat ); } g_free( mpdatname ); } } } } mple_dev_free( dev ); } return 0; }