#ifndef MPLE_H #define MPLE_H #include /* I hate include files that aren't self-contained */ #include #include #include #include #define DEFAULT_PB_TEMPLATE "%s/esys/pblist%d.dat" #define DEFAULT_MP_TEMPLATE "%s/esys/nw-mp3/mp%04x.dat" #define DEFAULT_MASTER_PBLIST 1 #define MAX_TRACKS 40000 /* according to the manual */ /* On-disk data structures and magic */ #define PBLIST_MAGIC "\x00\x03\xce\xa0" #define MPDAT_MAGIC "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" /* This is used to find likely devices in HAL */ #define HAL_MAGIC "NETWORK WALKMAN" /* Header structure from pblist file [incomplete] */ typedef struct { guint8 signature[8]; /* "WMPLESYS", hence the name of the module */ guint32 timestamp; /* ctime of the ESYS folder */ guint32 msn; /* media serial number */ guint32 magic; /* no idea what this is */ guint32 folders; /* #folders */ guint32 tracks; /* number of tracks on the device */ /* XORing the header 32 bits at a time should result in this checksum, or XORing including this should result in zero */ guint32 checksum; /* XOR checksum */ } pblist_hdr; /* folder descriptor. complete. */ typedef struct { guint16 foldername[126]; /* name of this folder */ guint32 offset; /* offset from start of pblist file to track list */ } pblist_folder; /* track pointer in pblist. complete. */ typedef struct { guint16 filename[128]; guint16 title[128]; guint16 artist[128]; } pblist_track; /* Header structure from mp*.dat file. complete. */ typedef struct { guint8 signature[4]; /* "WMMP" */ guint32 size; /* size of file in bytes */ guint32 time; /* time in milliseconds */ guint32 frames; /* number of MP3 frames */ guint32 msn; /* media serial number */ guint8 magic[12]; } mpdat_hdr; /* and now, structures for passing the data around */ typedef struct { struct _mple_device *dev; struct _mple_folder *parent; guint16 tracknum; pblist_track trackdata; /* filesystem support */ mpdat_hdr header; id3_length_t id3datalen; gchar *id3data; } mple_track; typedef struct _mple_folder { struct _mple_device *dev; pblist_folder folderdata; GList *tracklist; } mple_folder; typedef enum _mple_aux_data { MPLE_MSN = 1, MPLE_TS = 2, MPLE_MAGIC = 4, } mple_aux_data; typedef struct _mple_device { /* where to find the device */ gchar *device; /* /dev/whatever */ gchar *path; /* base path to the device, e.g. "/media/NW-S23" */ /* auxilliary information */ mple_aux_data aux; /* whether this data is valid */ guint32 msn; /* media serial number */ time_t timestamp; /* timestamp from master pblist, converted to time_t */ guint32 magic; /* magic from pblist file */ /* where to find files on the device */ gchar *pbtemplate; /* e.g. "%s/esys/pblist%d.dat" */ gchar *mptemplate; /* e.g. "%s/esys/nw-mp3/mp%04x.dat" */ guint16 master_pblist; /* probably 1 */ /* the actual list of folders */ GList *folderlist; /* smarter syncing */ gboolean autosync; gboolean dirty; /* allow functions to report on progress */ void (* progress)( double percent, void *context ); void *context; } mple_device; /* Actual API-like thing */ /* Initialise/Release the device structure */ mple_device *mple_dev_init( char * ); void mple_dev_free( mple_device * ); guint16 mple_dev_sync( mple_device * ); /* this is an attempt to cater for devices that differ in where they place files. */ void *mple_dev_set_pb_template( mple_device *, char * ); void *mple_dev_set_mp_template( mple_device *, char * ); /* Pull the entire contents of the pblist (directory) off the device */ GList *mple_parse_pblist( mple_device * ); /* find/add/del/move folder */ /* Since pos == 0 is reserved for "add at first available slot", folder indices are 1-based. */ /* - del nukes the ENTIRE folder including contents */ guint16 mple_get_folder( mple_device *device, pblist_folder *folder ); guint16 mple_add_folder( mple_device *, pblist_folder *, guint16 pos ); guint16 mple_del_folder( mple_device *, guint16 pos ); guint16 mple_mv_folder( mple_device *, guint16 oldpos, guint16 newpos ); guint16 mple_ren_folder( mple_device *, guint16 pos, pblist_folder * ); /* same interface for tracks, less 'find' */ /* ren allows rewriting all metadata for the track */ guint16 mple_add_track( mple_device *, char *filename, pblist_track *, guint16 folder, guint16 pos ); guint16 mple_del_track( mple_device *, guint16 tracknum ); guint16 mple_mv_track( mple_device *, guint16 tracknum, guint16 folder, guint16 pos ); guint16 mple_ren_track( mple_device *, guint16 tracknum, pblist_track * ); mple_track *mple_get_track_ptr( mple_device *, guint16 ); gboolean mple_get_track_header( mple_device *, guint16 ); /* add an already-encoded track to a folder */ guint16 mple_add_to_folder( mple_device *, guint16 folder, pblist_track *, guint16 tracknum, guint16 pos ); /* extract metadata from a file/filehandle into a pblist_track struct */ pblist_track *mple_get_metadata_FILE( FILE * ); pblist_track *mple_get_metadata_NAME( char * ); /* write a file to the device. returns the track number */ guint16 mple_write_file( mple_device *, char *, guint16, guint16 ); /* convert a WMMP file back into an MP3 and write it to a file descriptor. Doesn't restore ID3 data as yet. */ gboolean mple_convert_wmmp( mple_track *, int /*fd_t*/ ); /* read the media serial number from the specified device */ gboolean mple_get_media_serial_number( mple_device * ); /* get a list of likely NW devices on the system */ GList *mple_get_nw_devs( gchar * ); /* filesystem-like support */ typedef struct _MPLEFILE { mple_track *tptr; FILE *fp; size_t ptr; guint8 conv[256]; /* Write support. There's a little too much for my liking in here... */ gboolean writing; gulong bufsize; guint8 *buffer; /* very much internal use only, thanks */ guint32 framerates[16]; guint32 frames; guint32 frate; guint32 flen; struct _mp3file *mp3f; gboolean format_ok; } MPLEFILE; MPLEFILE *mple_open( mple_device *, guint16, guint16, const gchar *, char *); int mple_close( MPLEFILE * ); int mple_seek( MPLEFILE *, long, int ); long mple_tell( MPLEFILE * ); size_t mple_read( void *, size_t, size_t, MPLEFILE *); size_t mple_write( void *, size_t, size_t, MPLEFILE *); int mple_stat( mple_device *, guint16, struct stat *buf ); /* convert mple strings into something more useful */ #include char *utf8_from_utf16be( char *, size_t ); guint16 *utf8_to_utf16be( const char *, size_t, size_t * ); #include gchar *mple_getstr( guint16 * ); wchar_t *guint16o_wchar( guint16 * ); #endif