Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1,58 @@
#include "../../Library/ml_pmp/pmp.h"
#include "api.h"
#include "../agave/albumart/svc_albumartprovider.h"
#include <api/service/waservicefactory.h>
extern PMPDevicePlugin plugin;
static svc_albumArtProvider *FindProvider(const wchar_t *filename, int providerType, waServiceFactory **factory)
{
FOURCC albumartprovider = svc_albumArtProvider::getServiceType();
int n = (int)plugin.service->service_getNumServices(albumartprovider);
for (int i=0; i<n; i++)
{
waServiceFactory *sf = plugin.service->service_enumService(albumartprovider,i);
if (sf)
{
svc_albumArtProvider * provider = (svc_albumArtProvider*)sf->getInterface();
if (provider)
{
if (provider->ProviderType() == providerType && provider->IsMine(filename))
{
*factory = sf;
return provider;
}
sf->releaseInterface(provider);
}
}
}
return NULL;
}
void CopyAlbumArt(const wchar_t *source, const wchar_t *destination)
{
size_t datalen = 0;
void *data = 0;
wchar_t *mimeType = 0;
waServiceFactory *destinationFactory = 0;
svc_albumArtProvider *destinationProvider = FindProvider(destination, ALBUMARTPROVIDER_TYPE_EMBEDDED, &destinationFactory);
if (destinationFactory)
{
/* First, look to see if there's already embedded album art */
if (destinationProvider->GetAlbumArtData(destination, L"cover", &data, &datalen, &mimeType) == ALBUMARTPROVIDER_SUCCESS && data && datalen)
{
destinationFactory->releaseInterface(destinationProvider);
WASABI_API_MEMMGR->sysFree(data);
WASABI_API_MEMMGR->sysFree(mimeType);
return;
}
else if (AGAVE_API_ALBUMART->GetAlbumArtData(source, L"cover", &data, &datalen, &mimeType) == ALBUMART_SUCCESS && data && datalen)
{
destinationProvider->SetAlbumArtData(destination, L"cover", data, datalen, mimeType);
WASABI_API_MEMMGR->sysFree(data);
WASABI_API_MEMMGR->sysFree(mimeType);
destinationFactory->releaseInterface(destinationProvider);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,240 @@
#pragma once
#include <windows.h>
#include <Dbt.h>
#include "../../Library/ml_pmp/transcoder.h"
#include "../../Library/ml_pmp/pmp.h"
#include "../nde/nde_c.h"
#include "../nu/AutoLock.h"
#include <vector>
#define WINAMP_ANDROID_MARKER_FILE L"\\.winamp\\winamp.info"
//Filename="E:\Howling Bells - Into The Chaos.MP3"
//Artist="Howling Bells"
//Album="E:"
//Title="Into The Chaos"
//Genre=""
//AlbumArtist=""
//Publisher=""
//Composer=""
//Year="0"
//Track="0"
//Bitrate="0"
//Playcount="0"
//Discnum="0"
//Length="0"
//Size="7767879"
enum
{
NDE_ANDROID_FAILURE=0,
NDE_ANDROID_SUCCESS=1,
};
enum
{
DEVICEVIEW_COL_FILENAME = 0,
DEVICEVIEW_COL_ARTIST=1,
DEVICEVIEW_COL_ALBUM=2,
DEVICEVIEW_COL_TITLE=3,
DEVICEVIEW_COL_GENRE=4,
DEVICEVIEW_COL_ALBUM_ARTIST=5,
DEVICEVIEW_COL_PUBLISHER=6,
DEVICEVIEW_COL_COMPOSER=7,
DEVICEVIEW_COL_YEAR=8,
DEVICEVIEW_COL_TRACK=9,
DEVICEVIEW_COL_BITRATE=10,
DEVICEVIEW_COL_DISC_NUMBER=11,
DEVICEVIEW_COL_LENGTH=12,
DEVICEVIEW_COL_SIZE=13,
DEVICEVIEW_COL_PLAY_COUNT=14,
};
#define TAG_CACHE L"winamp_metadata.dat"
#define FIELD_LENGTH 1024
class AndroidSong {
public:
AndroidSong();
wchar_t filename[MAX_PATH];
wchar_t artist[FIELD_LENGTH];
wchar_t album[FIELD_LENGTH];
wchar_t title[FIELD_LENGTH];
wchar_t genre[FIELD_LENGTH];
wchar_t albumartist[FIELD_LENGTH];
wchar_t publisher[FIELD_LENGTH];
wchar_t composer[FIELD_LENGTH];
int year,track,length,discnum,bitrate,playcount;
__int64 size;
BOOL filled;
wchar_t ext[ 6 ];
};
enum DeviceType {
TYPE_OTHER,
TYPE_PSP,
};
class AndroidPlaylist;
class AndroidArt
{
public:
AndroidArt(ARGB32 *bits, int w, int h);
~AndroidArt();
ARGB32 *bits;
int w,h;
};
class AndroidDevice : public Device
{
public:
AndroidDevice(wchar_t drive, pmpDeviceLoading * load);
~AndroidDevice();
AndroidDevice();
void fileProbe(wchar_t * indir);
void tag(void); //load ID3 tags from cache or mp3 file
void createDeviceFields();
int openDeviceDatabase();
int openDeviceTable();
void closeDeviceTable();
static void CloseDatabase();
void SeekToBegininngOfDevice(nde_scanner_t s);
void refreshNDECache(void);
void fillMetaData(AndroidSong *s);
static int getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, size_t len);
void setupTranscoder();
AndroidPlaylist* getMasterPlaylist();
AndroidSong* findSongInMasterPlaylist(const wchar_t *songfn);
void writeRecordToDB(AndroidSong* songToPrint);
//////////////////////////////////////////
virtual __int64 getDeviceCapacityAvailable(); // in bytes
virtual __int64 getDeviceCapacityTotal(); // in bytes
virtual void Eject(); // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this;
virtual void Close(); // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this;
// return 0 for success, -1 for failed or cancelled
virtual int transferTrackToDevice(const itemRecordW * track, // the track to transfer
void * callbackContext, //pass this to the callback
void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
songid_t * songid, // fill in the songid when you are finished
int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
);
virtual int trackAddedToTransferQueue(const itemRecordW *track); // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
virtual void trackRemovedFromTransferQueue(const itemRecordW *track);
// return the amount of space that will be taken up on the device by the track (once it has been tranferred)
// or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
virtual __int64 getTrackSizeOnDevice(const itemRecordW *track);
virtual void deleteTrack(songid_t songid); // physically remove from device. Be sure to remove it from all the playlists!
virtual void commitChanges(); // optional. Will be called at a good time to save changes
virtual int getPlaylistCount(); // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
// PlaylistName(0) should return the name of the device.
virtual void getPlaylistName(int playlistnumber, wchar_t *buf, int len);
virtual int getPlaylistLength(int playlistnumber);
virtual songid_t getPlaylistTrack(int playlistnumber,int songnum); // returns a songid
virtual void setPlaylistName(int playlistnumber, const wchar_t *buf); // with playlistnumber==0, set the name of the device.
virtual void playlistSwapItems(int playlistnumber, int posA, int posB); // swap the songs at position posA and posB
virtual void sortPlaylist(int playlistnumber, int sortBy);
virtual void addTrackToPlaylist(int playlistnumber, songid_t songid); // adds songid to the end of the playlist
virtual void removeTrackFromPlaylist(int playlistnumber, int songnum); //where songnum is the position of the track in the playlist
virtual void deletePlaylist(int playlistnumber);
virtual int newPlaylist(const wchar_t *name); // create empty playlist, returns playlistnumber. -1 for failed.
virtual void getTrackArtist(songid_t songid, wchar_t *buf, int len);
virtual void getTrackAlbum(songid_t songid, wchar_t *buf, int len);
virtual void getTrackTitle(songid_t songid, wchar_t *buf, int len);
virtual int getTrackTrackNum(songid_t songid);
virtual int getTrackDiscNum(songid_t songid);
virtual void getTrackGenre(songid_t songid, wchar_t * buf, int len);
virtual int getTrackYear(songid_t songid);
virtual __int64 getTrackSize(songid_t songid); // in bytes
virtual int getTrackLength(songid_t songid); // in millisecs
virtual int getTrackBitrate(songid_t songid); // in kbps
virtual int getTrackPlayCount(songid_t songid);
virtual int getTrackRating(songid_t songid); //0-5
virtual __time64_t getTrackLastPlayed(songid_t songid); // in unix time format
virtual __time64_t getTrackLastUpdated(songid_t songid); // in unix time format
virtual void getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len);
virtual void getTrackPublisher(songid_t songid, wchar_t *buf, int len);
virtual void getTrackComposer(songid_t songid, wchar_t *buf, int len);
virtual int getTrackType(songid_t songid);
virtual void getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len) ; //optional
// feel free to ignore any you don't support
virtual void setTrackArtist(songid_t songid, const wchar_t *value);
virtual void setTrackAlbum(songid_t songid, const wchar_t *value);
virtual void setTrackTitle(songid_t songid, const wchar_t *value);
virtual void setTrackTrackNum(songid_t songid, int value);
virtual void setTrackDiscNum(songid_t songid, int value);
virtual void setTrackGenre(songid_t songid, const wchar_t *value);
virtual void setTrackYear(songid_t songid, int year);
virtual void setTrackPlayCount(songid_t songid, int value);
virtual void setTrackRating(songid_t songid, int value);
virtual void setTrackLastPlayed(songid_t songid, __time64_t value); // in unix time format
virtual void setTrackLastUpdated(songid_t songid, __time64_t value); // in unix time format
virtual void setTrackAlbumArtist(songid_t songid, const wchar_t *value);
virtual void setTrackPublisher(songid_t songid, const wchar_t *value);
virtual void setTrackComposer(songid_t songid, const wchar_t *value);
virtual void setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value) ; //optional
virtual bool playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue); // return false if unsupported
virtual intptr_t extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4);
virtual bool copyToHardDriveSupported();
virtual __int64 songSizeOnHardDrive(songid_t song); // how big a song will be when copied back. Return -1 for not supported.
virtual int copyToHardDrive(songid_t song, // the song to copy
wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
void * callbackContext, //pass this to the callback
void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
); // -1 for failed/not supported. 0 for success.
// art functions
virtual void setArt(songid_t songid, void *buf, int w, int h); //buf is in format ARGB32*
virtual pmpart_t getArt(songid_t songid);
virtual void releaseArt(pmpart_t art);
virtual int drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h);
virtual void getArtNaturalSize(pmpart_t art, int *w, int *h);
virtual void setArtNaturalSize(pmpart_t art, int w, int h);
virtual void getArtData(pmpart_t art, void* data); // data ARGB32* is at natural size
virtual bool artIsEqual(pmpart_t a, pmpart_t b);
// Additional attributes
Transcoder *transcoder;
wchar_t drive;
wchar_t iniFile[MAX_PATH];
wchar_t pldir[MAX_PATH];
wchar_t songFormat[MAX_PATH];
wchar_t supportedFormats[MAX_PATH];
wchar_t purgeFolders[2];
int pl_write_mode; // used to determine how the playlists are stored
__int64 transferQueueLength;
std::vector<AndroidPlaylist*> androidPlaylists;
bool loadedUpToDate; //whether or not songs in memory are tagged and correct
static nde_database_t discDB;
nde_table_t deviceTable;
Nullsoft::Utility::LockGuard dbcs;
wchar_t ndeDataFile[100];
wchar_t ndeIndexFile[100];
private:
// update a track with new metadata (string)
void updateTrackField(AndroidSong* song, unsigned int col, const void* newValue, int fieldType);
bool readRecordFromDB(AndroidSong* song);
bool songChanged(AndroidSong* song);
};

View file

@ -0,0 +1,134 @@
#include "./androiddevice.h"
#include "./AndroidPlaylist.h"
#include <shlwapi.h>
#include <strsafe.h>
// dtor
// cleanup the memory allocated for the vector of songs
AndroidPlaylist::~AndroidPlaylist()
{
}
// this is the constructor that gets called
AndroidPlaylist::AndroidPlaylist(AndroidDevice& d, LPCTSTR fileName, BOOL m)
: device(d), master(m), dirty(false)
{
StringCbCopyW(filename, sizeof(filename), fileName);
StringCbCopyW(playlistName, sizeof(playlistName), PathFindFileName(fileName));
StringCbCopyW(playlistPath, sizeof(playlistName), fileName);
PathRemoveFileSpec(playlistPath);
}
void AndroidPlaylist::OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
{
if ( filename == NULL )
return;
AndroidSong *song = NULL;
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
song = device.findSongInMasterPlaylist( filename );
songs.push_back( song );
}
size_t AndroidPlaylist::size()
{
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
return songs.size();
}
AndroidSong *&AndroidPlaylist::at(size_t index)
{
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
return songs.at(index);
}
void AndroidPlaylist::push_back(AndroidSong *callback)
{
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
songs.push_back(callback);
dirty=TRUE;
}
void AndroidPlaylist::RemoveSong(AndroidSong *song)
{
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
size_t old_size = songs.size();
//songs.eraseAll(song);
auto it = songs.begin();
while (it != songs.end())
{
if (*it != song)
{
it++;
continue;
}
it = songs.erase(it);
}
if (old_size != songs.size())
dirty=TRUE;
}
void AndroidPlaylist::swap(size_t index1, size_t index2)
{
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
AndroidSong *temp = songs[index1];
songs[index1] = songs[index2];
songs[index2] = temp;
dirty = true;
}
void AndroidPlaylist::eraseAt(size_t index)
{
// Nullsoft::Utility::AutoLock songs_lock(songs_guard);
songs.erase(songs.begin() + index);
dirty=true;
}
static int filenamecmp( const wchar_t *f1, const wchar_t *f2 )
{
for ( ;;)
{
wchar_t c1 = *f1++;
wchar_t c2 = *f2++;
if ( !c1 && !c2 )
return 0;
if ( !c1 )
return -1;
if ( !c2 )
return 1;
c1 = towupper( c1 );
c2 = towupper( c2 );
if ( c1 == '\\' )
c1 = '/';
if ( c2 == '\\' )
c2 = '/';
if ( c1 < c2 )
return -1;
else if ( c1 > c2 )
return 1;
}
}
AndroidSong *AndroidPlaylist::FindSong(const wchar_t *filename)
{
//Nullsoft::Utility::AutoLock songs_lock(songs_guard);
for (SongList::iterator e = songs.begin(); e != songs.end(); e++)
{
if (filenamecmp(filename, (*e)->filename) == 0)
{
return (*e);
}
}
return 0;
}
#define CBCLASS AndroidPlaylist
START_DISPATCH;
VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
END_DISPATCH;

View file

@ -0,0 +1,49 @@
#pragma once
#include <vector>
#include "../playlist/ifc_playlistloadercallback.h"
#include "../nu/AutoLock.h"
class AndroidDevice;
class AndroidSong;
class AndroidPlaylist: public ifc_playlistloadercallback
{
public:
AndroidPlaylist(AndroidDevice& d, LPCTSTR pszPlaylist, BOOL master);
~AndroidPlaylist();
public:
/*** ifc_playlistloadercallback ***/
void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
public:
// utility
BOOL isMaster() { return master; }
wchar_t* getFilename() { return filename; }
size_t size();
AndroidSong *&at(size_t index);
void push_back(AndroidSong *callback);
void RemoveSong(AndroidSong *song);
void swap(size_t index1, size_t index2);
void eraseAt(size_t index);
AndroidSong *FindSong(const wchar_t *filename);
protected:
RECVS_DISPATCH;
private:
AndroidDevice &device;
typedef std::vector<AndroidSong*> SongList;
SongList songs;
public:
//Nullsoft::Utility::LockGuard songs_guard;
wchar_t playlistName[MAX_PATH];
wchar_t playlistPath[MAX_PATH];
wchar_t filename[MAX_PATH];
BOOL master;
BOOL dirty;
};

View file

@ -0,0 +1,74 @@
#include "./androidplaylistsaver.h"
#include "./androidplaylist.h"
#include "./androiddevice.h"
#include "./api.h"
#include <strsafe.h>
AndroidPlaylistSaver::AndroidPlaylistSaver(LPCTSTR iFilename, LPCTSTR iPlaylistName, AndroidPlaylist *iPlaylist)
: filename((LPTSTR)iFilename), title((LPTSTR)iPlaylistName), playlist(iPlaylist)
{
}
AndroidPlaylistSaver::~AndroidPlaylistSaver()
{
}
HRESULT AndroidPlaylistSaver::Save()
{
INT result = WASABI_API_PLAYLISTMNGR->Save(filename, this);
return (PLAYLISTMANAGER_SUCCESS == result) ? S_OK : E_FAIL;
}
size_t AndroidPlaylistSaver::GetNumItems()
{
return playlist->size();
}
size_t AndroidPlaylistSaver::GetItem(size_t item, wchar_t *filename, size_t filenameCch)
{
AndroidSong* song = (AndroidSong *) playlist->at(item);
if (!song) return 0;
HRESULT hr = StringCchCopyEx(filename, filenameCch, song->filename, NULL, NULL, STRSAFE_IGNORE_NULLS);
if (FAILED(hr))
*filename = L'\0';
return SUCCEEDED(hr);
}
size_t AndroidPlaylistSaver::GetItemTitle(size_t item, wchar_t *title, size_t titleCch)
{
AndroidSong* song = (AndroidSong *) playlist->at(item);
if (!song) return 0;
HRESULT hr = StringCchCopyEx(title, titleCch, song->title, NULL, NULL, STRSAFE_IGNORE_NULLS);
if (FAILED(hr))
*title = L'\0';
return SUCCEEDED(hr);
}
int AndroidPlaylistSaver::GetItemLengthMs(size_t item)
{
AndroidSong* song = (AndroidSong *) playlist->at(item);
if (!song) return 0;
return song->length ? song->length: -1;
}
size_t AndroidPlaylistSaver::GetItemExtendedInfo(size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch)
{
return 0;
}
#define CBCLASS AndroidPlaylistSaver
START_DISPATCH;
CB(IFC_PLAYLIST_GETNUMITEMS, GetNumItems)
CB(IFC_PLAYLIST_GETITEM, GetItem)
CB(IFC_PLAYLIST_GETITEMTITLE, GetItemTitle)
CB(IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMs)
CB(IFC_PLAYLIST_GETITEMEXTENDEDINFO, GetItemExtendedInfo)
END_DISPATCH;

View file

@ -0,0 +1,33 @@
#pragma once
#include <wtypes.h>
#include "../playlist/ifc_playlist.h"
class AndroidPlaylist;
class AndroidPlaylistSaver : public ifc_playlist
{
public:
AndroidPlaylistSaver(LPCTSTR iFilename, LPCTSTR iTitle, AndroidPlaylist * iPlaylist);
virtual ~AndroidPlaylistSaver();
public:
/*** ifc_playlist ***/
size_t GetNumItems();
size_t GetItem(size_t item, wchar_t *filename, size_t filenameCch);
size_t GetItemTitle(size_t item, wchar_t *title, size_t titleCch);
int GetItemLengthMs(size_t item); // TODO: maybe microsecond for better resolution?
size_t GetItemExtendedInfo(size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch);
HRESULT Save();
protected:
RECVS_DISPATCH;
protected:
LPTSTR title;
LPTSTR filename;
AndroidPlaylist *playlist;
};

View file

@ -0,0 +1,64 @@
#include "../../Library/ml_pmp/pmp.h"
#include "api.h"
#include <api/service/waservicefactory.h>
api_language *WASABI_API_LNG = 0;
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
// Metadata service
api_metadata *AGAVE_API_METADATA=0;
api_playlistmanager *WASABI_API_PLAYLISTMNGR=0;
api_threadpool *WASABI_API_THREADPOOL=0;
api_albumart *AGAVE_API_ALBUMART=0;
api_memmgr *WASABI_API_MEMMGR=0;
api_application *WASABI_API_APP=0;
api_devicemanager *AGAVE_API_DEVICEMANAGER = 0;
extern PMPDevicePlugin plugin;
template <class api_T>
void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
{
if (plugin.service)
{
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
api_t = reinterpret_cast<api_T *>( factory->getInterface() );
}
}
template <class api_T>
void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
{
if (plugin.service && api_t)
{
waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
if (factory)
factory->releaseInterface(api_t);
}
api_t = NULL;
}
void WasabiInit()
{
ServiceBuild(WASABI_API_LNG, languageApiGUID);
ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
ServiceBuild(WASABI_API_PLAYLISTMNGR, api_playlistmanagerGUID);
ServiceBuild(WASABI_API_THREADPOOL, ThreadPoolGUID);
ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
ServiceBuild(WASABI_API_MEMMGR, memMgrApiServiceGuid);
ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
ServiceBuild(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
}
void WasabiQuit()
{
ServiceRelease(WASABI_API_LNG, languageApiGUID);
ServiceRelease(WASABI_API_PLAYLISTMNGR, api_playlistmanagerGUID);
ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
ServiceRelease(WASABI_API_THREADPOOL, ThreadPoolGUID);
ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
ServiceRelease(WASABI_API_MEMMGR, memMgrApiServiceGuid);
ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
ServiceRelease(AGAVE_API_DEVICEMANAGER, DeviceManagerGUID);
}

View file

@ -0,0 +1,34 @@
#pragma once
#include "../Agave/Language/api_language.h"
#include "../Agave/Metadata/api_metadata.h"
extern api_metadata *metadataApi;
#define AGAVE_API_METADATA metadataApi
#include "../playlist/api_playlistmanager.h"
extern api_playlistmanager *playlistManagerApi;
#define WASABI_API_PLAYLISTMNGR playlistManagerApi
#include "../nu/threadpool/api_threadpool.h"
extern api_threadpool *threadPoolApi;
#define WASABI_API_THREADPOOL threadPoolApi
#include "../Agave/AlbumArt/api_albumart.h"
extern api_albumart *albumArtApi;
#define AGAVE_API_ALBUMART albumArtApi
#include <api/memmgr/api_memmgr.h>
extern api_memmgr *memmgr;
#define WASABI_API_MEMMGR memmgr
#include <api/application/api_application.h>
extern api_application *applicationApi;
#define WASABI_API_APP applicationApi
#include "../devices/api_devicemanager.h"
extern api_devicemanager *deviceManagerApi;
#define AGAVE_API_DEVICEMANAGER deviceManagerApi
void WasabiInit();
void WasabiQuit();

View file

@ -0,0 +1,343 @@
#include "api.h"
#include "./deviceprovider.h"
#include "../devices/api_devicemanager.h"
extern PMPDevicePlugin plugin;
void connectDrive(wchar_t drive, bool checkSize, bool checkBlacklist);
static size_t tlsIndex = (size_t)-1;
static BOOL
DiscoveryProvider_RegisterCancelSwitch(BOOL *cancelSwitch)
{
if ((size_t)-1 != tlsIndex &&
NULL != WASABI_API_APP)
{
WASABI_API_APP->SetThreadStorage(tlsIndex, cancelSwitch);
return TRUE;
}
return FALSE;
}
static BOOL
DiscoveryProvider_GetCancelSwitchOn()
{
if ((size_t)-1 != tlsIndex &&
NULL != WASABI_API_APP)
{
BOOL *cancelSwitch = (BOOL*)WASABI_API_APP->GetThreadStorage(tlsIndex);
if (NULL != cancelSwitch &&
FALSE != *cancelSwitch)
{
return TRUE;
}
}
return FALSE;
}
static void
DeviceProvider_DriverEnumCb(wchar_t drive, unsigned int type)
{
if (DRIVE_REMOVABLE == type &&
FALSE == DiscoveryProvider_GetCancelSwitchOn())
{
connectDrive(drive,true,true);
}
}
DeviceProvider::DeviceProvider()
: ref(1), activity(0), manager(NULL), readyEvent(NULL), cancelDiscovery(FALSE)
{
InitializeCriticalSection(&lock);
enumerator = (ENUMDRIVES)SendMessageW(plugin.hwndPortablesParent,
WM_PMP_IPC, 0, PMP_IPC_ENUM_ACTIVE_DRIVES);
}
DeviceProvider::~DeviceProvider()
{
CancelDiscovery();
if (NULL != readyEvent)
CloseHandle(readyEvent);
DeleteCriticalSection(&lock);
}
HRESULT DeviceProvider::CreateInstance(DeviceProvider **instance)
{
if (NULL == instance)
return E_POINTER;
*instance = new DeviceProvider();
if (NULL == *instance)
return E_OUTOFMEMORY;
return S_OK;
}
size_t DeviceProvider::AddRef()
{
return InterlockedIncrement((LONG*)&ref);
}
size_t DeviceProvider::Release()
{
if (0 == ref)
return ref;
LONG r = InterlockedDecrement((LONG*)&ref);
if (0 == r)
delete(this);
return r;
}
int DeviceProvider::QueryInterface(GUID interface_guid, void **object)
{
if (NULL == object)
return E_POINTER;
if (IsEqualIID(interface_guid, IFC_DeviceProvider))
*object = static_cast<ifc_deviceprovider*>(this);
else
{
*object = NULL;
return E_NOINTERFACE;
}
if (NULL == *object)
return E_UNEXPECTED;
AddRef();
return S_OK;
}
void DeviceProvider::Lock()
{
EnterCriticalSection(&lock);
}
void DeviceProvider::Unlock()
{
LeaveCriticalSection(&lock);
}
DWORD DeviceProvider::DiscoveryThread()
{
IncrementActivity();
if (NULL != enumerator &&
FALSE == cancelDiscovery)
{
DiscoveryProvider_RegisterCancelSwitch(&cancelDiscovery);
enumerator(DeviceProvider_DriverEnumCb);
DiscoveryProvider_RegisterCancelSwitch(NULL);
}
DecrementActivity();
Lock();
if (NULL != readyEvent)
SetEvent(readyEvent);
Unlock();
return 0;
}
static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user, intptr_t id)
{
DeviceProvider *self;
DWORD result;
self = (DeviceProvider*)user;
if (NULL != self)
result = self->DiscoveryThread();
else
result = -2;
return result;
}
HRESULT DeviceProvider::BeginDiscovery(api_devicemanager *manager)
{
HRESULT hr;
if (NULL == enumerator)
return E_UNEXPECTED;
Lock();
if (NULL != readyEvent &&
WAIT_TIMEOUT == WaitForSingleObject(readyEvent, 0))
{
hr = E_PENDING;
}
else
{
hr = S_OK;
if (NULL == readyEvent)
{
readyEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (NULL == readyEvent)
hr = E_FAIL;
}
if ((size_t)-1 == tlsIndex &&
NULL != WASABI_API_APP)
{
tlsIndex = WASABI_API_APP->AllocateThreadStorage();
}
if (SUCCEEDED(hr))
{
cancelDiscovery = FALSE;
ResetEvent(readyEvent);
if (0 != WASABI_API_THREADPOOL->RunFunction(0, DeviceProvider_DiscoveryThreadStarter,
this, 0, api_threadpool::FLAG_LONG_EXECUTION))
{
SetEvent(readyEvent);
hr = E_FAIL;
}
}
}
Unlock();
return hr;
}
HRESULT DeviceProvider::CancelDiscovery()
{
HRESULT hr;
hr = S_FALSE;
Lock();
if (NULL != readyEvent)
{
cancelDiscovery = TRUE;
if (WAIT_OBJECT_0 == WaitForSingleObject(readyEvent, 0))
hr = S_OK;
cancelDiscovery = FALSE;
}
Unlock();
return hr;
}
HRESULT DeviceProvider::GetActive()
{
HRESULT hr;
Lock();
if (0 != activity)
hr = S_OK;
else
hr = S_FALSE;
Unlock();
return hr;
}
HRESULT DeviceProvider::Register(api_devicemanager *manager)
{
HRESULT hr;
if (NULL != this->manager)
return E_UNEXPECTED;
if (NULL == manager)
return E_POINTER;
hr = manager->RegisterProvider(this);
if (SUCCEEDED(hr))
{
this->manager = manager;
manager->AddRef();
}
return hr;
}
HRESULT DeviceProvider::Unregister()
{
HRESULT hr;
if (NULL == manager)
return E_UNEXPECTED;
hr = manager->UnregisterProvider(this);
manager->Release();
manager = NULL;
return hr;
}
size_t DeviceProvider::IncrementActivity()
{
size_t a;
Lock();
activity++;
if (1 == activity &&
NULL != manager)
{
manager->SetProviderActive(this, TRUE);
}
a = activity;
Unlock();
return a;
}
size_t DeviceProvider::DecrementActivity()
{
size_t a;
Lock();
if (0 != activity)
{
activity--;
if (0 == activity &&
NULL != manager)
{
manager->SetProviderActive(this, FALSE);
}
}
a = activity;
Unlock();
return a;
}
#define CBCLASS DeviceProvider
START_DISPATCH;
CB(ADDREF, AddRef)
CB(RELEASE, Release)
CB(QUERYINTERFACE, QueryInterface)
CB(API_BEGINDISCOVERY, BeginDiscovery)
CB(API_CANCELDISCOVERY, CancelDiscovery)
CB(API_GETACTIVE, GetActive)
END_DISPATCH;
#undef CBCLASS

View file

@ -0,0 +1,50 @@
#pragma once
#include <wtypes.h>
#include "../devices/ifc_deviceprovider.h"
#include "../../Library/ml_pmp/pmp.h"
class DeviceProvider : public ifc_deviceprovider
{
protected:
DeviceProvider();
~DeviceProvider();
public:
static HRESULT CreateInstance(DeviceProvider **instance);
public:
/* Dispatchable */
size_t AddRef();
size_t Release();
int QueryInterface(GUID interface_guid, void **object);
/* ifc_deviceprovider */
HRESULT BeginDiscovery(api_devicemanager *manager);
HRESULT CancelDiscovery();
HRESULT GetActive();
public:
HRESULT Register(api_devicemanager *manager);
HRESULT Unregister();
size_t IncrementActivity();
size_t DecrementActivity();
private:
void Lock();
void Unlock();
DWORD DiscoveryThread();
friend static int DeviceProvider_DiscoveryThreadStarter(HANDLE handle, void *user_data, intptr_t id);
protected:
size_t ref;
size_t activity;
CRITICAL_SECTION lock;
api_devicemanager *manager;
ENUMDRIVES enumerator;
HANDLE readyEvent;
BOOL cancelDiscovery;
protected:
RECVS_DISPATCH;
};

View file

@ -0,0 +1,138 @@
// this file almost totally copied from MSDN
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#define LOCK_TIMEOUT 3000 // 10 Seconds
#define LOCK_RETRIES 20
static HANDLE OpenVolume(TCHAR cDriveLetter)
{
HANDLE hVolume;
UINT uDriveType;
wchar_t szVolumeName[8] = {0};
wchar_t szRootName[5] = {0};
DWORD dwAccessFlags = 0;
wsprintf(szRootName, L"%c:\\", cDriveLetter);
uDriveType = GetDriveType(szRootName);
switch(uDriveType) {
case DRIVE_REMOVABLE:
dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
break;
case DRIVE_CDROM:
dwAccessFlags = GENERIC_READ;
break;
default:
printf("Cannot eject. Drive type is incorrect.\n");
return INVALID_HANDLE_VALUE;
}
wsprintf(szVolumeName, L"\\\\.\\%c:", cDriveLetter);
hVolume = CreateFile( szVolumeName,
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
if (hVolume == INVALID_HANDLE_VALUE)
printf("CreateFile error %d\n", GetLastError());
return hVolume;
}
static BOOL CloseVolume(HANDLE hVolume)
{
return CloseHandle(hVolume);
}
static BOOL LockVolume(HANDLE hVolume)
{
DWORD dwBytesReturned;
DWORD dwSleepAmount;
int nTryCount;
dwSleepAmount = LOCK_TIMEOUT / LOCK_RETRIES;
// Do this in a loop until a timeout period has expired
for (nTryCount = 0; nTryCount < LOCK_RETRIES; nTryCount++) {
if (DeviceIoControl(hVolume,
FSCTL_LOCK_VOLUME,
NULL, 0,
NULL, 0,
&dwBytesReturned,
NULL))
return TRUE;
Sleep(dwSleepAmount);
}
return FALSE;
}
static BOOL DismountVolume(HANDLE hVolume)
{
DWORD dwBytesReturned;
return DeviceIoControl( hVolume,
FSCTL_DISMOUNT_VOLUME,
NULL, 0,
NULL, 0,
&dwBytesReturned,
NULL);
}
static BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPreventRemoval)
{
DWORD dwBytesReturned;
PREVENT_MEDIA_REMOVAL PMRBuffer;
PMRBuffer.PreventMediaRemoval = fPreventRemoval;
return DeviceIoControl( hVolume,
IOCTL_STORAGE_MEDIA_REMOVAL,
&PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),
NULL, 0,
&dwBytesReturned,
NULL);
}
static int AutoEjectVolume(HANDLE hVolume)
{
DWORD dwBytesReturned;
return DeviceIoControl( hVolume,
IOCTL_STORAGE_EJECT_MEDIA,
NULL, 0,
NULL, 0,
&dwBytesReturned,
NULL);
}
BOOL EjectVolume(TCHAR cDriveLetter)
{
HANDLE hVolume;
BOOL fAutoEject = FALSE;
hVolume = OpenVolume(cDriveLetter);
if (hVolume == INVALID_HANDLE_VALUE)
return FALSE;
// Lock and dismount the volume.
if (LockVolume(hVolume) && DismountVolume(hVolume)) {
// Set prevent removal to false and eject the volume.
if (PreventRemovalOfVolume(hVolume, FALSE) && AutoEjectVolume(hVolume))
fAutoEject = TRUE;
}
// Close the volume so other processes can use the drive.
if (!CloseVolume(hVolume))
return FALSE;
if (fAutoEject) return TRUE;
else return FALSE;
}

View file

@ -0,0 +1,67 @@
#include "api.h"
#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include "resource.h"
#include <strsafe.h>
typedef struct CopyData
{
void * callbackContext;
void (*callback)(void * callbackContext, wchar_t * status);
} CopyData;
DWORD CALLBACK CopyToIpodProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred,
LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred,
DWORD dwStreamNumber,
DWORD dwCallbackReason,
HANDLE hSourceFile, HANDLE hDestinationFile,
LPVOID lpData)
{
CopyData *inst = (CopyData *)lpData;
if (inst && inst->callback)
{
wchar_t status[100] = {0};
wchar_t langtemp[100] = {0};
StringCbPrintf(status, sizeof(status), WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFERING_PERCENT, langtemp, 100), (int)(100ULL * TotalBytesTransferred.QuadPart / (TotalFileSize.QuadPart)));
inst->callback(inst->callbackContext,status);
}
return PROGRESS_CONTINUE;
}
int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch)
{
wchar_t langtemp[100] = {0};
CopyData c;
c.callback = callback;
c.callbackContext = callbackContext;
if (CopyFileEx(infile, outfile, CopyToIpodProgressRoutine, &c, killswitch,0))
{
if (callback)
{
callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_DONE, langtemp, 100));
}
return 0;
}
else
{
switch(GetLastError())
{
case ERROR_REQUEST_ABORTED:
DeleteFile(outfile);
if (callback)
{
callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_CANCELLED, langtemp, 100));
}
default:
if (callback)
{
callback(callbackContext, WASABI_API_LNGSTRINGW_BUF(IDS_TRANSFER_FAILED, langtemp, 100));
}
}
return -1;
}
}

View file

@ -0,0 +1,601 @@
#include "../../Library/ml_pmp/pmp.h"
#include "../Winamp/wa_ipc.h"
#include <vector>
#include "../nu/AutoWide.h"
#include "../nu/AutoChar.h"
#include "../nu/Alias.h"
#include <api/service/waServiceFactory.h>
#include "api.h"
#include "resource.h"
#include "androiddevice.h"
#include "deviceprovider.h"
#include <devguid.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <strsafe.h>
#define PLUGIN_VERSION L"1.72"
static int Init();
static void Quit();
static bool doRegisterForDevNotification(void);
static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3);
extern PMPDevicePlugin plugin = {PMPHDR_VER,0,Init,Quit,MessageProc};
// start-android
static const wchar_t *winampini;
static std::vector<wchar_t*> blacklist;
bool loading_devices[26] = {0,};
static HDEVNOTIFY hDevNotify;
std::vector<AndroidDevice*> devices;
HWND config;
static DeviceProvider *deviceProvider = NULL;
static UINT_PTR rescanTimer = 0;
static void blacklistLoad() {
wchar_t keyname[64] = {0};
int l = GetPrivateProfileIntW(L"pmp_android", L"blacklistnum", 0, winampini);
for(int i=l>100?l-100:0; i<l; i++) {
wchar_t buf[100] = {0};
StringCchPrintfW(keyname, 64, L"blacklist-%d", i);
GetPrivateProfileStringW(L"pmp_android", keyname, L"", buf, 100, winampini);
if(buf[0])
{
blacklist.push_back(_wcsdup(buf));
}
}
}
static void blacklistSave() {
wchar_t buf[64] = {0};
StringCchPrintfW(buf, 64, L"%d", blacklist.size());
WritePrivateProfileStringW(L"pmp_android", L"blacklistnum", buf, winampini);
for(size_t i=0; i<blacklist.size(); i++)
{
StringCchPrintfW(buf, 64, L"blacklist-%d", i);
WritePrivateProfileStringW(L"pmp_android", buf, (const wchar_t*)blacklist.at(i), winampini);
}
}
static wchar_t *makeBlacklistString(wchar_t drive) {
wchar_t path[4]={drive,L":\\"};
wchar_t name[100]=L"";
wchar_t buf[FIELD_LENGTH]=L"";
DWORD serial=0;
UINT olderrmode=SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
GetVolumeInformation(path,name,100,&serial,NULL,NULL,NULL,0);
if(serial)
{
StringCchPrintf(buf, FIELD_LENGTH, L"s:%d",serial);
SetErrorMode(olderrmode);
return _wcsdup(buf);
}
{
ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
StringCchPrintf(buf, FIELD_LENGTH, L"n:%s,%d,%d", name, total.HighPart, total.LowPart);
SetErrorMode(olderrmode);
return _wcsdup(buf);
}
}
static bool blacklistCheck(wchar_t drive)
{
wchar_t *s = makeBlacklistString(drive);
if (s)
{
for(size_t i=0; i<blacklist.size(); i++)
{
if(!wcscmp(s,(wchar_t*)blacklist.at(i)))
{
free(s);
return true;
}
}
free(s);
}
return false;
}
static bool blacklistAdd(const wchar_t drive)
{
wchar_t *s = makeBlacklistString(drive);
if (s)
{
for(size_t i=0; i<blacklist.size(); i++)
{
if(!wcscmp(s,(wchar_t*)blacklist.at(i)))
{
free(s);
return false;
}
}
blacklist.push_back(s);
}
return true;
}
static BOOL
Device_IsiPod(const wchar_t drive)
{
const wchar_t test[] = {drive, L":\\iPod_Control"};
WIN32_FIND_DATAW findData;
HANDLE file = FindFirstFileW(test, &findData);
if (INVALID_HANDLE_VALUE != file)
{
FindClose(file);
if (0 != (FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes))
return TRUE;
}
return FALSE;
}
static BOOL
Device_IsAndroid(const wchar_t drive)
{
const wchar_t test[] = {drive, L":\\Android"};
WIN32_FIND_DATAW findData;
HANDLE file = FindFirstFileW(test, &findData);
if (INVALID_HANDLE_VALUE != file)
{
FindClose(file);
if (0 != (FILE_ATTRIBUTE_DIRECTORY & findData.dwFileAttributes))
return TRUE;
}
return FALSE;
}
static BOOL
Device_IsSizeOk(const wchar_t drive)
{
const wchar_t test[] = {drive, L":\\"};
ULARGE_INTEGER total;
if (0 == GetDiskFreeSpaceExW(test, NULL, &total, NULL) ||
total.HighPart == 0 && total.LowPart == 0)
{
return FALSE;
}
return TRUE;
}
static BOOL
Device_IsOkToConnect(const wchar_t drive)
{
const wchar_t test[] = {drive, TEXT(":\\Winamp\\")TAG_CACHE};
wchar_t title[128] = {0};
wchar_t message[1024] = {0};
int result;
if (FALSE != PathFileExistsW(test))
return TRUE;
StringCbPrintfW(message, sizeof(message), WASABI_API_LNGSTRINGW(IDS_REMOVEABLE_DRIVE_DETECTED),
towupper(drive));
WASABI_API_LNGSTRINGW_BUF(IDS_WINAMP_PMP_SUPPORT,title,ARRAYSIZE(title));
result = MessageBoxW(NULL, message, title,
MB_YESNO | MB_SETFOREGROUND | MB_TOPMOST |
MB_ICONINFORMATION);
if(IDNO == result)
{
return FALSE;
}
return TRUE;
}
static Nullsoft::Utility::LockGuard connect_guard;
static int ThreadFunc_Load(HANDLE handle, void *user_data, intptr_t id)
{
wchar_t drive = (wchar_t)id;
if (FALSE == Device_IsOkToConnect(drive))
{
Nullsoft::Utility::AutoLock connect_lock(connect_guard);
blacklistAdd(drive);
blacklistSave();
}
else
{
pmpDeviceLoading load;
Device * d = new AndroidDevice(drive,&load);
}
loading_devices[drive-'A'] = false;
deviceProvider->DecrementActivity();
return 0;
}
//#include <WinIoCtl.h>
void connectDrive(wchar_t drive, bool checkSize=true, bool checkBlacklist=true)
{
Nullsoft::Utility::AutoLock connect_lock(connect_guard);
// capitalize
if (drive >= 'a' && drive <= 'z')
drive = drive - 32;
// reject invalid drive letters
if (drive < 'A' || drive > 'Z')
return;
if(checkBlacklist && blacklistCheck(drive))
return;
// if device is taken already ignore
for (std::vector<AndroidDevice*>::const_iterator e = devices.begin(); e != devices.end(); e++)
{
if ((*e)->drive == drive)
return;
}
if (loading_devices[drive-'A'])
return;
loading_devices[drive-'A'] = true;
if(FALSE == checkSize || FALSE != Device_IsSizeOk(drive))
{
if (FALSE != Device_IsAndroid(drive) &&
FALSE == Device_IsiPod(drive))
{
deviceProvider->IncrementActivity();
if (NULL != WASABI_API_THREADPOOL &&
0 == WASABI_API_THREADPOOL->RunFunction(0, ThreadFunc_Load, 0,
(int)drive, api_threadpool::FLAG_LONG_EXECUTION))
{
return;
}
deviceProvider->DecrementActivity();
}
}
loading_devices[drive-'A'] = false;
}
static void autoDetectCallback(wchar_t drive,UINT type)
{
if(type == DRIVE_REMOVABLE)
{
connectDrive(drive, true, true);
}
}
// end-android
static int Init()
{
WasabiInit();
// start-android
winampini = (const wchar_t*)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETINIFILEW);
// need to have this initialised before we try to do anything with localisation features
WASABI_API_START_LANG(plugin.hDllInstance,PmpAndroidLangGUID);
// end-android
static wchar_t szDescription[256];
StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
WASABI_API_LNGSTRINGW(IDS_NULLSOFT_ANDROID_DEVICE_PLUGIN), PLUGIN_VERSION);
plugin.description = szDescription;
/** load up the backlist */
blacklistLoad();
if (NULL != AGAVE_API_DEVICEMANAGER &&
NULL == deviceProvider)
{
if (SUCCEEDED(DeviceProvider::CreateInstance(&deviceProvider)) &&
FAILED(deviceProvider->Register(AGAVE_API_DEVICEMANAGER)))
{
deviceProvider->Release();
deviceProvider = NULL;
}
}
/* Our device shows up as a normal drive */
if (NULL == deviceProvider ||
FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
{
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
}
return 0;
}
static void Quit()
{
if (NULL != deviceProvider)
{
deviceProvider->Unregister();
deviceProvider->Release();
deviceProvider = NULL;
}
WasabiQuit();
UnregisterDeviceNotification(hDevNotify);
AndroidDevice::CloseDatabase();
}
static wchar_t FirstDriveFromMask(ULONG *unitmask) {
char i;
ULONG adj = 0x1, mask = *unitmask;
for(i=0; i<26; ++i) {
if(mask & 0x1) {
*unitmask -= adj;
break;
}
adj = adj << 1;
mask = mask >> 1;
}
return (i+L'A');
}
static int GetNumberOfDrivesFromMask(ULONG unitmask) {
int count = 0;
for(int i=0; i<26; ++i)
{
if(unitmask & 0x1)
count++;
unitmask = unitmask >> 1;
}
return count;
}
static void CALLBACK RescanOnTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
KillTimer(hwnd, idEvent);
if (idEvent == rescanTimer)
rescanTimer = 0;
if (NULL == deviceProvider ||
FAILED(deviceProvider->BeginDiscovery(AGAVE_API_DEVICEMANAGER)))
{
PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)autoDetectCallback,PMP_IPC_ENUM_ACTIVE_DRIVES);
}
}
int wmDeviceChange(WPARAM wParam, LPARAM lParam)
{
UINT olderrmode=SetErrorMode(SEM_FAILCRITICALERRORS);
if(wParam==DBT_DEVICEARRIVAL || wParam==DBT_DEVICEREMOVECOMPLETE)
{ // something has been inserted or removed
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
if(lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
{ // its a volume
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if((!(lpdbv->dbcv_flags & DBTF_MEDIA) && !(lpdbv->dbcv_flags & DBTF_NET)))
{ // its not a network drive or a CD/floppy, game on!
ULONG dbcv_unitmask = lpdbv->dbcv_unitmask;
// see just how many drives have been flagged on the action
// eg one android drive could have multiple partitions that we handle
int count = GetNumberOfDrivesFromMask(dbcv_unitmask);
for(int j = 0; j < count; j++)
{
wchar_t drive = FirstDriveFromMask(&dbcv_unitmask);
if((wParam == DBT_DEVICEARRIVAL) && !blacklistCheck(drive))
{ // connected
connectDrive(drive);
//send a message as if the user just selected a drive from the combo box, this way the fields are refreshed to the correct device's settings
SendMessage(config, WM_COMMAND,MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0);
}
else
{ // removal
for(size_t i=0; i < devices.size(); i++)
{
AndroidDevice * d = (AndroidDevice*)devices.at(i);
if(d->drive == drive)
{
devices.erase(devices.begin() + i);
if(config) SendMessage(config,WM_USER,0,0); //refresh fields
if(config) SendMessage(config,WM_COMMAND, MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0); //update to correct device change as if the user had clicked on the combo box themself
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)d,PMP_IPC_DEVICEDISCONNECTED);
delete d;
i--;
}
}
}
}
}
}
}
else
{
rescanTimer = SetTimer(NULL, rescanTimer, 10000, RescanOnTimer);
}
SetErrorMode(olderrmode);
return 0;
}
static int IsDriveConnectedToPMP(wchar_t drive)
{
for(size_t i = 0; i < devices.size(); i++)
{
if(((AndroidDevice*)devices.at(i))->drive == drive)
{
return 1;
}
}
return 0;
}
static INT_PTR CALLBACK config_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
for(wchar_t d=L'A'; d<='Z'; d++)
{
wchar_t drive[3] = {d,L':',0}, drv[4] = {d,L':','\\',0};
UINT uDriveType = GetDriveType(drv);
if(uDriveType == DRIVE_REMOVABLE || uDriveType == DRIVE_CDROM || uDriveType == DRIVE_FIXED) {
int position = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_ADDSTRING,0,(LPARAM)drive);
SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_SETITEMDATA,position,d);
}
}
SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_SETCURSEL,0,0);
SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
}
break;
case WM_CLOSE:
EndDialog(hwndDlg,0);
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDC_COMBO_MANUALCONNECT:
{
if(HIWORD(wParam)==CBN_SELCHANGE) {
int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
if(indx >= 0)
{
int connected = IsDriveConnectedToPMP(drive), isblacklisted = blacklistCheck(drive);
EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALCONNECT), !connected && !isblacklisted);
EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALDISCONNECT), connected);
EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALBLACKLIST), TRUE);
SetDlgItemText(hwndDlg, IDC_MANUALBLACKLIST, WASABI_API_LNGSTRINGW(isblacklisted ? IDS_UNBLACKLIST_DRIVE : IDS_BLACKLIST_DRIVE));
}
}
}
break;
case IDC_MANUALCONNECT:
{
char titleStr[32] = {0};
if(MessageBoxA(hwndDlg, WASABI_API_LNGSTRING(IDS_MANUAL_CONNECT_PROMPT),
WASABI_API_LNGSTRING_BUF(IDS_WARNING,titleStr,32), MB_YESNO) == IDYES)
{
int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
if(drive >= L'A' && drive <= L'Z') {
wchar_t *bl = makeBlacklistString(drive);
if (bl)
{
for(size_t i=0; i<blacklist.size(); i++)
{
if(!wcscmp(bl,(wchar_t*)blacklist.at(i)))
{
free(blacklist.at(i));
blacklist.erase(blacklist.begin() + i);
break;
}
}
free(bl);
}
connectDrive(drive,false);
// should do a better check here incase of failure, etc
EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALCONNECT), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_MANUALDISCONNECT), TRUE);
}
}
}
break;
case IDC_MANUALDISCONNECT:
{
int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
if(drive >= L'A' && drive <= L'Z')
{
for(size_t i=0; i < devices.size(); i++)
{
AndroidDevice * d = (AndroidDevice*)devices.at(i);
if(d->drive == drive)
{
devices.erase(devices.begin() + i);
if(config) SendMessage(config,WM_USER,0,0); //refresh fields
if(config) SendMessage(config,WM_COMMAND, MAKEWPARAM(IDC_DRIVESELECT,CBN_SELCHANGE),0); //update to correct device change as if the user had clicked on the combo box themself
SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)d,PMP_IPC_DEVICEDISCONNECTED);
SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
delete d;
i--;
}
}
}
}
break;
case IDC_MANUALBLACKLIST:
{
int indx = (int)SendDlgItemMessageW(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETCURSEL,0,0);
wchar_t drive = (wchar_t)SendDlgItemMessage(hwndDlg,IDC_COMBO_MANUALCONNECT,CB_GETITEMDATA,indx,0);
if(drive >= L'A' && drive <= L'Z') {
wchar_t *bl = makeBlacklistString(drive);
if (bl)
{
if(!blacklistCheck(drive)) {
blacklist.push_back(bl);
// see if we've got a connected drive and prompt to remove it or wait till restart
if(IsDriveConnectedToPMP(drive)) {
wchar_t title[96] = {0};
GetWindowText(hwndDlg, title, 96);
if(MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DRIVE_CONNECTED_DISCONNECT_Q),title,MB_YESNO)==IDYES){
SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_MANUALDISCONNECT,0),0);
}
}
}
else
{
for(size_t i=0; i < blacklist.size(); i++)
{
if(!wcscmp(bl,(wchar_t*)blacklist.at(i)))
{
free(blacklist.at(i));
blacklist.erase(blacklist.begin() + i);
break;
}
}
free(bl);
}
}
SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_COMBO_MANUALCONNECT,CBN_SELCHANGE),0);
}
}
break;
case IDOK:
case IDCANCEL:
blacklistSave();
EndDialog(hwndDlg,0);
break;
}
break;
}
return 0;
}
static intptr_t MessageProc(int msg, intptr_t param1, intptr_t param2, intptr_t param3)
{
switch(msg) {
case PMP_DEVICECHANGE:
return wmDeviceChange(param1,param2);
case PMP_CONFIG:
WASABI_API_DIALOGBOXW(IDD_CONFIG_GLOBAL,(HWND)param1,config_dialogProc);
return 1;
}
return 0;
}
extern "C" __declspec(dllexport) PMPDevicePlugin *winampGetPMPDevicePlugin()
{
return &plugin;
}

View file

@ -0,0 +1,209 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#include ""version.rc2""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// PNG
//
IDB_ANDROID_160 PNG "resources\\generic_android.png"
IDR_ANDROID_ICON PNG "resources\\androidIcon.png"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_CONFIG DIALOGEX 0, 0, 264, 226
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "File Name Format",IDC_STATIC,7,10,56,8
EDITTEXT IDC_NAMEFORMAT,80,7,127,14,ES_AUTOHSCROLL
PUSHBUTTON "Format Help",IDC_FILENAMEHELP,211,7,46,14
LTEXT "Playlist Directory",IDC_STATIC,7,26,54,8
EDITTEXT IDC_PLDIR,80,24,128,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse...",IDC_PLBROWSE,211,23,46,14
LTEXT "Supported Formats",IDC_STATIC,7,42,62,8
EDITTEXT IDC_SUPPORTEDFORMATS,80,40,128,14,ES_AUTOHSCROLL
PUSHBUTTON "Syntax Help",IDC_FORMATSHELP,211,40,46,14
LTEXT "Delete Empty Folders",IDC_STATIC,7,55,69,8
CONTROL "",IDC_PURGEFOLDERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,56,8,8
PUSHBUTTON "Save and Rescan",IDC_RESCAN,7,71,66,14
PUSHBUTTON "Refresh Cache",IDC_REFRESHCACHE,79,71,66,14
GROUPBOX "Playlist Writing Options",IDC_STATIC,7,95,250,49
COMBOBOX IDC_PL_WRITE_COMBO,12,108,120,35,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Changing how Winamp saves its playlists may improve compatability with other portable devices.",IDC_STATIC,137,104,113,34
LTEXT "",IDC_PL_WRITE_EG,12,126,120,10
END
IDD_CONFIG_GLOBAL DIALOGEX 0, 0, 196, 90
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Android Device Support Configuration"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Select the Drive to use from the available list below",IDC_STATIC,5,3,186,67
COMBOBOX IDC_COMBO_MANUALCONNECT,31,17,40,242,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Connect Drive",IDC_MANUALCONNECT,75,17,90,13
PUSHBUTTON "Disconnect Drive",IDC_MANUALDISCONNECT,75,34,90,13
PUSHBUTTON "Blacklist Drive",IDC_MANUALBLACKLIST,75,51,90,13
DEFPUSHBUTTON "Close",IDOK,75,73,45,13
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_CONFIG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 257
TOPMARGIN, 7
BOTTOMMARGIN, 218
END
IDD_CONFIG_GLOBAL, DIALOG
BEGIN
LEFTMARGIN, 5
RIGHTMARGIN, 191
TOPMARGIN, 3
BOTTOMMARGIN, 86
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_NULLSOFT_ANDROID_DEVICE_PLUGIN "Nullsoft Android Device Plug-in v%s"
65535 "{EBFF6E00-39D8-45e6-B3EC-E3B07A45E6B0}"
END
STRINGTABLE
BEGIN
IDS_CANNOT_OPEN_FILE "Cannot open file"
IDS_CANNOT_CREATE_FILE "Cannot create file"
IDS_TRANSFERING_PERCENT "Transferring %d%%"
IDS_CANCELLED "Cancelled"
IDS_DONE "Done"
IDS_TRANSFER_FAILED "Transfer failed"
IDS_REMOVEABLE_DRIVE_DETECTED
"Winamp has detected an Android device on %c:.\nIs this a device that you want to manage with Winamp?"
IDS_WINAMP_PMP_SUPPORT "Winamp Portable Music Player Support"
IDS_MANUAL_CONNECT_PROMPT
"Manually connecting the wrong device could cause problems.\nPlease be sure that you have entered a valid Android device letter.\n\nAre you sure you wish to continue?"
IDS_WARNING "Warning"
IDS_LOADING_DRIVE_X "Loading Drive X:"
IDS_FAILED_TO_EJECT_DRIVE
"Failed to eject device. Is something else using it?"
IDS_ERROR "Error"
IDS_ANDROID_DRIVE_X "ANDROID Drive X:"
IDS_TRACK_IN_USE "Track is in use - Could not delete!"
END
STRINGTABLE
BEGIN
IDS_CACHE_UPDATED "Cache updated."
IDS_SUCCESS "Success"
IDS_FILENAME_FORMATTING_INFO
"You may enter a filename format string for your files.\nIt can contain \\ or / to delimit a path, and the following keywords:\n\n <Artist> - inserts the artist with the default capitalization\n <ARTIST> - inserts the artist in all uppercase\n <artist> - inserts the artist in all lowercase\n <Albumartist>/<ALBUMARTIST>/<albumartist> - inserts the album artist\n <Album>/<ALBUM>/<album> - inserts the album\n <year> - inserts the album year\n <Genre>/<GENRE>/<genre> - inserts the album genre\n <Title>/<TITLE>/<title> - inserts the track title\n <filename> - inserts the original filename (extension safe)\n <disc> - inserts the disc number\n #, ##, or ### - inserts the track number, with leading 0s if ## or ###\n\n For Example: E:\\Music\\<Artist>\\<Album>\\## - <Title>\n"
IDS_FILENAME_FORMAT_HELP "Filename Format Help"
IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS
"Please select a folder to load playlists from the device."
IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE
"Error: selected path is not on device!"
IDS_SUPPORTED_FORMAT_INFO
"You may enter supported extensions in the form of\nextensions separated by semicolons.\n\nFor Example: mp3;wav;wma"
IDS_SUPPORTED_FORMAT_HELP "Supported Formats Help"
IDS_RESCAN_COMPLETE_SAVED "Rescan complete, device settings saved."
IDS_RESCAN_COMPLETE "Rescan complete"
IDS_ADVANCED "Advanced"
IDS_UNBLACKLIST_DRIVE "Un-blacklist Drive"
IDS_BLACKLIST_DRIVE "Blacklist Drive"
IDS_DRIVE_CONNECTED_DISCONNECT_Q
"The Drive you have selected to blacklist is currently connected and being managed.\n\nWould you like to disconnect the Drive now or you can wait until you restart Winamp."
IDS_SLASH_AT_START "Slash at start of paths (default)"
IDS_DOT_AT_START "Dot at start of paths"
END
STRINGTABLE
BEGIN
IDS_NO_SLASH_OR_DOT "No slash or dot at start"
IDS_EG_SLASH "e.g. \\path\\to\\file.mp3"
IDS_EG_DOT "e.g. .\\path\\to\\file.mp3"
IDS_EG_NEITHER "e.g. path\\to\\file.mp3"
IDS_DELAYLOAD_FAILURE "Android plug-in cannot load the database to write the cache file"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#include "version.rc2"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,130 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29509.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pmp_android", "pmp_android.vcxproj", "{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}"
ProjectSection(ProjectDependencies) = postProject
{57C90706-B25D-4ACA-9B33-95CDB2427C27} = {57C90706-B25D-4ACA-9B33-95CDB2427C27}
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
{4D25C321-7F8B-424E-9899-D80A364BAF1A} = {4D25C321-7F8B-424E-9899-D80A364BAF1A}
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1} = {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
{E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
{255B68B5-7EF8-45EF-A675-2D6B88147909} = {255B68B5-7EF8-45EF-A675-2D6B88147909}
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "..\tataki\tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
ProjectSection(ProjectDependencies) = postProject
{DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nde", "..\nde\nde.vcxproj", "{4D25C321-7F8B-424E-9899-D80A364BAF1A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
ProjectSection(ProjectDependencies) = postProject
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
ProjectSection(ProjectDependencies) = postProject
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|Win32.ActiveCfg = Debug|Win32
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|Win32.Build.0 = Debug|Win32
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|x64.ActiveCfg = Debug|x64
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Debug|x64.Build.0 = Debug|x64
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|Win32.ActiveCfg = Release|Win32
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|Win32.Build.0 = Release|Win32
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|x64.ActiveCfg = Release|x64
{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}.Release|x64.Build.0 = Release|x64
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
{255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
{DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.ActiveCfg = Debug|Win32
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.Build.0 = Debug|Win32
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.ActiveCfg = Debug|x64
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.Build.0 = Debug|x64
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.ActiveCfg = Release|Win32
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.Build.0 = Release|Win32
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.ActiveCfg = Release|x64
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.Build.0 = Release|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C4E799C1-027B-487B-8E1A-31F2D26A1AFE}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,332 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{491665B2-6437-4D30-9AEC-DE7D1CB20E1E}</ProjectGuid>
<RootNamespace>pmp_android</RootNamespace>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>false</VcpkgEnableManifest>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
<VcpkgConfiguration>Debug</VcpkgConfiguration>
</PropertyGroup>
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<VcpkgInstalledDir>
</VcpkgInstalledDir>
<VcpkgUseStatic>false</VcpkgUseStatic>
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;shlwapi.lib;fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalIncludeDirectories)</AdditionalLibraryDirectories>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN64;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<Optimization>MinSpace</Optimization>
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_WINDOWS;_UNICODE;UNICODE;_USRDLL;ML_ex_EXPORTS;_CRT_SECURE_NO_WARNINGS;WIN64;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck>
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
<AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
<ObjectFileName>$(IntDir)</ObjectFileName>
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>None</DebugInformationFormat>
<DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040c</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<GenerateDebugInformation>false</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
<PostBuildEvent>
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
<ClCompile Include="albumart.cpp" />
<ClCompile Include="androiddevice.cpp" />
<ClCompile Include="androidplaylist.cpp" />
<ClCompile Include="androidplaylistsaver.cpp" />
<ClCompile Include="api.cpp" />
<ClCompile Include="deviceprovider.cpp" />
<ClCompile Include="eject.cpp" />
<ClCompile Include="filecopy.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="utils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\General\gen_ml\ml.h" />
<ClInclude Include="..\..\Library\ml_pmp\pmp.h" />
<ClInclude Include="androiddevice.h" />
<ClInclude Include="androidplaylist.h" />
<ClInclude Include="androidplaylistsaver.h" />
<ClInclude Include="api.h" />
<ClInclude Include="deviceprovider.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<Image Include="resources\androidIcon.png" />
<Image Include="resources\generic_android.png" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="pmp_android.rc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\nde\nde.vcxproj">
<Project>{4d25c321-7f8b-424e-9899-d80a364baf1a}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\replicant\nu\nu.vcxproj">
<Project>{f1f5cd60-0d5b-4cea-9eeb-2f87ff9aa915}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\tataki\tataki.vcxproj">
<Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\WAT\WAT.vcxproj">
<Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="albumart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="androiddevice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="androidplaylist.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="androidplaylistsaver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="api.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="deviceprovider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="eject.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="filecopy.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="androiddevice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="androidplaylist.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="androidplaylistsaver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="api.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="deviceprovider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\General\gen_ml\ml.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\Library\ml_pmp\pmp.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resources\generic_android.png">
<Filter>Image Files</Filter>
</Image>
<Image Include="resources\androidIcon.png">
<Filter>Image Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{82d6647a-a3b9-4ade-b2cc-4a360f5ed80d}</UniqueIdentifier>
</Filter>
<Filter Include="Ressource Files">
<UniqueIdentifier>{8731ac77-4c42-42fc-8ff8-f64922843c99}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{06318ce7-b270-4a39-833a-4ab306c760ed}</UniqueIdentifier>
</Filter>
<Filter Include="Image Files">
<UniqueIdentifier>{d2febc64-2e0e-4a50-8994-0dcaab423352}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="pmp_android.rc">
<Filter>Ressource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View file

@ -0,0 +1,75 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by pmp_android.rc
//
#define IDS_CANNOT_OPEN_FILE 1
#define IDS_CANNOT_CREATE_FILE 2
#define IDS_TRANSFERING_PERCENT 3
#define IDS_CANCELLED 4
#define IDS_DONE 5
#define IDS_TRANSFER_FAILED 6
#define IDS_REMOVEABLE_DRIVE_DETECTED 7
#define IDS_WINAMP_PMP_SUPPORT 8
#define IDS_MANUAL_CONNECT_PROMPT 9
#define IDS_WARNING 10
#define IDS_LOADING_DRIVE_X 11
#define IDS_FAILED_TO_EJECT_DRIVE 12
#define IDS_ERROR 13
#define IDS_STRING14 14
#define IDS_ANDROID_DRIVE_X 14
#define IDS_TRACK_IN_USE 15
#define IDS_CACHE_UPDATED 16
#define IDS_SUCCESS 17
#define IDS_FILENAME_FORMATTING_INFO 18
#define IDS_FILENAME_FORMAT_HELP 19
#define IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS 20
#define IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE 21
#define IDS_SUPPORTED_FORMAT_INFO 22
#define IDS_SUPPORTED_FORMAT_HELP 23
#define IDS_RESCAN_COMPLETE_SAVED 24
#define IDS_RESCAN_COMPLETE 25
#define IDS_ADVANCED 26
#define IDS_UNBLACKLIST_DRIVE 27
#define IDS_BLACKLIST_DRIVE 28
#define IDS_DRIVE_CONNECTED_DISCONNECT_Q 29
#define IDS_SLASH_AT_START 30
#define IDS_DOT_AT_START 31
#define IDS_NO_SLASH_OR_DOT 32
#define IDS_EG_SLASH 33
#define IDS_EG_DOT 34
#define IDS_STRING35 35
#define IDS_EG_NEITHER 35
#define IDS_DELAYLOAD_FAILURE 36
#define IDD_CONFIG 102
#define IDD_CONFIG_GLOBAL 105
#define IDB_ANDROID_160 110
#define IDB_PNG1 111
#define IDR_ANDROID_ICON 111
#define IDC_PLDIR 1001
#define IDC_NAMEFORMAT 1002
#define IDC_SUPPORTEDFORMATS 1003
#define IDC_DRIVESELECT 1004
#define IDC_COMBO_MANUALCONNECT 1005
#define IDC_MANUALCONNECT 1006
#define IDC_MANUALDISCONNECT 1007
#define IDC_MANUALBLACKLIST 1008
#define IDC_REFRESHCACHE 1011
#define IDC_FILENAMEHELP 1012
#define IDC_PLBROWSE 1013
#define IDC_FORMATSHELP 1014
#define IDC_RESCAN 1015
#define IDC_PURGEFOLDERS 1016
#define IDC_PL_WRITE_COMBO 1017
#define IDC_PL_WRITE_EG 1018
#define IDS_NULLSOFT_ANDROID_DEVICE_PLUGIN 65534
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 113
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1019
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -0,0 +1,334 @@
#include <windows.h>
#include "../../General/gen_ml/ml.h"
#include "../../Library/ml_pmp/pmp.h"
#include "AndroidDevice.h"
#include <strsafe.h>
#include <shlwapi.h>
BOOL RecursiveCreateDirectory(wchar_t* buf1);
__int64 fileSize(wchar_t * filename);
bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
DeviceType detectDeviceType(wchar_t drive);
void removebadchars(wchar_t *s);
wchar_t * FixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
void removebadchars(wchar_t *s) {
while (s && *s)
{
if (*s == L'?' || *s == L'/' || *s == L'\\' || *s == L':' || *s == L'*' || *s == L'\"' || *s == L'<' || *s == L'>' || *s == L'|')
*s = L'_';
s = CharNextW(s);
}
}
__int64 fileSize(wchar_t * filename)
{
WIN32_FIND_DATA f={0};
HANDLE h = FindFirstFileW(filename,&f);
if(h == INVALID_HANDLE_VALUE) return -1;
FindClose(h);
ULARGE_INTEGER i;
i.HighPart = f.nFileSizeHigh;
i.LowPart = f.nFileSizeLow;
return i.QuadPart;
}
// RecursiveCreateDirectory: creates all non-existent folders in a path
BOOL RecursiveCreateDirectory(wchar_t* buf1) {
wchar_t *p=buf1;
int errors = 0;
if (*p) {
p = PathSkipRoot(buf1);
if (!p) return true ;
wchar_t ch='c';
while (ch) {
while (p && *p != '\\' && *p) p = CharNext(p);
ch = (p ? *p : 0);
if (p) *p = 0;
int pp = (int)wcslen(buf1)-1;
while(buf1[pp] == '.' || buf1[pp] == ' ' ||
(buf1[pp] == '\\' && (buf1[pp-1] == '.' || buf1[pp-1] == ' ' || buf1[pp-1] == '/')) ||
buf1[pp] == '/' && buf1)
{
if(buf1[pp] == '\\')
{
buf1[pp-1] = '_';
pp -= 2;
} else {
buf1[pp] = '_';
pp--;
}
}
WIN32_FIND_DATA fd = {0};
// Avoid a "There is no disk in the drive" error box on empty removable drives
UINT prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
HANDLE h = FindFirstFile(buf1,&fd);
SetErrorMode(prevErrorMode);
if (h == INVALID_HANDLE_VALUE)
{
if (!CreateDirectory(buf1,NULL)) errors++;
} else {
FindClose(h);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) errors++;
}
if (p) *p++ = ch;
}
}
return errors != 0;
}
bool supportedFormat(wchar_t * file, wchar_t * supportedFormats) {
wchar_t * ext = wcsrchr(file,'.');
if(!ext) return false;
ext++;
wchar_t * p = supportedFormats;
while(p && *p) {
bool ret=false;
wchar_t * np = wcschr(p,L';');
if(np) *np = 0;
if(!_wcsicmp(ext,p)) ret=true;
if(np) { *np = L';'; p=np+1; }
else return ret;
if(ret) return true;
}
return false;
}
// FixReplacementVars: replaces <Artist>, <Title>, <Album>, and #, ##, ##, with appropriate data
// DOES NOT add a file extention!!
wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song)
{
#define ADD_STR(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) outp++; }
#define ADD_STR_U(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towupper(*outp); outp++; } }
#define ADD_STR_L(x) { x(song,outp,str_size-1-(outp-str)); removebadchars(outp); while (outp && *outp) { *outp=towlower(*outp); outp++; } }
wchar_t tmpsrc[4096] = {0};
lstrcpyn(tmpsrc,str,sizeof(tmpsrc)/sizeof(wchar_t)); //lstrcpyn is nice enough to make sure it's null terminated.
wchar_t *inp = tmpsrc;
wchar_t *outp = str;
int slash = 0;
while (inp && *inp && outp-str < str_size-2)
{
if (*inp == L'<')
{
if (!wcsncmp(inp,L"<TITLE>",7))
{
ADD_STR_U(dev->getTrackTitle);
inp+=7;
}
else if (!wcsncmp(inp,L"<title>",7))
{
ADD_STR_L(dev->getTrackTitle);
inp+=7;
}
else if (!_wcsnicmp(inp,L"<Title>",7))
{
ADD_STR(dev->getTrackTitle);
inp+=7;
}
else if (!wcsncmp(inp,L"<ALBUM>",7))
{
ADD_STR_U(dev->getTrackAlbum);
inp+=7;
}
else if (!wcsncmp(inp,L"<album>",7))
{
ADD_STR_L(dev->getTrackAlbum);
inp+=7;
}
else if (!_wcsnicmp(inp,L"<Album>",7))
{
ADD_STR(dev->getTrackAlbum);
inp+=7;
}
else if (!wcsncmp(inp,L"<GENRE>",7))
{
ADD_STR_U(dev->getTrackGenre);
inp+=7;
}
else if (!wcsncmp(inp,L"<genre>",7))
{
ADD_STR_L(dev->getTrackGenre);
inp+=7;
}
else if (!_wcsnicmp(inp,L"<Genre>",7))
{
ADD_STR(dev->getTrackGenre);
inp+=7;
}
else if (!wcsncmp(inp,L"<ARTIST>",8))
{
ADD_STR_U(dev->getTrackArtist);
inp+=8;
}
else if (!wcsncmp(inp,L"<artist>",8))
{
ADD_STR_L(dev->getTrackArtist);
inp+=8;
}
else if (!_wcsnicmp(inp,L"<Artist>",8))
{
ADD_STR(dev->getTrackArtist);
inp+=8;
}
else if (!wcsncmp(inp,L"<ALBUMARTIST>",13))
{
wchar_t temp[128] = {0};
dev->getTrackAlbumArtist(song, temp, 128);
if (temp[0] == 0)
dev->getTrackArtist(song, temp, 128);
lstrcpyn(outp,temp,str_size-1-(outp-str));
removebadchars(outp);
while (outp && *outp) { *outp=towupper(*outp); outp++; }
inp+=13;
}
else if (!wcsncmp(inp,L"<albumartist>",13))
{
wchar_t temp[128] = {0};
dev->getTrackAlbumArtist(song, temp, 128);
if (temp[0] == 0)
dev->getTrackArtist(song, temp, 128);
lstrcpyn(outp,temp,str_size-1-(outp-str));
removebadchars(outp);
while (outp && *outp) { *outp=towlower(*outp); outp++; }
inp+=13;
}
else if (!_wcsnicmp(inp,L"<Albumartist>",13))
{
wchar_t temp[128] = {0};
dev->getTrackAlbumArtist(song, temp, 128);
if (temp[0] == 0)
dev->getTrackArtist(song, temp, 128);
lstrcpyn(outp,temp, (int)str_size-1-(outp-str));
removebadchars(outp);
while (outp && *outp) outp++;
inp+=13;
}
else if (!_wcsnicmp(inp,L"<year>",6))
{
wchar_t year[64] = {0};
int y = dev->getTrackYear(song);
if (y) StringCchPrintf(year, ARRAYSIZE(year), L"%d", y);
lstrcpyn(outp,year, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
inp+=6;
}
else if (!_wcsnicmp(inp,L"<disc>",6))
{
wchar_t disc[16] = {0};
int d = dev->getTrackDiscNum(song);
if (d) StringCchPrintf(disc, ARRAYSIZE(disc), L"%d", d);
lstrcpyn(outp,disc, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
inp+=6;
}
else if (!_wcsnicmp(inp,L"<filename>",10))
{
wchar_t tfn[MAX_PATH], *ext, *fn;
StringCchCopy(tfn,MAX_PATH,((AndroidSong*)song)->filename);
ext = wcsrchr(tfn, L'.');
*ext = 0; //kill extension since its added later
fn = wcsrchr(tfn, L'\\');
fn++;
lstrcpyn(outp,fn, (int)str_size-1-(outp-str));
while (outp && *outp) outp++;
inp+=10;
}
else
{
// use this to skip over unknown tags
while (inp && *inp && *inp != L'>') inp++;
if (inp) inp++;
}
}
else if (*inp == L'#')
{
int nd=0;
wchar_t tmp[64] = {0};
while (inp && *inp == L'#') nd++,inp++;
int track = dev->getTrackTrackNum(song);
if (!track)
{
while (inp && *inp == L' ') inp++;
while (inp && *inp == L'\\') inp++;
if (inp && (*inp == L'-' || *inp == L'.' || *inp == L'_')) // separator
{
inp++;
while (inp && *inp == L' ') inp++;
}
}
else
{
if (nd > 1)
{
wchar_t tmp2[32] = {0};
if (nd > 5) nd=5;
StringCchPrintf(tmp2, ARRAYSIZE(tmp2), L"%%%02dd",nd);
StringCchPrintf(tmp, ARRAYSIZE(tmp), tmp2,track);
}
else StringCchPrintf(tmp, ARRAYSIZE(tmp), L"%d",track);
}
lstrcpyn(outp,tmp, (int)str_size-1-(outp-str)); while (outp && *outp) outp++;
}
else
{
if (*inp == L'\\') slash += 1;
*outp++=*inp++;
}
}
if (outp) *outp = 0;
// if we end up with something like U:\\\ then this
// will set it to be just <filename> so it'll not
// end up making a load of bad files e.g. U:\.mp3
int out_len = lstrlen(str);
if (out_len)
{
if (out_len - 2 == slash)
{
outp = str + 3;
wchar_t tfn[MAX_PATH], *ext, *fn;
StringCchCopy(tfn,MAX_PATH,((AndroidSong*)song)->filename);
ext = wcsrchr(tfn, L'.');
*ext = 0; //kill extension since its added later
fn = wcsrchr(tfn, L'\\');
fn++;
lstrcpyn(outp,fn, (int)str_size-1-(outp-str));
while (outp && *outp) outp++;
if (outp) *outp = 0;
}
}
inp=str;
outp=str;
wchar_t lastc=0;
while (inp && *inp)
{
wchar_t ch=*inp++;
if (ch == L'\t') ch=L' ';
if (ch == L' ' && (lastc == L' ' || lastc == L'\\' || lastc == L'/')) continue; // ignore space after slash, or another space
if ((ch == L'\\' || ch == L'/') && lastc == L' ') outp--; // if we have a space then slash, back up to write the slash where the space was
*outp++=ch;
lastc=ch;
}
if (outp) *outp=0;
#undef ADD_STR
#undef ADD_STR_L
#undef ADD_STR_U
return str;
}

View file

@ -0,0 +1,39 @@
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
#include "../../../Winamp/buildType.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,72,0,0
PRODUCTVERSION WINAMP_PRODUCTVER
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Winamp SA"
VALUE "FileDescription", "Winamp Portable Device Plug-in"
VALUE "FileVersion", "1,72,0,0"
VALUE "InternalName", "Nullsoft Android Device"
VALUE "LegalCopyright", "Copyright © 2010-2023 Winamp SA"
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
VALUE "OriginalFilename", "pmp_android.dll"
VALUE "ProductName", "Winamp"
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END