P4SDevice.cpp 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185
  1. #include "P4SDevice.h"
  2. #include <time.h>
  3. #include "msWMDM_i.c"
  4. #include "../nu/AutoWide.h"
  5. #include "../nu/AutoChar.h"
  6. #include "../WAT/wa_logger.h"
  7. #include "MyProgress.h"
  8. #include "WMDRMDeviceApp_i.c"
  9. extern C_ItemList devices;
  10. extern HANDLE killEvent;
  11. extern CRITICAL_SECTION csTransfers;
  12. #define plext L"pla"
  13. BOOL FormatResProtocol(const wchar_t *resourceName, const wchar_t *resourceType, wchar_t *buffer, size_t bufferMax);
  14. static BYTE* GetMetadataItem(IWMDMStorage4 * store, const WCHAR * name);
  15. static IWMDMStorage4* GetOrCreateFolder(IWMDMStorage4 * store, wchar_t * name, P4SDevice * dev=NULL, bool album=false, const itemRecordW * item=NULL);
  16. // from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmdm/htm/wmdm_format_capability.asp
  17. void FreeFormatCapability(WMDM_FORMAT_CAPABILITY formatCap)
  18. {
  19. // Loop through all configurations.
  20. for (UINT i=0; i < formatCap.nPropConfig; i++)
  21. {
  22. // Loop through all descriptions of a configuration and delete
  23. // the values particular to that description type.
  24. for (UINT j=0; j < formatCap.pConfigs[i].nPropDesc; j++)
  25. {
  26. switch (formatCap.pConfigs[i].pPropDesc[j].ValidValuesForm)
  27. {
  28. case WMDM_ENUM_PROP_VALID_VALUES_ENUM:
  29. for (UINT k=0; k < formatCap.pConfigs[i].pPropDesc[j].ValidValues.EnumeratedValidValues.cEnumValues; k++)
  30. {
  31. PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.EnumeratedValidValues.pValues[k]));
  32. }
  33. CoTaskMemFree(formatCap.pConfigs[i].pPropDesc[j].ValidValues.EnumeratedValidValues.pValues);
  34. break;
  35. case WMDM_ENUM_PROP_VALID_VALUES_RANGE:
  36. PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.ValidValuesRange.rangeMin));
  37. PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.ValidValuesRange.rangeMax));
  38. PropVariantClear (&(formatCap.pConfigs[i].pPropDesc[j].ValidValues.ValidValuesRange.rangeStep));
  39. break;
  40. case WMDM_ENUM_PROP_VALID_VALUES_ANY:
  41. // No dynamically allocated memory for this value.
  42. default:
  43. break;
  44. }
  45. // Free the memory for the description name.
  46. CoTaskMemFree(formatCap.pConfigs[i].pPropDesc[j].pwszPropName);
  47. }
  48. // Free the memory holding the array of description items for this configuration.
  49. CoTaskMemFree(formatCap.pConfigs[i].pPropDesc);
  50. }
  51. // Free the memory pointing to the array of configurations.
  52. CoTaskMemFree(formatCap.pConfigs);
  53. formatCap.nPropConfig = 0;
  54. }
  55. static HRESULT GetFormatCaps(WMDM_FORMATCODE formatCode, IWMDMDevice3* pDevice)
  56. {
  57. // Get a list of supported configurations for the format.
  58. WMDM_FORMAT_CAPABILITY formatCapList;
  59. HRESULT hr = pDevice->GetFormatCapability(formatCode, &formatCapList);
  60. if (FAILED(hr)) return E_FAIL;
  61. if (formatCapList.nPropConfig == 0)
  62. {
  63. FreeFormatCapability(formatCapList);
  64. return E_FAIL; // operation succeeded, but format not supported.
  65. }
  66. // TODO: Display the format name.
  67. // Loop through the configurations and examine each one.
  68. for (UINT iConfig = 0; iConfig < formatCapList.nPropConfig; iConfig++)
  69. {
  70. WMDM_PROP_CONFIG formatConfig = formatCapList.pConfigs[iConfig];
  71. // Preference level for this configuration (lower number means more preferred).
  72. // TODO: Display the preference level for this format configuration.
  73. // Loop through all properties for this configuration and get supported
  74. // values for the property. Values can be a single value, a range,
  75. // or a list of enumerated values.
  76. for (UINT iDesc = 0; iDesc < formatConfig.nPropDesc; iDesc++)
  77. {
  78. WMDM_PROP_DESC propDesc = formatConfig.pPropDesc[iDesc];
  79. // TODO: Display the property name.
  80. // Three ways a value can be represented: any, a range, or a list.
  81. switch (propDesc.ValidValuesForm)
  82. {
  83. case WMDM_ENUM_PROP_VALID_VALUES_ANY:
  84. // TODO: Display a message indicating that all values are valid.
  85. break;
  86. case WMDM_ENUM_PROP_VALID_VALUES_RANGE:
  87. {
  88. // List these in the docs as the propvariants set.
  89. WMDM_PROP_VALUES_RANGE rng =
  90. propDesc.ValidValues.ValidValuesRange;
  91. // TODO: Display the min, max, and step values.
  92. }
  93. break;
  94. case WMDM_ENUM_PROP_VALID_VALUES_ENUM:
  95. {
  96. // TODO: Display a banner for the list of valid values.
  97. /*
  98. WMDM_PROP_VALUES_ENUM list = propDesc.ValidValues.EnumeratedValidValues;
  99. PROPVARIANT pVal;
  100. for (UINT iValue = 0; iValue < list.cEnumValues; iValue++)
  101. {
  102. pVal = list.pValues[iValue];
  103. // TODO: Display each valid value.
  104. PropVariantClear(&pVal);
  105. PropVariantInit(&pVal);
  106. }*/
  107. }
  108. break;
  109. default:
  110. FreeFormatCapability(formatCapList);
  111. return E_FAIL;
  112. //break;
  113. }
  114. }
  115. }
  116. // Now clear the memory used by WMDM_FORMAT_CAPABILITY.
  117. FreeFormatCapability(formatCapList);
  118. return hr;
  119. }
  120. static __time64_t wmdmDateTimeToUnixTime(_WMDMDATETIME * t) {
  121. tm m={0};
  122. m.tm_hour = t->wHour;
  123. m.tm_min = t->wMinute;
  124. m.tm_sec = t->wSecond;
  125. m.tm_mday = t->wDay;
  126. m.tm_mon = t->wMonth;
  127. m.tm_year = t->wYear;
  128. return _mktime64(&m);
  129. }
  130. HRESULT getMetadata(IWMDMStorage4 *store2,IWMDMMetaData ** meta, bool noMetadata) {
  131. const wchar_t ** propnames = (const wchar_t**)calloc(15,sizeof(void*));
  132. propnames[0] = g_wszWMDMFormatCode;
  133. propnames[1] = g_wszWMDMTitle;
  134. propnames[2] = g_wszWMDMAuthor;
  135. propnames[3] = g_wszWMDMAlbumTitle;
  136. propnames[4] = g_wszWMDMGenre;
  137. propnames[5] = g_wszWMDMTrack;
  138. propnames[6] = g_wszWMDMYear;
  139. propnames[7] = g_wszWMDMFileSize;
  140. propnames[8] = g_wszWMDMDuration;
  141. propnames[9] = g_wszWMDMPlayCount;
  142. propnames[10] = g_wszWMDMUserRating;
  143. propnames[11] = g_wszWMDMUserLastPlayTime;
  144. propnames[12] = g_wszWMDMLastModifiedDate;
  145. propnames[13] = g_wszWMDMAlbumArtist;
  146. propnames[14] = g_wszWMDMComposer;
  147. HRESULT h;
  148. if(noMetadata) {
  149. h = store2->GetSpecifiedMetadata(1,(LPCWSTR*)propnames,meta);
  150. if(h == WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED) h = S_OK;
  151. if(h != S_OK) { // ugh. Guess that this is an AAC/M4A. Dirty workaround hack!
  152. if (SUCCEEDED(store2->CreateEmptyMetadataObject(meta))) {
  153. h = S_OK;
  154. DWORD type = WMDM_FORMATCODE_UNDEFINEDAUDIO;
  155. (*meta)->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&type,sizeof(type));
  156. }
  157. }
  158. } else {
  159. h = store2->GetSpecifiedMetadata(13,(LPCWSTR*)propnames,meta);
  160. if(h == WMDM_S_NOT_ALL_PROPERTIES_RETRIEVED) h = S_OK;
  161. }
  162. free(propnames);
  163. return h;
  164. }
  165. void P4SDevice::foundSong(IWMDMStorage4 * store, IWMDMMetaData * meta,bool video,int pl,wchar_t * artist, wchar_t * album, IWMDMStorage4 * alb, IWMDMMetaData * albmeta) {
  166. Playlist * pls = (Playlist *)playlists.Get(pl);
  167. Song * song = new Song;
  168. song->video = video;
  169. song->meta = meta;
  170. song->modified = false;
  171. song->storage = store;
  172. song->artist = artist;
  173. song->album = album;
  174. if(alb && albmeta) {
  175. song->alb = alb;
  176. song->albmeta = albmeta;
  177. alb->AddRef();
  178. albmeta->AddRef();
  179. }
  180. if(song->artist) song->artist = _wcsdup(song->artist);
  181. if(song->album) song->album = _wcsdup(song->album);
  182. pls->songs.Add(song);
  183. store->AddRef();
  184. meta->AddRef();
  185. if(noMetadata || video) {
  186. wchar_t buf[2048]=L"";
  187. getTrackAlbum((songid_t)song,buf,2048);
  188. if(video) meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)L"~",4);
  189. else {
  190. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)buf,wcslen(buf)*2 + 2);
  191. buf[0]=0;
  192. getTrackArtist((songid_t)song,buf,2048);
  193. }
  194. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)buf,wcslen(buf)*2 + 2);
  195. buf[0]=0;
  196. getTrackTitle((songid_t)song,buf,2048);
  197. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)buf,wcslen(buf)*2 + 2);
  198. int n = getTrackTrackNum((songid_t)song);
  199. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMTrack,(BYTE*)&n,sizeof(DWORD));
  200. __int64 s = (__int64)getTrackSize((songid_t)song);
  201. meta->AddItem(WMDM_TYPE_QWORD,g_wszWMDMFileSize,(BYTE*)&s,sizeof(__int64));
  202. }
  203. }
  204. void P4SDevice::foundPlaylist(IWMDMStorage4 * store, IWMDMMetaData * meta) {
  205. DWORD count = 0;
  206. IWMDMStorage ** stores;
  207. wchar_t buf[100] = {0};
  208. store->GetName(buf,100);
  209. //OutputDebugString(buf);
  210. if(store->GetReferences(&count,&stores) == S_OK) {
  211. if(count > 0) {
  212. Playlist * pl = new Playlist;
  213. StringCchCopy(pl->name, ARRAYSIZE(pl->name), buf);
  214. {wchar_t * ext = wcsrchr(pl->name,L'.'); if(ext) *ext=0;}
  215. pl->storage = store;
  216. pl->meta = meta;
  217. meta->AddRef();
  218. store->AddRef();
  219. playlists.Add(pl);
  220. int num = playlists.GetSize()-1;
  221. for(unsigned int i=0; i<count; i++) {
  222. IWMDMStorage4 * song=NULL;
  223. /*{
  224. wchar_t buf[100] = {0};
  225. stores[i]->GetName(buf,100);
  226. OutputDebugString(buf);
  227. }*/
  228. if(stores[i]->QueryInterface(&song) == S_OK) if(song) {
  229. /*
  230. Song * s = new Song;
  231. s->modified=false;
  232. s->storage=song;
  233. HRESULT h = getMetadata(song,&s->meta);
  234. if (SUCCEEDED(h)) pl->songs.Add(s);
  235. else delete s;
  236. */
  237. //pl->songs.Add(song);
  238. IWMDMMetaData * meta;
  239. if (SUCCEEDED(getMetadata(song,&meta,noMetadata))) {
  240. foundSong(song,meta,false,num); meta->Release();
  241. }
  242. song->Release();
  243. }
  244. stores[i]->Release();
  245. }
  246. } else {
  247. //OutputDebugString(L"ref count zero");
  248. }
  249. CoTaskMemFree(stores);
  250. } else {
  251. //OutputDebugString(L"can't get playlist refs");
  252. }
  253. }
  254. void P4SDevice::traverseStorage(IWMDMStorage * store, int level, wchar_t * artist, wchar_t * album) {
  255. if(!store) return;
  256. IWMDMStorage4 * store2=NULL;
  257. ULONG num;
  258. //OutputDebugStringA("1A");
  259. C_ItemList storages;
  260. {
  261. IWMDMEnumStorage * enstore=NULL;
  262. IWMDMStorage * storeold=NULL;
  263. HRESULT hr = store->EnumStorage(&enstore);
  264. while(SUCCEEDED(hr)) {
  265. if (WaitForSingleObject(killEvent,0) == WAIT_OBJECT_0)
  266. break;
  267. hr = enstore->Next(1,&storeold,&num);
  268. if(SUCCEEDED(hr) && storeold) {
  269. hr = storeold->QueryInterface(&store2);
  270. storeold->Release();
  271. if(SUCCEEDED(hr) && store2) {
  272. storages.Add(store2);
  273. }
  274. else break;
  275. }
  276. else break;
  277. }
  278. if(enstore) enstore->Release();
  279. }
  280. //OutputDebugStringA("2A");
  281. //while (SUCCEEDED(hr) && enstore) {
  282. IWMDMStorage4 * alb=NULL;
  283. IWMDMMetaData * albmeta=NULL;
  284. for(int i=0; i<storages.GetSize(); i++) {
  285. wchar_t buf[256]=L"";
  286. store2 = (IWMDMStorage4*)storages.Get(i);
  287. store2->GetName(buf,256);
  288. wchar_t *ext = wcsrchr(buf,L'.');
  289. if(ext && _wcsicmp(ext,L".alb")==0) {
  290. alb = store2;
  291. alb->AddRef();
  292. alb->GetMetadata(&albmeta);
  293. break;
  294. }
  295. }
  296. //albfiles.Add(new AlbFile(store2,meta));
  297. for(int i=0; i<storages.GetSize(); i++) {
  298. if (WaitForSingleObject(killEvent,0) == WAIT_OBJECT_0)
  299. break;
  300. //OutputDebugStringA("1");
  301. store2 = (IWMDMStorage4*)storages.Get(i);
  302. if(store2 == alb) continue;
  303. wchar_t buf[256]=L"";
  304. //OutputDebugStringA("2");
  305. store2->GetName(buf,256);
  306. if(playlistsDir == NULL && _wcsicmp(buf,L"My Playlists")==0) { playlistsDir = store2; store2->AddRef(); }
  307. if(playlistsDir == NULL && _wcsicmp(buf,L"Playlists")==0) { playlistsDir = store2; store2->AddRef(); }
  308. DWORD attribs=NULL;
  309. store2->GetAttributes(&attribs,NULL);
  310. //OutputDebugStringA("3");
  311. if(attribs & WMDM_FILE_ATTR_FOLDER) {
  312. if(level==0) artist=buf;
  313. else if(level==1) album=buf;
  314. //OutputDebugStringA("5");
  315. WMDM_STORAGE_ENUM_MODE mode = ENUM_MODE_RAW;
  316. store2->SetEnumPreference(&mode,0,NULL);
  317. traverseStorage(store2,level+1,artist,album);
  318. } else if(attribs & WMDM_FILE_ATTR_FILE || !attribs) {
  319. IWMDMMetaData * meta=NULL;
  320. //OutputDebugStringA("1");
  321. HRESULT h = getMetadata(store2,&meta,noMetadata);
  322. //OutputDebugStringA("2");
  323. //OutputDebugStringA("4");
  324. /*{
  325. wchar_t buf2[400] = {0};
  326. wsprintf(buf2,L"name: %s atr: 0x%x, hr: 0x%x %s",buf,attribs,h,h == E_INVALIDARG?L"POOT":L"");
  327. OutputDebugString(buf2);
  328. }*/
  329. if(meta && h == S_OK) {
  330. wchar_t * name=NULL;
  331. WMDM_TAG_DATATYPE type;
  332. BYTE * value=NULL;
  333. UINT valuelen;
  334. if(meta->QueryByName(g_wszWMDMFormatCode,&type,&value,&valuelen) == S_OK && type == WMDM_TYPE_DWORD)
  335. {
  336. switch(*(DWORD*)value) { // find out what it is...
  337. case WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST:
  338. case WMDM_FORMATCODE_WPLPLAYLIST:
  339. case WMDM_FORMATCODE_M3UPLAYLIST:
  340. case WMDM_FORMATCODE_MPLPLAYLIST:
  341. case WMDM_FORMATCODE_ASXPLAYLIST:
  342. case WMDM_FORMATCODE_PLSPLAYLIST:
  343. foundPlaylist(store2,meta);
  344. break;
  345. case WMDM_FORMATCODE_ASF:
  346. case WMDM_FORMATCODE_AVI:
  347. case WMDM_FORMATCODE_MPEG:
  348. case WMDM_FORMATCODE_WMV:
  349. case WMDM_FORMATCODE_MP2:
  350. case WMDM_FORMATCODE_3GP:
  351. case WMDM_FORMATCODE_UNDEFINEDVIDEO:
  352. foundSong(store2,meta,true);
  353. break;
  354. case WMDM_FORMATCODE_UNDEFINED:
  355. { //ugh. nokiahack.
  356. wchar_t * ext = wcsrchr(buf,'.');
  357. if(!ext) break;
  358. if(!_wcsicmp(ext,L".mp4") || !_wcsicmp(ext,L".m4a")) foundSong(store2,meta,false);
  359. }
  360. break;
  361. case WMDM_FORMATCODE_AIFF:
  362. case WMDM_FORMATCODE_WAVE:
  363. case WMDM_FORMATCODE_MP3:
  364. case WMDM_FORMATCODE_WMA:
  365. case WMDM_FORMATCODE_OGG:
  366. case WMDM_FORMATCODE_AAC:
  367. case WMDM_FORMATCODE_MP4:
  368. case WMDM_FORMATCODE_AUDIBLE:
  369. case WMDM_FORMATCODE_FLAC:
  370. case WMDM_FORMATCODE_UNDEFINEDAUDIO:
  371. foundSong(store2,meta,false,0,0,0,alb,albmeta);
  372. break;
  373. }
  374. } else {
  375. wchar_t * ext = wcsrchr(buf,'.');
  376. if(ext) {
  377. bool m = noMetadata;
  378. noMetadata = true;
  379. if(!_wcsicmp(ext,L".mp3") || !_wcsicmp(ext,L".wma")) foundSong(store2,meta,false,0,artist,album);
  380. else if(!_wcsicmp(ext,L".wmv") || !_wcsicmp(ext,L".avi")) foundSong(store2,meta,true,0,artist,album);
  381. else if(!_wcsicmp(ext,L".asx") || !_wcsicmp(ext,L".pla")) foundPlaylist(store2,meta);
  382. noMetadata = m;
  383. }
  384. }
  385. meta->Release();
  386. if(name) CoTaskMemFree(name);
  387. if(value) CoTaskMemFree(value);
  388. }
  389. }
  390. if(store2) store2->Release();
  391. }
  392. if(alb) alb->Release();
  393. if(albmeta) albmeta->Release();
  394. }
  395. bool P4SDevice::songsEqual(songid_t a, songid_t b) {
  396. wchar_t ba[1024] = {0};
  397. wchar_t bb[1024] = {0};
  398. getTrackTitle(a,ba,1024);
  399. getTrackTitle(b,bb,1024);
  400. if(wcscmp(ba,bb)) return false;
  401. getTrackAlbum(a,ba,1024);
  402. getTrackAlbum(b,bb,1024);
  403. if(wcscmp(ba,bb)) return false;
  404. getTrackArtist(a,ba,1024);
  405. getTrackArtist(b,bb,1024);
  406. if(wcscmp(ba,bb)) return false;
  407. return true;
  408. }
  409. int P4SDevice::songsCmp(songid_t a, songid_t b) {
  410. int q=0;
  411. wchar_t ba[1024] = {0};
  412. wchar_t bb[1024] = {0};
  413. getTrackTitle(a,ba,1024);
  414. getTrackTitle(b,bb,1024);
  415. q=wcscmp(ba,bb); if(q) return q;
  416. getTrackAlbum(a,ba,1024);
  417. getTrackAlbum(b,bb,1024);
  418. q=wcscmp(ba,bb); if(q) return q;
  419. getTrackArtist(a,ba,1024);
  420. getTrackArtist(b,bb,1024);
  421. return wcscmp(ba,bb);
  422. }
  423. P4SDevice * sortDev;
  424. static int song_sortfunc(const void *elem1, const void *elem2) {
  425. songid_t a = *(songid_t *)elem1;
  426. songid_t b = *(songid_t *)elem2;
  427. return sortDev->songsCmp(a,b);
  428. }
  429. extern IWMDRMDeviceApp * DRMDeviceApp;
  430. static songid_t BinaryChopFind(songid_t find,Playlist * mpl, P4SDevice * dev) {
  431. sortDev = dev;
  432. songid_t * ret = (songid_t*)bsearch(&find,mpl->songs.GetAll(),mpl->songs.GetSize(),sizeof(songid_t),song_sortfunc);
  433. return ret?*ret:NULL;
  434. }
  435. P4SDevice::P4SDevice(IWMDMDevice3* pIDevice, bool noMetadata) : transcoder(NULL) {
  436. error=0;
  437. musicDir = L"Music";
  438. videoDir = L"Video";
  439. lastChange=NULL;
  440. this->noMetadata = noMetadata;
  441. if(DRMDeviceApp && DRMDeviceApp->SynchronizeLicenses(pIDevice,NULL,0,0) == S_OK)
  442. {
  443. //OutputDebugString(L"sync!");
  444. }
  445. playlistsDir=NULL;
  446. transferQueueSize=0;
  447. Playlist * mpl = new Playlist;
  448. playlists.Add(mpl);
  449. WMDevice = pIDevice;
  450. if (NULL != WMDevice)
  451. {
  452. WMDevice->AddRef();
  453. if (FAILED(WMDevice->GetName(name,100)))
  454. name[0] = L'\0';
  455. }
  456. else
  457. name[0] = L'\0';
  458. // give loading indication to the user....
  459. pmpDeviceLoading load;
  460. load.dev = this;
  461. load.UpdateCaption = NULL;
  462. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)&load,PMP_IPC_DEVICELOADING);
  463. if(load.UpdateCaption) {
  464. wchar_t buf[200]=L"";
  465. wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_LOADING),name);
  466. load.UpdateCaption(buf,load.context);
  467. }
  468. Load();
  469. }
  470. void P4SDevice::Load() {
  471. Playlist * mpl = (Playlist*)playlists.Get(0);
  472. HRESULT hr;
  473. IWMDMEnumStorage * enstore=0;
  474. IWMDMStorage * store0=0;
  475. IWMDMStorage4 * store=0;
  476. hr = WMDevice->EnumStorage(&enstore);
  477. ULONG num;
  478. if(!enstore) {delete this; return;}
  479. hr = enstore->Next(1,&store0,&num);
  480. if (SUCCEEDED(hr)) hr = store0->QueryInterface(&store);
  481. if(store0) store0->Release();
  482. else error=1;
  483. if(enstore) enstore->Release();
  484. else error=1;
  485. if (SUCCEEDED(hr) && !error) {
  486. wchar_t buf[100] = {0};
  487. store->GetName(buf,100);
  488. mpl->storage = store;
  489. store->AddRef();
  490. WMDM_STORAGE_ENUM_MODE mode = ENUM_MODE_RAW;
  491. store->SetEnumPreference(&mode,0,NULL);
  492. //traverseStorage(store);
  493. IWMDMStorage * playlists;
  494. if(store->GetStorage(L"Playlists",&playlists) == S_FALSE) {
  495. if(store->GetStorage(L"My Playlists",&playlists) == S_FALSE)
  496. {
  497. playlists = NULL;
  498. }
  499. }
  500. if(playlists)
  501. {
  502. traverseStorage(playlists);
  503. playlists->QueryInterface(&playlistsDir);
  504. playlists->Release();
  505. }
  506. IWMDMStorage * songs = NULL;
  507. if(store->GetStorage(L"Music",&songs) == S_OK)
  508. {
  509. traverseStorage(songs);
  510. songs->Release();
  511. }
  512. else if(store->GetStorage(L"My Music",&songs) == S_OK)
  513. {
  514. traverseStorage(songs);
  515. songs->Release();
  516. musicDir = L"My Music";
  517. }
  518. else if(store->GetStorage(L"Music Files",&songs) == S_OK)
  519. {
  520. traverseStorage(songs);
  521. songs->Release();
  522. musicDir = L"Music Files";
  523. }
  524. else { // create a music folder
  525. IWMDMStorageControl3 * storeControl=NULL;
  526. store->QueryInterface(&storeControl);
  527. if(storeControl) {
  528. IWMDMStorage * newdir=NULL;
  529. IWMDMMetaData * meta=NULL;
  530. store->CreateEmptyMetadataObject(&meta);
  531. storeControl->Insert3(WMDM_MODE_BLOCK|WMDM_CONTENT_FOLDER,WMDM_FILE_ATTR_FOLDER,NULL,musicDir,NULL,NULL,meta,NULL,&newdir);
  532. if(newdir) newdir->Release();
  533. else error=1;
  534. if(meta) meta->Release();
  535. else error=1;
  536. storeControl->Release();
  537. } else error=1;
  538. }
  539. if(store->GetStorage(L"Video",&songs) == S_OK) { traverseStorage(songs); songs->Release(); supportsVideo=true; }
  540. if(store->GetStorage(L"TV",&songs) == S_OK) { traverseStorage(songs); songs->Release(); supportsVideo=true; }
  541. if(!playlists && !songs) traverseStorage(store);
  542. }
  543. if(!store) error=1;
  544. if(error) {delete this; return;}
  545. if(!playlistsDir) playlistsDir = GetOrCreateFolder(store,L"Playlists");
  546. if(!playlistsDir) {delete this; return;}//MessageBox(plugin.hwndWinampParent,L"An error has occured whilst trying to initialise the playlists on your device.\nPlaylists will not work correctly.",L"Playlists Error",0);
  547. sortDev = this;
  548. qsort(mpl->songs.GetAll(),mpl->songs.GetSize(),sizeof(void*),song_sortfunc);
  549. // Now to recombobulate the playlists (this SUCKS slightly less now)
  550. for(int i=1; i<playlists.GetSize(); i++) {
  551. Playlist * pl = (Playlist *)playlists.Get(i);
  552. int l = pl->songs.GetSize();
  553. for(int j=0; j<l; j++) {
  554. songid_t plsong = (songid_t)pl->songs.Get(j);
  555. songid_t mplsong = BinaryChopFind(plsong,mpl,this);
  556. if(mplsong) pl->songs.Set(j,(void*)mplsong);
  557. else { pl->songs.Del(j--); l--; }
  558. Song * p = (Song *)plsong;
  559. p->meta->Release();
  560. p->storage->Release();
  561. delete p;
  562. }
  563. }
  564. requiresALB=false;
  565. { // check for .alb support
  566. WMDM_FORMAT_CAPABILITY formatCapList;
  567. HRESULT hr = WMDevice->GetFormatCapability(WMDM_FORMATCODE_ABSTRACTAUDIOALBUM, &formatCapList);
  568. bool size=false,data=false,format=false;
  569. if(!FAILED(hr)) {
  570. for(unsigned int i=0; i<formatCapList.nPropConfig; i++) {
  571. WMDM_PROP_CONFIG formatConfig = formatCapList.pConfigs[i];
  572. for(unsigned int j=0; j<formatConfig.nPropDesc; j++) {
  573. if(!formatConfig.pPropDesc[j].pwszPropName) continue;
  574. if(wcscmp(formatConfig.pPropDesc[j].pwszPropName,g_wszWMDMAlbumCoverSize)==0) size=true;
  575. else if(wcscmp(formatConfig.pPropDesc[j].pwszPropName,g_wszWMDMAlbumCoverData)==0) data=true;
  576. else if(wcscmp(formatConfig.pPropDesc[j].pwszPropName,g_wszWMDMAlbumCoverFormat)==0) format=true;
  577. }
  578. }
  579. }
  580. if(size && data && format) requiresALB=true;
  581. FreeFormatCapability(formatCapList);
  582. }
  583. devices.Add(this);
  584. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
  585. //transcoder = NULL;
  586. transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
  587. if(transcoder) {
  588. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP3,WMDevice)))
  589. transcoder->AddAcceptableFormat(L"mp3");
  590. //transcoder->AddAcceptableFormat(L"wav");
  591. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMA,WMDevice)))
  592. transcoder->AddAcceptableFormat(L"wma");
  593. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_ASF,WMDevice)))
  594. transcoder->AddAcceptableFormat(L"asf");
  595. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AVI,WMDevice)))
  596. transcoder->AddAcceptableFormat(L"avi");
  597. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_OGG,WMDevice)))
  598. transcoder->AddAcceptableFormat(L"ogg");
  599. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_FLAC,WMDevice)))
  600. transcoder->AddAcceptableFormat(L"flac");
  601. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AUDIBLE,WMDevice)))
  602. transcoder->AddAcceptableFormat(L"aa");
  603. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MPEG,WMDevice))) {
  604. transcoder->AddAcceptableFormat(L"mpeg");
  605. transcoder->AddAcceptableFormat(L"mpg");
  606. }
  607. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMV,WMDevice)))
  608. transcoder->AddAcceptableFormat(L"wmv");
  609. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_3GP,WMDevice)))
  610. transcoder->AddAcceptableFormat(L"3gp");
  611. if(SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice))) {
  612. transcoder->AddAcceptableFormat(L"mp4");
  613. transcoder->AddAcceptableFormat(L"m4a");
  614. }
  615. if(noMetadata || SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AAC,WMDevice))) {
  616. transcoder->AddAcceptableFormat(L"m4a");
  617. transcoder->AddAcceptableFormat(L"mp4");
  618. transcoder->AddAcceptableFormat(L"aac");
  619. }
  620. }
  621. }
  622. static void commitPlaylist(Playlist * pl) {
  623. int l = pl->songs.GetSize();
  624. IWMDMStorage ** newOrder = (IWMDMStorage **)calloc(l, sizeof(IWMDMStorage *));
  625. for(int j=0; j<l; j++) ((Song *)pl->songs.Get(j))->storage->QueryInterface(&newOrder[j]);
  626. pl->storage->SetReferences(l, newOrder);
  627. for(int i=0; i<l; i++) newOrder[i]->Release();
  628. free(newOrder);
  629. pl->modified = false;
  630. }
  631. P4SDevice::~P4SDevice() {
  632. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
  633. if(playlistsDir) playlistsDir->Release();
  634. for(int i=1; i<playlists.GetSize(); i++) {
  635. Playlist * pl = (Playlist*)playlists.Get(i);
  636. if(pl->modified) commitPlaylist(pl);
  637. pl->storage->Release();
  638. pl->meta->Release();
  639. }
  640. if(playlists.GetSize()) {
  641. Playlist * pl = (Playlist*)playlists.Get(0);
  642. pl->storage->Release();
  643. for(int j=0; j < pl->songs.GetSize(); j++) {
  644. Song * s = (Song *)pl->songs.Get(j);
  645. if (s)
  646. {
  647. if(s->modified) s->storage->SetMetadata(s->meta);
  648. s->meta->Release();
  649. s->storage->Release();
  650. delete s;
  651. }
  652. }
  653. }
  654. for(int i=0; i<devices.GetSize(); i++) {
  655. if(devices.Get(i) == (void*)this) {
  656. devices.Del(i);
  657. return;
  658. }
  659. }
  660. WMDevice->Release();
  661. if(transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
  662. }
  663. void P4SDevice::Close()
  664. {
  665. delete this;
  666. }
  667. __int64 P4SDevice::getDeviceCapacityAvailable() {
  668. static __int64 prev;
  669. IWMDMStorageGlobals * sg = NULL;
  670. if(!playlistsDir) return 0;
  671. playlistsDir->GetStorageGlobals(&sg);
  672. if(sg) {
  673. ULARGE_INTEGER s;
  674. sg->GetTotalFree(&s.LowPart,&s.HighPart);
  675. sg->Release();
  676. if(s.LowPart == 0 && s.HighPart == 0) return prev;
  677. return prev = s.QuadPart;
  678. }
  679. return prev;
  680. }
  681. __int64 P4SDevice::getDeviceCapacityTotal() {
  682. static __int64 prev;
  683. IWMDMStorageGlobals * sg = NULL;
  684. if(!playlistsDir) return 0;
  685. playlistsDir->GetStorageGlobals(&sg);
  686. if(sg) {
  687. ULARGE_INTEGER s;
  688. sg->GetTotalSize(&s.LowPart,&s.HighPart);
  689. sg->Release();
  690. if(s.LowPart == 0 && s.HighPart == 0) return prev;
  691. return prev = s.QuadPart;
  692. }
  693. return prev;
  694. }
  695. void P4SDevice::deleteTrack(songid_t songid) {
  696. lastChange=NULL;
  697. Song * s = (Song*)songid;
  698. IWMDMStorageControl3 * storeControl=NULL;
  699. s->storage->QueryInterface(&storeControl);
  700. if(!storeControl) return;
  701. for(int i=0; i<playlists.GetSize(); i++) {
  702. Playlist * pl = (Playlist *)playlists.Get(i);
  703. int j = pl->songs.GetSize();
  704. while(j-- > 0) if((Song *)pl->songs.Get(j) == s) { pl->songs.Del(j); pl->modified=true; }
  705. }
  706. if(storeControl->Delete(WMDM_MODE_BLOCK,NULL) != S_OK) return;
  707. s->meta->Release();
  708. s->storage->Release();
  709. storeControl->Release();
  710. delete s;
  711. }
  712. void P4SDevice::commitChanges() {
  713. for(int i=1; i<playlists.GetSize(); i++) {
  714. Playlist * pl = (Playlist*)playlists.Get(i);
  715. if(pl->modified) commitPlaylist(pl);
  716. }
  717. Playlist * pl = (Playlist*)playlists.Get(0);
  718. for(int j=0; j < pl->songs.GetSize(); j++) {
  719. Song * s = (Song *)pl->songs.Get(j);
  720. if(s->modified) {
  721. s->storage->SetMetadata(s->meta);
  722. s->meta->Release();
  723. s->storage->GetMetadata(&s->meta);
  724. s->modified = false;
  725. }
  726. }
  727. lastChange=NULL;
  728. }
  729. static int fileSizeA(char * filename)
  730. {
  731. FILE * fh = fopen(filename,"rb");
  732. if(!fh) return -1;
  733. fseek(fh,0,2); //seek to end;
  734. int l = ftell(fh);
  735. fclose(fh);
  736. return l;
  737. }
  738. #define MKVALIDFN(x) { wchar_t * n = x; while(n && *n == L'.') *(n++)=L'_'; while(n && *n) { if(*n == L'|' || *n == L'\\' || *n == L'/' || *n == L'?' || *n == L'<' || *n == L'>' || *n == L':' || *n == L'*' || *n == L'"') *n=L'_'; n++; } n = x+wcslen(x)-1; while(n && *n==L'.' && n>=x) *(n--)=0; }
  739. static IWMDMStorage4* GetOrCreateFolder(IWMDMStorage4 * store, wchar_t * name, P4SDevice * dev, bool album, const itemRecordW * item) {
  740. if(!name[0]) name=L"Blank";
  741. MKVALIDFN(name);
  742. if(!name[0]) name=L"Blank";
  743. if(!store) return NULL;
  744. IWMDMEnumStorage * enstore=NULL;
  745. HRESULT hr = store->EnumStorage(&enstore);
  746. IWMDMStorage * store0;
  747. IWMDMStorage4 * store4;
  748. ULONG num;
  749. if(!enstore) return NULL;
  750. enstore->Reset();
  751. hr = enstore->Next(1,&store0,&num);
  752. while(hr == S_OK) {
  753. store4=NULL;
  754. store0->QueryInterface(&store4);
  755. store0->Release();
  756. wchar_t buf[100] = {0};
  757. store4->GetName(buf,100);
  758. if(_wcsicmp(buf,name) == 0) {
  759. return store4;
  760. }
  761. store4->Release();
  762. hr = enstore->Next(1,&store0,&num);
  763. }
  764. if(enstore) enstore->Release();
  765. // we must create it!
  766. store0=store4=NULL;
  767. IWMDMStorageControl3 * storeControl=NULL;
  768. store->QueryInterface(&storeControl);
  769. if(!storeControl) return NULL;
  770. IWMDMMetaData * meta;
  771. store->CreateEmptyMetadataObject(&meta);
  772. storeControl->Insert3(WMDM_MODE_BLOCK|WMDM_CONTENT_FOLDER,WMDM_FILE_ATTR_FOLDER,NULL,name,NULL,NULL,meta,NULL,&store0);
  773. meta->Release();
  774. if(!store0) return NULL;
  775. store0->QueryInterface(&store4);
  776. storeControl->Release();
  777. store0->Release();
  778. store->Release();
  779. if(album) {
  780. wchar_t buffer[MAX_PATH];
  781. IWMDMStorageControl3 * storeControl;
  782. wsprintf(buffer,L"%s.alb",name);
  783. store4->QueryInterface(&storeControl);
  784. IWMDMStorage * newpl=NULL;
  785. IWMDMStorage4 * newpl4=NULL;
  786. IWMDMMetaData * meta=NULL;
  787. store4->CreateEmptyMetadataObject(&meta);
  788. if (meta)
  789. {
  790. DWORD formatCode = WMDM_FORMATCODE_ABSTRACTAUDIOALBUM;
  791. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&formatCode,sizeof(DWORD));
  792. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)name,(wcslen(name)*2)+2);
  793. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)((wchar_t*)item->albumartist),(wcslen(item->albumartist)*2)+2);
  794. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)name,(wcslen(name)*2)+2);
  795. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)((wchar_t*)item->artist),(wcslen(item->artist)*2)+2);
  796. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)((wchar_t*)item->genre),(wcslen(item->genre)*2)+2);
  797. storeControl->Insert3(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,0,NULL,buffer,NULL,NULL,meta,NULL,&newpl);
  798. storeControl->Release();
  799. if (newpl)
  800. {
  801. newpl->QueryInterface(&newpl4);
  802. newpl->Release();
  803. }
  804. if (newpl4)
  805. {
  806. newpl4->SetReferences(0,NULL);
  807. newpl4->SetMetadata(meta);
  808. newpl4->Release();
  809. }
  810. meta->Release();
  811. }
  812. }
  813. return store4;
  814. }
  815. // Disabled for 5.64
  816. // Fixes issues with exit failures and duplicates on transfer (view issue only) and other memory corruption issues
  817. /*typedef struct {
  818. C_ItemList * playlists;
  819. void * item;
  820. } addTrackStruct;
  821. void CALLBACK addTrack(ULONG_PTR dwParam) {
  822. addTrackStruct * a = (addTrackStruct *) dwParam;
  823. ((Playlist*)a->playlists->Get(0))->songs.Add(a->item);
  824. delete a;
  825. }*/
  826. static void getTime(__time64_t value, _WMDMDATETIME * time) {
  827. if(!time) return;
  828. ZeroMemory(time,sizeof(_WMDMDATETIME));
  829. struct tm * t = _localtime64(&value);
  830. if(!t) return;
  831. time->wYear = t->tm_year;
  832. time->wMonth = t->tm_mon;
  833. time->wDay = t->tm_mday;
  834. time->wHour = t->tm_hour;
  835. time->wMinute = t->tm_min;
  836. time->wSecond = t->tm_sec;
  837. }
  838. static int atoi_nullok(char * str) {
  839. if(str) return atoi(str);
  840. return 0;
  841. }
  842. static IWMDMStorage * storefoo;
  843. #define PHASE_START 1
  844. #define PHASE_INPROGRESS 2
  845. #define PHASE_FINISH 3
  846. #define PHASE_DONE 4
  847. #define PHASE_ERROR 5
  848. extern CSecureChannelClient SAC;
  849. extern int SynchronousProcedureCall(void * p, ULONG_PTR dwParam);
  850. void P4SDevice::doTransfer(TransferItem * t) {
  851. static wchar_t buf[256];
  852. static IWMDMStorage4 * store;
  853. static IWMDMStorageControl3 * control;
  854. switch(t->phase) {
  855. case PHASE_START:
  856. {
  857. bool video = false;
  858. DWORD formatCode=0;
  859. wchar_t * point = wcsrchr(t->file,L'.');
  860. if(point) {
  861. if(_wcsicmp(point,L".wma")==0) formatCode = WMDM_FORMATCODE_WMA;
  862. else if(_wcsicmp(point,L".wav")==0) formatCode = WMDM_FORMATCODE_WAVE;
  863. else if(_wcsicmp(point,L".ogg")==0) formatCode = WMDM_FORMATCODE_OGG;
  864. else if(_wcsicmp(point,L".m4a")==0) formatCode = WMDM_FORMATCODE_MP4;
  865. else if(_wcsicmp(point,L".aac")==0) formatCode = WMDM_FORMATCODE_AAC;
  866. else if(_wcsicmp(point,L".aa")==0) formatCode = WMDM_FORMATCODE_AUDIBLE;
  867. else if(_wcsicmp(point,L".flac")==0 || _wcsicmp(point,L".fla")==0) formatCode = WMDM_FORMATCODE_FLAC;
  868. else if(_wcsicmp(point,L".asf")==0) { video=true; formatCode = WMDM_FORMATCODE_ASF; }
  869. else if(_wcsicmp(point,L".avi")==0) { video=true; formatCode = WMDM_FORMATCODE_AVI; }
  870. else if(_wcsicmp(point,L".mpg")==0) { video=true; formatCode = WMDM_FORMATCODE_MPEG; }
  871. else if(_wcsicmp(point,L".mpeg")==0) { video=true; formatCode = WMDM_FORMATCODE_MPEG; }
  872. else if(_wcsicmp(point,L".wmv")==0) { video=true; formatCode = WMDM_FORMATCODE_WMV; }
  873. else if(_wcsicmp(point,L".m4v")==0) { video=true; formatCode = WMDM_FORMATCODE_MP4; }
  874. else if(_wcsicmp(point,L".mp2")==0) { video=true; formatCode = WMDM_FORMATCODE_MP2; }
  875. else if(_wcsicmp(point,L".mp4")==0) {
  876. wchar_t buf[10]=L"0";
  877. extendedFileInfoStructW m = {t->file,L"type",buf,10};
  878. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&m,IPC_GET_EXTENDED_FILE_INFOW);
  879. formatCode = WMDM_FORMATCODE_MP4;
  880. video = (buf[0]==L'1');
  881. }
  882. else formatCode = WMDM_FORMATCODE_MP3; // mp3 or whatever
  883. }
  884. t->video = video;
  885. store = ((Playlist *)playlists.Get(0))->storage;
  886. store->AddRef();
  887. if(video) {
  888. store = GetOrCreateFolder(store,videoDir,this);
  889. if(_wcsicmp(t->track->artist,L"")) store = GetOrCreateFolder(store,t->track->artist);
  890. } else {
  891. store = GetOrCreateFolder(store,musicDir,this);
  892. if(_wcsicmp(t->track->artist,L"")) store = GetOrCreateFolder(store,t->track->artist);
  893. else store = GetOrCreateFolder(store,L"No Artist");
  894. if(_wcsicmp(t->track->album,L"")) store = GetOrCreateFolder(store,t->track->album,this,requiresALB,t->track);
  895. else store = GetOrCreateFolder(store,L"No Album");
  896. }
  897. /*
  898. DWORD dw;
  899. do {
  900. WMDevice->GetStatus(&dw);
  901. SleepEx(50,true);
  902. } while(!(dw & WMDM_STATUS_READY));
  903. */
  904. if(!store) {
  905. t->callback(t->callbackContext,WASABI_API_LNGSTRINGW(IDS_COUND_NOT_CREATE_FOLDER));
  906. *(t->songid)=NULL;
  907. t->phase=PHASE_ERROR;
  908. return;
  909. }
  910. // create and fill in metadata...
  911. HRESULT hr;
  912. hr = store->CreateEmptyMetadataObject(&t->meta);
  913. if(hr != S_OK) {
  914. wchar_t buf[100] = {0};
  915. wsprintf(buf,WASABI_API_LNGSTRINGW(IDS_COULD_NOT_CREATE_METADATA),hr);
  916. t->callback(t->callbackContext,buf);
  917. *(t->songid)=NULL;
  918. t->phase=PHASE_ERROR;
  919. return;
  920. }
  921. t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&formatCode,sizeof(DWORD));
  922. if(t->track->artist) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)((wchar_t*)(t->track->artist)),(wcslen(t->track->artist)*2)+2);
  923. if(t->track->albumartist) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)((wchar_t*)(t->track->albumartist)),(wcslen(t->track->albumartist)*2)+2);
  924. if(t->track->composer) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMComposer,(BYTE*)((wchar_t*)(t->track->composer)),(wcslen(t->track->composer)*2)+2);
  925. if(t->track->album) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)((wchar_t*)(t->track->album)),(wcslen(t->track->album)*2)+2);
  926. if(t->track->genre) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)((wchar_t*)(t->track->genre)),(wcslen(t->track->genre)*2)+2);
  927. if(t->track->title) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)((wchar_t*)(t->track->title)),(wcslen(t->track->title)*2)+2);
  928. if(t->track->track> 0) t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMTrack,(BYTE*)&t->track->track,sizeof(DWORD));
  929. __int64 len = t->track->length;
  930. len *= 10000000;
  931. wchar_t buf2[256] = {0};
  932. t->meta->AddItem(WMDM_TYPE_QWORD,g_wszWMDMDuration,(BYTE*)&len,sizeof(__int64));
  933. int fs = fileSizeA(AutoChar(t->file));
  934. len = fs;
  935. t->meta->AddItem(WMDM_TYPE_QWORD,g_wszWMDMFileSize,(BYTE*)&len,sizeof(__int64));
  936. wsprintf(buf2,L"%d",t->track->year);
  937. if(t->track->year > 0) t->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMYear,(BYTE*)buf2,(wcslen(buf2)*2) + 2);
  938. int v;
  939. if (t->track->length)
  940. {
  941. v = 8*(fs/t->track->length); //atoi_nullok(getRecordExtendedItem(t->track,"BITRATE")) * 1000;
  942. t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMBitrate,(BYTE*)&v,sizeof(DWORD));
  943. }
  944. v = t->track->playcount;
  945. t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMPlayCount,(BYTE*)&v,sizeof(DWORD));
  946. v = t->track->rating;
  947. if(v>=0 && v<=5) t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMUserRating,(BYTE*)&v,sizeof(DWORD));
  948. _WMDMDATETIME time1={0}, time2={0};
  949. getTime(t->track->lastplay,&time1);
  950. t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMUserLastPlayTime,(BYTE*)&time1,sizeof(DWORD));
  951. getTime(t->track->lastupd,&time2);
  952. t->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMLastModifiedDate,(BYTE*)&time2,sizeof(DWORD));
  953. control = NULL;
  954. store->QueryInterface(&control);
  955. IWMDMStorage * newstore=NULL;
  956. if(video) wsprintf(buf,L"%s%s",(wchar_t*)(t->track->title),(wchar_t*)(wcsrchr(t->track->filename,'.')));
  957. else wsprintf(buf,L"%02d - %s%s",t->track->track,(wchar_t*)(t->track->title),(wchar_t*)(wcsrchr(t->track->filename,'.')));
  958. if(video) wsprintf(buf,L"%s%s",(wchar_t*)(t->track->title),wcsrchr(t->file,L'.'));
  959. else wsprintf(buf,L"%02d - %s%s",t->track->track,(wchar_t*)(t->track->title),wcsrchr(t->file,L'.'));
  960. MKVALIDFN(buf);
  961. if(!control) {
  962. t->callback(t->callbackContext,WASABI_API_LNGSTRINGW(IDS_INCOMPATABLE_DEVICE));
  963. *(t->songid)=NULL;
  964. t->phase = PHASE_ERROR;
  965. return;
  966. }
  967. t->phase = PHASE_INPROGRESS;
  968. t->progress = new MyProgress(t);
  969. storefoo = NULL;
  970. hr = control->Insert3(WMDM_MODE_BLOCK|WMDM_MODE_TRANSFER_PROTECTED|WMDM_CONTENT_FILE|WMDM_STORAGECONTROL_INSERTAFTER,
  971. WMDM_FILE_ATTR_FILE,
  972. t->file,
  973. buf,
  974. NULL,
  975. t->progress,
  976. t->meta,
  977. NULL,
  978. &storefoo);
  979. //OutputDebugString(L"finished insert");
  980. if (FAILED(hr)) {
  981. wchar_t buf1[100] = {0};
  982. wsprintf(buf1,WASABI_API_LNGSTRINGW(IDS_ERROR_IN_INSERT),hr);
  983. t->callback(t->callbackContext,buf1);
  984. *(t->songid)=NULL;
  985. t->phase = PHASE_ERROR;
  986. return;
  987. }
  988. }
  989. break;
  990. case PHASE_FINISH:
  991. //OutputDebugString(L"phase finish start");
  992. {
  993. /*
  994. DWORD dw;
  995. WMDevice->GetStatus(&dw);
  996. while(!(dw == WMDM_STATUS_READY)) {
  997. SleepEx(50,true);
  998. WMDevice->GetStatus(&dw);
  999. }
  1000. */
  1001. }
  1002. t->progress->Release();
  1003. control->Release();
  1004. if(storefoo) { /*OutputDebugString(L"storefoo");*/ storefoo->Release(); storefoo=NULL; }
  1005. if(store) {
  1006. IWMDMStorage * store0 = NULL;
  1007. store->GetStorage(buf,&store0);
  1008. store->Release();
  1009. if(store0) {
  1010. IWMDMStorage4 * store4 = NULL;
  1011. store0->QueryInterface(&store4);
  1012. if(store4) {
  1013. store4->AddRef();
  1014. store0->Release();
  1015. store4->SetMetadata(t->meta);
  1016. //t->meta->Release();
  1017. Song * song = new Song;
  1018. song->modified=false;
  1019. song->storage = store4;
  1020. song->meta = t->meta;
  1021. song->video = t->video;
  1022. //((Playlist*)playlists.Get(0))->songs.Add(song);
  1023. // Disabled for 5.64
  1024. // Fixes issues with exit failures and duplicates on transfer (view issue only) and other memory corruption issues
  1025. /*
  1026. addTrackStruct * a = new addTrackStruct;
  1027. a->item=song;
  1028. a->playlists = &playlists;
  1029. //PostMessage(plugin.hwndPortablesParent,WM_USER+3,(WPARAM)addTrack,(LPARAM)a);
  1030. SynchronousProcedureCall((void*)addTrack,(ULONG_PTR)a);
  1031. */
  1032. *(t->songid) = (songid_t)song;
  1033. // sort out the album group...
  1034. if(t->track->album && requiresALB) {
  1035. IWMDMStorage * album0=NULL;
  1036. IWMDMStorage * parent=NULL;
  1037. IWMDMStorage4 * parent4=NULL;
  1038. IWMDMStorage4 * album4;
  1039. wchar_t buf[512] = {0};
  1040. wsprintf(buf,L"%s.alb",(wchar_t*)(t->track->album));
  1041. store4->GetParent(&parent);
  1042. if (parent)
  1043. {
  1044. parent->QueryInterface(&parent4);
  1045. parent->Release();
  1046. if (parent4)
  1047. {
  1048. parent4->GetStorage(buf,&album0);
  1049. parent4->Release();
  1050. if(album0) {
  1051. album0->QueryInterface(&album4);
  1052. album0->Release();
  1053. DWORD refc;
  1054. IWMDMStorage ** refs;
  1055. IWMDMStorage ** newrefs;
  1056. album4->GetReferences(&refc,&refs);
  1057. newrefs = (IWMDMStorage **)calloc((refc + 1), sizeof(void*));
  1058. for(DWORD i=0; i<refc; i++) newrefs[i] = refs[i];
  1059. newrefs[refc] = store4;
  1060. refc++;
  1061. album4->SetReferences(refc,newrefs);
  1062. refc--;
  1063. for(DWORD i=0; i<refc; i++) refs[i]->Release();
  1064. free(newrefs);
  1065. CoTaskMemFree(refs);
  1066. song->alb = album4;
  1067. album4->GetMetadata(&song->albmeta);
  1068. //album4->Release();
  1069. int w,h;
  1070. ARGB32 *bits;
  1071. if (AGAVE_API_ALBUMART->GetAlbumArt(t->file, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS)
  1072. {
  1073. setArt((songid_t)song,bits,w,h);
  1074. WASABI_API_MEMMGR->sysFree(bits);
  1075. }
  1076. }
  1077. }
  1078. }
  1079. }
  1080. }
  1081. }
  1082. }
  1083. if(!*t->songid) t->callback(t->callbackContext,WASABI_API_LNGSTRINGW(IDS_UNSPECIFIED_ERROR));
  1084. t->phase = PHASE_DONE;
  1085. //OutputDebugString(L"phase finish finished");
  1086. break;
  1087. }
  1088. }
  1089. int P4SDevice::transferTrackToDevice(const itemRecordW * track,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),songid_t * songid,int * killswitch) {
  1090. wchar_t file[2048] = {0};
  1091. StringCchCopy(file, ARRAYSIZE(file), track->filename);
  1092. bool deletefile = false;
  1093. if(transcoder) if(transcoder->ShouldTranscode(file)) {
  1094. wchar_t newfile[MAX_PATH] = {0};
  1095. wchar_t ext[10] = {0};
  1096. transcoder->CanTranscode(file,ext);
  1097. transcoder->GetTempFilePath(ext,newfile);
  1098. if(transcoder->TranscodeFile(file,newfile,killswitch,callback,callbackContext)) return -1;
  1099. StringCchCopy(file, ARRAYSIZE(file), newfile);
  1100. deletefile=true;
  1101. }
  1102. callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_WAITING_FOR_OTHER_TRANSFERS));
  1103. EnterCriticalSection(&csTransfers); // only one transfer at once, globally :(
  1104. callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
  1105. TransferItem t;
  1106. t.file = file;
  1107. t.track = track;
  1108. t.callback = callback;
  1109. t.callbackContext = callbackContext;
  1110. t.killswitch = killswitch;
  1111. t.songid = songid;
  1112. t.dev = this;
  1113. t.phase = PHASE_START;
  1114. t.pc = 0;
  1115. *songid = NULL;
  1116. this->doTransfer(&t); // do the transfer
  1117. if(t.phase == PHASE_FINISH) this->doTransfer(&t); // finish it, if needs be.
  1118. int ret = (*songid)?0:-1;
  1119. if(ret==0) callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_DONE));
  1120. trackRemovedFromTransferQueue(track);
  1121. LeaveCriticalSection(&csTransfers);
  1122. if(deletefile) _wunlink(file);
  1123. return ret;
  1124. }
  1125. bool extentionSupported(IWMDMDevice3* WMDevice, wchar_t * ext,bool aac_and_m4a_support, bool video_supported) {
  1126. if(!ext) return false;
  1127. bool supported=false;
  1128. if(!_wcsicmp(ext,L".mp3")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP3,WMDevice));
  1129. else if(!_wcsicmp(ext,L".wma")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMA,WMDevice));
  1130. else if(!_wcsicmp(ext,L".wav")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WAVE,WMDevice));
  1131. else if(!_wcsicmp(ext,L".aa")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AUDIBLE,WMDevice));
  1132. else if(!_wcsicmp(ext,L".m4a") || !_wcsicmp(ext,L".aac")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AAC,WMDevice)) || SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice));
  1133. else if(!_wcsicmp(ext,L".ogg")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_OGG,WMDevice));
  1134. else if(!_wcsicmp(ext,L".flac") || !_wcsicmp(ext,L".fla")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_FLAC,WMDevice));
  1135. else if(!_wcsicmp(ext,L".avi")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AVI,WMDevice));
  1136. else if(!_wcsicmp(ext,L".mpg") || !_wcsicmp(ext,L".mpeg")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MPEG,WMDevice));
  1137. else if(!_wcsicmp(ext,L".asf")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_ASF,WMDevice));
  1138. else if(!_wcsicmp(ext,L".wmv")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_WMV,WMDevice));
  1139. else if(!_wcsicmp(ext,L".mp4")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice)) || SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_AAC,WMDevice));
  1140. else if(!_wcsicmp(ext,L".m4v")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP4,WMDevice));
  1141. else if(!_wcsicmp(ext,L".mp2")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_MP2,WMDevice));
  1142. else if(!_wcsicmp(ext,L".3gp")) supported = SUCCEEDED(GetFormatCaps(WMDM_FORMATCODE_3GP,WMDevice));
  1143. else return false;
  1144. if(!supported) {
  1145. if(!_wcsicmp(ext,L".mp3") || !_wcsicmp(ext,L".wma") || !_wcsicmp(ext,L".wav")) supported=true;
  1146. if(aac_and_m4a_support && (!_wcsicmp(ext,L".m4a") || !_wcsicmp(ext,L".aac"))) supported=true;
  1147. if(video_supported && (!_wcsicmp(ext,L".asf") || !_wcsicmp(ext,L".avi") || !_wcsicmp(ext,L".mpeg") || !_wcsicmp(ext,L".mpg") || !_wcsicmp(ext,L".wmv"))) supported=true;
  1148. }
  1149. return supported;
  1150. }
  1151. /*
  1152. bool extentionSupported(wchar_t * ext,bool aac_and_m4a_support) {
  1153. if(!ext) return false;
  1154. if(_wcsicmp(ext,L".mp3") && _wcsicmp(ext,L".wma") && _wcsicmp(ext,L".wav")
  1155. && (aac_and_m4a_support || (_wcsicmp(ext,L".m4a") && _wcsicmp(ext,L".aac")))
  1156. ) return false;
  1157. return true;
  1158. }
  1159. */
  1160. static __int64 fileSize(wchar_t * filename)
  1161. {
  1162. WIN32_FIND_DATA f={0};
  1163. HANDLE h = FindFirstFileW(filename,&f);
  1164. if(h == INVALID_HANDLE_VALUE) return -1;
  1165. FindClose(h);
  1166. ULARGE_INTEGER i;
  1167. i.HighPart = f.nFileSizeHigh;
  1168. i.LowPart = f.nFileSizeLow;
  1169. return i.QuadPart;
  1170. }
  1171. int P4SDevice::trackAddedToTransferQueue(const itemRecordW * track) {
  1172. __int64 l;
  1173. if(transcoder && transcoder->ShouldTranscode(track->filename)) {
  1174. int k = transcoder->CanTranscode(track->filename);
  1175. if(k == -1) return -2;
  1176. if(k == 0) l = (__int64)fileSize(track->filename);
  1177. else l = (__int64)k;
  1178. } else {
  1179. wchar_t * ext = wcsrchr(track->filename,'.');
  1180. if(!extentionSupported(WMDevice,ext,noMetadata,supportsVideo)) return -2; // fucko: assumes all noMetadata devices are nokia (which is true for now)
  1181. l = (__int64)fileSize(track->filename);
  1182. }
  1183. __int64 test = l;
  1184. __int64 avail = getDeviceCapacityAvailable();
  1185. test += transferQueueSize;
  1186. //test += (__int64)3000000;
  1187. if(test > avail) return -1;
  1188. transferQueueSize += l;
  1189. return 0;
  1190. }
  1191. void P4SDevice::trackRemovedFromTransferQueue(const itemRecordW * track) {
  1192. __int64 l = (__int64)fileSize(track->filename);
  1193. if(transcoder && transcoder->ShouldTranscode(track->filename)) {
  1194. int k = transcoder->CanTranscode(track->filename);
  1195. if(k != -1 && k != 0) l = (__int64)k;
  1196. }
  1197. transferQueueSize -= l;
  1198. }
  1199. __int64 P4SDevice::getTrackSizeOnDevice(const itemRecordW * track) {
  1200. if(transcoder && transcoder->ShouldTranscode(track->filename)) {
  1201. int k = transcoder->CanTranscode(track->filename);
  1202. if(k != -1 && k != 0) return k;
  1203. }
  1204. wchar_t * ext = wcsrchr(track->filename,'.');
  1205. if(!extentionSupported(WMDevice,ext,noMetadata,supportsVideo)) return 0; // fucko: assumes all noMetadata devices are nokia (which is true for now)
  1206. return fileSize(track->filename);
  1207. }
  1208. int P4SDevice::getPlaylistCount() {
  1209. return playlists.GetSize();
  1210. }
  1211. static BYTE* GetMetadataItem(IWMDMMetaData *meta, const WCHAR * name) {
  1212. WMDM_TAG_DATATYPE type;
  1213. BYTE * value=NULL;
  1214. UINT len;
  1215. if(!meta) { return (BYTE*)""; } // OutputDebugString(L"no meta");
  1216. if((meta->QueryByName(name,&type,&value,&len)) != S_OK) { return NULL; /*value;*/ } //wchar_t buf[100]; wsprintf(buf,L"meta fail: %x %s",hr,name); OutputDebugString(buf);
  1217. return value;
  1218. }
  1219. static BYTE* GetMetadataItem(Song * song, const WCHAR * name) {
  1220. WMDM_TAG_DATATYPE type;
  1221. BYTE * value=NULL;
  1222. UINT len;
  1223. if(!song || !(song->meta)) { return (BYTE*)""; } // OutputDebugString(L"no meta");
  1224. if((song->meta->QueryByName(name,&type,&value,&len)) != S_OK) { return NULL; /*value;*/ } //wchar_t buf[100]; wsprintf(buf,L"meta fail: %x %s",hr,name); OutputDebugString(buf);
  1225. return value;
  1226. }
  1227. void P4SDevice::getPlaylistName(int playlistnumber, wchar_t * buf, int len)
  1228. {
  1229. if (NULL == buf)
  1230. return;
  1231. if(playlistnumber == 0)
  1232. {
  1233. if (NULL == WMDevice)
  1234. buf[0] = L'\0';
  1235. else
  1236. {
  1237. HRESULT hr;
  1238. hr = WMDevice->GetName(buf, len);
  1239. if (FAILED(hr))
  1240. {
  1241. buf[0] = L'\0';
  1242. }
  1243. }
  1244. }
  1245. else
  1246. {
  1247. StringCchCopy(buf, len, ((Playlist *)playlists.Get(playlistnumber))->name);
  1248. }
  1249. }
  1250. int P4SDevice::getPlaylistLength(int playlistnumber) {
  1251. if(playlistnumber == -1) return 0;
  1252. return ((Playlist*)playlists.Get(playlistnumber))->songs.GetSize();
  1253. }
  1254. songid_t P4SDevice::getPlaylistTrack(int playlistnumber,int songnum) {
  1255. if(playlistnumber == -1) return NULL;
  1256. return (songid_t)((Playlist*)playlists.Get(playlistnumber))->songs.Get(songnum);
  1257. }
  1258. void P4SDevice::setPlaylistName(int playlistnumber, const wchar_t *buf) {
  1259. if(playlistnumber == -1) return;
  1260. IWMDMStorageControl3 * storeControl=NULL;
  1261. Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
  1262. lstrcpyn(pl->name,buf,128);
  1263. pl->storage->QueryInterface(&storeControl);
  1264. pl->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)buf,(wcslen(buf)*2)+2);
  1265. pl->storage->SetMetadata(pl->meta);
  1266. wchar_t buffer[256] = {0};
  1267. wsprintf(buffer,L"%s.%s",buf,plext);
  1268. if(storeControl) {
  1269. storeControl->Rename(WMDM_MODE_BLOCK,buffer,NULL);
  1270. storeControl->Release();
  1271. }
  1272. }
  1273. int sortby;
  1274. //Device * sortDev;
  1275. #define SKIP_THE_AND_WHITESPACE(x) { while (!iswalnum(*x) && *x) x++; if (!_wcsnicmp(x,L"the ",4)) x+=4; while (*x == L' ') x++; }
  1276. int STRCMP_NULLOK(const wchar_t *pa, const wchar_t *pb) {
  1277. if (!pa) pa=L"";
  1278. else SKIP_THE_AND_WHITESPACE(pa)
  1279. if (!pb) pb=L"";
  1280. else SKIP_THE_AND_WHITESPACE(pb)
  1281. return lstrcmpi(pa,pb);
  1282. }
  1283. #undef SKIP_THE_AND_WHITESPACE
  1284. static int sortFunc(const void *elem1, const void *elem2)
  1285. {
  1286. int use_by = sortby;
  1287. songid_t a=(songid_t)*(songid_t *)elem1;
  1288. songid_t b=(songid_t)*(songid_t *)elem2;
  1289. #define RETIFNZ(v) if ((v)!=0) return v;
  1290. // this might be too slow, but it'd be nice
  1291. int x;
  1292. for (x = 0; x < 5; x ++)
  1293. {
  1294. if (use_by == SORTBY_TITLE) // title -> artist -> album -> disc -> track
  1295. {
  1296. wchar_t bufa[2048] = {0};
  1297. wchar_t bufb[2048] = {0};
  1298. sortDev->getTrackTitle(a,bufa,2048);
  1299. sortDev->getTrackTitle(b,bufb,2048);
  1300. int v=STRCMP_NULLOK(bufa,bufb);
  1301. RETIFNZ(v)
  1302. use_by=SORTBY_ARTIST;
  1303. }
  1304. else if (use_by == SORTBY_ARTIST) // artist -> album -> disc -> track -> title
  1305. {
  1306. wchar_t bufa[2048] = {0};
  1307. wchar_t bufb[2048] = {0};
  1308. sortDev->getTrackArtist(a,bufa,2048);
  1309. sortDev->getTrackArtist(b,bufb,2048);
  1310. int v=STRCMP_NULLOK(bufa,bufb);
  1311. RETIFNZ(v)
  1312. use_by=SORTBY_ALBUM;
  1313. }
  1314. else if (use_by == SORTBY_ALBUM) // album -> disc -> track -> title -> artist
  1315. {
  1316. wchar_t bufa[2048] = {0};
  1317. wchar_t bufb[2048] = {0};
  1318. sortDev->getTrackAlbum(a,bufa,2048);
  1319. sortDev->getTrackAlbum(b,bufb,2048);
  1320. int v=STRCMP_NULLOK(bufa,bufb);
  1321. RETIFNZ(v)
  1322. use_by=SORTBY_DISCNUM;
  1323. }
  1324. else if (use_by == SORTBY_DISCNUM) // disc -> track -> title -> artist -> album
  1325. {
  1326. int v1=sortDev->getTrackDiscNum(a);
  1327. int v2=sortDev->getTrackDiscNum(b);
  1328. if (v1<0)v1=0;
  1329. if (v2<0)v2=0;
  1330. RETIFNZ(v1-v2)
  1331. use_by=SORTBY_TRACKNUM;
  1332. }
  1333. else if (use_by == SORTBY_TRACKNUM) // track -> title -> artist -> album -> disc
  1334. {
  1335. int v1=sortDev->getTrackTrackNum(a);
  1336. int v2=sortDev->getTrackTrackNum(b);
  1337. if (v1<0)v1=0;
  1338. if (v2<0)v2=0;
  1339. RETIFNZ(v1-v2)
  1340. use_by=SORTBY_TITLE;
  1341. }
  1342. else if (use_by == SORTBY_GENRE) // genre -> artist -> album -> disc -> track
  1343. {
  1344. wchar_t bufa[2048] = {0};
  1345. wchar_t bufb[2048] = {0};
  1346. sortDev->getTrackGenre(a,bufa,2048);
  1347. sortDev->getTrackGenre(b,bufb,2048);
  1348. int v=STRCMP_NULLOK(bufa,bufb);
  1349. RETIFNZ(v)
  1350. use_by=SORTBY_ARTIST;
  1351. }
  1352. else if (use_by == SORTBY_PLAYCOUNT) // size -> artist -> album -> disc -> track
  1353. {
  1354. int v1=sortDev->getTrackPlayCount(a);
  1355. int v2=sortDev->getTrackPlayCount(b);
  1356. if (v1<0)v1=0;
  1357. if (v2<0)v2=0;
  1358. RETIFNZ(v1-v2)
  1359. use_by=SORTBY_ARTIST;
  1360. }
  1361. else if (use_by == SORTBY_RATING) // size -> artist -> album -> disc -> track
  1362. {
  1363. int v1=sortDev->getTrackRating(a);
  1364. int v2=sortDev->getTrackRating(b);
  1365. if (v1<0)v1=0;
  1366. if (v2<0)v2=0;
  1367. RETIFNZ(v1-v2)
  1368. use_by=SORTBY_ARTIST;
  1369. }
  1370. else if (use_by == SORTBY_LASTPLAYED)
  1371. {
  1372. __time64_t la = sortDev->getTrackLastPlayed(a);
  1373. __time64_t lb = sortDev->getTrackLastPlayed(b);
  1374. double t = difftime((time_t)la,(time_t)lb);
  1375. int v = t>0?1:(t<0?-1:0);
  1376. RETIFNZ(v)
  1377. use_by=SORTBY_ARTIST;
  1378. }
  1379. else break; // no sort order?
  1380. }
  1381. return 0;
  1382. }
  1383. void P4SDevice::sortPlaylist(int playlistnumber, int sortBy) {
  1384. if(playlistnumber == -1) return;
  1385. sortby = sortBy;
  1386. sortDev = this;
  1387. Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
  1388. qsort(pl->songs.GetAll(),pl->songs.GetSize(),sizeof(void*),sortFunc);
  1389. pl->modified = true;
  1390. }
  1391. void P4SDevice::playlistSwapItems(int playlistnumber, int posA, int posB) {
  1392. if(playlistnumber == -1) return;
  1393. Playlist * pl = (Playlist*)playlists.Get(playlistnumber);
  1394. if(posA >= pl->songs.GetSize() || posB >= pl->songs.GetSize()) return;
  1395. void * a = pl->songs.Get(posA);
  1396. void * b = pl->songs.Get(posB);
  1397. pl->songs.Set(posA,b);
  1398. pl->songs.Set(posB,a);
  1399. pl->modified=true;
  1400. }
  1401. void P4SDevice::addTrackToPlaylist(int playlistnumber, songid_t songid) {
  1402. if(playlistnumber == -1) return;
  1403. Playlist * pl = (Playlist*)playlists.Get(playlistnumber);
  1404. pl->songs.Add((void*)songid);
  1405. pl->modified=true;
  1406. }
  1407. void P4SDevice::removeTrackFromPlaylist(int playlistnumber, int songnum) {
  1408. if(playlistnumber == -1) return;
  1409. Playlist * pl = (Playlist*)playlists.Get(playlistnumber);
  1410. pl->songs.Del(songnum);
  1411. pl->modified=true;
  1412. }
  1413. void P4SDevice::deletePlaylist(int playlistnumber) {
  1414. if(playlistnumber == -1) return;
  1415. IWMDMStorageControl3 * storeControl;
  1416. Playlist * pl = (Playlist *)playlists.Get(playlistnumber);
  1417. pl->storage->QueryInterface(&storeControl);
  1418. storeControl->Delete(WMDM_MODE_BLOCK,NULL);
  1419. pl->meta->Release();
  1420. pl->storage->Release();
  1421. playlists.Del(playlistnumber);
  1422. storeControl->Release();
  1423. }
  1424. int P4SDevice::newPlaylist(const wchar_t *name) {
  1425. IWMDMStorageControl3 * storeControl;
  1426. if(!playlistsDir) return -1;
  1427. playlistsDir->QueryInterface(&storeControl);
  1428. DWORD dw=WMDM_FORMATCODE_ABSTRACTAUDIOVIDEOPLAYLIST;
  1429. IWMDMMetaData* meta = NULL;
  1430. int ret = -1;
  1431. if (SUCCEEDED(playlistsDir->CreateEmptyMetadataObject(&meta)) && meta)
  1432. {
  1433. meta->AddItem(WMDM_TYPE_DWORD, g_wszWMDMFormatCode, (BYTE *)&dw, sizeof(dw));
  1434. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)name,(wcslen(name)*2)+2);
  1435. IWMDMStorage * newpl=NULL;
  1436. wchar_t buffer[MAX_PATH] = {0};
  1437. wsprintf(buffer,L"%s.%s",name,plext);
  1438. storeControl->Insert3(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,0,NULL,buffer,NULL,NULL,meta,NULL,&newpl);
  1439. if(newpl) {
  1440. IWMDMStorage4 * newpl4=NULL;
  1441. newpl->QueryInterface(&newpl4);
  1442. Playlist * pl = new Playlist;
  1443. lstrcpyn(pl->name,name,128);
  1444. pl->storage = newpl4;
  1445. pl->modified = false;
  1446. pl->meta = meta;
  1447. playlists.Add(pl);
  1448. ret = playlists.GetSize() - 1;
  1449. newpl->Release();
  1450. }
  1451. }
  1452. storeControl->Release();
  1453. return ret;
  1454. }
  1455. void P4SDevice::getTrackArtist(songid_t songid, wchar_t * buf, int len) {
  1456. buf[0]=0;
  1457. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMAuthor);
  1458. if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
  1459. if(noMetadata || !b) {
  1460. if(!buf[0]) { // guess based upon file path
  1461. Song *s = (Song *)songid;
  1462. if(s->artist) {lstrcpyn(buf,s->artist,len);
  1463. return;
  1464. }
  1465. IWMDMStorage * p = NULL;
  1466. if(s->storage->GetParent(&p) == S_OK) {
  1467. IWMDMStorage * p2 = NULL;
  1468. IWMDMStorage4 * p3 = NULL;
  1469. if (SUCCEEDED(p->QueryInterface(&p3))) {
  1470. if(p3->GetParent(&p2) == S_OK) {
  1471. p2->GetName(buf,len);
  1472. p2->Release();
  1473. }
  1474. p3->Release();
  1475. }
  1476. p->Release();
  1477. }
  1478. }
  1479. }
  1480. }
  1481. void P4SDevice::getTrackAlbum(songid_t songid, wchar_t * buf, int len) {
  1482. buf[0]=0;
  1483. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMAlbumTitle);
  1484. if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
  1485. if(!b || noMetadata || ((Song*)songid)->video) {
  1486. if(!buf[0]) { // guess based upon file path
  1487. Song *s = (Song *)songid;
  1488. if(s->album) {lstrcpyn(buf,s->album,len); return;}
  1489. IWMDMStorage * p = NULL;
  1490. if(s->storage->GetParent(&p) == S_OK) {
  1491. p->GetName(buf,len);
  1492. p->Release();
  1493. }
  1494. }
  1495. }
  1496. if(buf[0] == L'~' && buf[1] == 0) buf[0]=0;
  1497. }
  1498. void P4SDevice::getTrackTitle(songid_t songid, wchar_t * buf, int len) {
  1499. buf[0]=0;
  1500. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMTitle);
  1501. if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
  1502. if(!b || noMetadata || ((Song*)songid)->video) {
  1503. if(!buf[0]) { // guess based upon file name
  1504. Song *s = (Song *)songid;
  1505. wchar_t buf2[256]=L"";
  1506. s->storage->GetName(buf2,256);
  1507. wchar_t * n = wcsrchr(buf2,L'-');
  1508. if(n) {
  1509. while(n && (*n == L'-' || *n == L' ' || *n == L'_' || *n == L'.')) n++;
  1510. lstrcpyn(buf,n,len);
  1511. } else lstrcpyn(buf,buf2,len);
  1512. }
  1513. wchar_t * ext = wcsrchr(buf,L'.');
  1514. if(ext) *ext=0;
  1515. }
  1516. }
  1517. void P4SDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len) {
  1518. buf[0]=0;
  1519. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMGenre);
  1520. if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
  1521. }
  1522. int P4SDevice::getTrackTrackNum(songid_t songid) {
  1523. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMTrack);
  1524. int r = b?(int)*((DWORD*)b):0; if(b) CoTaskMemFree(b);
  1525. if(r) return r;
  1526. if(!b || noMetadata) { // guess based upon file name
  1527. Song *s = (Song *)songid;
  1528. wchar_t buf2[256]=L"";
  1529. s->storage->GetName(buf2,256);
  1530. wchar_t * n = buf2; //wcschr(buf2,L'-');
  1531. while(n) {
  1532. while((*n == L'-' || *n == L' ' || *n == L'_' || *n == L'.') && *n) n++;
  1533. if(!n) break;
  1534. int m=0; while(*(n+m)>=L'0' && *(n+m)<=L'9') m++;
  1535. if(m == 2) { *(n+m)=0; return _wtoi(n); }
  1536. n = wcschr(n,L'-');
  1537. }
  1538. /*
  1539. wchar_t * n = wcschr(buf2,L'-');
  1540. if(n) {
  1541. *(n--)=0;
  1542. while((*n == L'-' || *n == L' ' || *n == L'_' || *n == L'.') && n > buf2) *(n--)=0;
  1543. return _wtoi(buf2);
  1544. }
  1545. */
  1546. }
  1547. return 0;
  1548. }
  1549. int P4SDevice::getTrackYear(songid_t songid) {
  1550. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMYear);
  1551. int r = b?_wtoi((wchar_t*)b):0; if(b) CoTaskMemFree(b); return r;
  1552. }
  1553. __int64 P4SDevice::getTrackSize(songid_t songid) {
  1554. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMFileSize);
  1555. int r = b?(int)*((__int64*)b):0; if(b) CoTaskMemFree(b);
  1556. if(r) return r;
  1557. DWORD high, low;
  1558. ((Song *)songid)->storage->GetSize(&low,&high);
  1559. ULARGE_INTEGER u;
  1560. u.HighPart = high;
  1561. u.LowPart = low;
  1562. return u.QuadPart;
  1563. }
  1564. int P4SDevice::getTrackLength(songid_t songid) {
  1565. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMDuration);
  1566. int r = b?(int)(*((__int64*)b)/10000):0; if(b) CoTaskMemFree(b); return r;
  1567. }
  1568. int P4SDevice::getTrackBitrate(songid_t songid) {
  1569. int len = getTrackLength(songid) / 8000;
  1570. return len?(int)(getTrackSize(songid)/1024) / len:0;
  1571. }
  1572. int P4SDevice::getTrackPlayCount(songid_t songid) {
  1573. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMPlayCount);
  1574. int r = b?(int)*((DWORD*)b):0; if(b) CoTaskMemFree(b); return r;
  1575. }
  1576. int P4SDevice::getTrackRating(songid_t songid) {
  1577. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMUserRating);
  1578. int r = b?(int)*((DWORD*)b):0; if(b) CoTaskMemFree(b); return r;
  1579. }
  1580. __time64_t P4SDevice::getTrackLastPlayed(songid_t songid) {
  1581. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMUserLastPlayTime);
  1582. __time64_t r = b?wmdmDateTimeToUnixTime((_WMDMDATETIME *)b):0; if(b) CoTaskMemFree(b); return r;
  1583. }
  1584. __time64_t P4SDevice::getTrackLastUpdated(songid_t songid) {
  1585. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMLastModifiedDate);
  1586. __time64_t r = b?wmdmDateTimeToUnixTime((_WMDMDATETIME *)b):0; if(b) CoTaskMemFree(b); return r;
  1587. }
  1588. void P4SDevice::getTrackAlbumArtist(songid_t songid, wchar_t * buf, int len) {
  1589. buf[0]=0;
  1590. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMAlbumArtist);
  1591. if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
  1592. if(!buf[0]) getTrackArtist(songid,buf,len);
  1593. }
  1594. void P4SDevice::getTrackComposer(songid_t songid, wchar_t * buf, int len) {
  1595. buf[0]=0;
  1596. BYTE * b = GetMetadataItem((Song *)songid,g_wszWMDMComposer);
  1597. if(b) { lstrcpyn(buf,(wchar_t*)b,len); CoTaskMemFree(b); }
  1598. }
  1599. int P4SDevice::getTrackType(songid_t songid) {
  1600. Song * s = (Song *)songid;
  1601. return s->video;
  1602. }
  1603. void P4SDevice::getTrackExtraInfo(songid_t songid, const wchar_t * field, wchar_t * buf, int len) {
  1604. if(!wcscmp(field,FIELD_EXTENSION)) {
  1605. Song * s = (Song *)songid;
  1606. wchar_t buf2[2048] = {0};
  1607. s->storage->GetName(buf2,2048);
  1608. wchar_t * ext = wcsrchr(buf2,L'.');
  1609. if(ext) { ext++; lstrcpyn(buf,ext,len); }
  1610. }
  1611. }
  1612. void P4SDevice::PreCommit(Song * s) {
  1613. if(!lastChange) lastChange = s;
  1614. else if(s != lastChange) {
  1615. if(lastChange->modified) {
  1616. lastChange->storage->SetMetadata(lastChange->meta);
  1617. lastChange->meta->Release();
  1618. lastChange->storage->GetMetadata(&lastChange->meta);
  1619. lastChange->modified = false;
  1620. }
  1621. lastChange = s;
  1622. }
  1623. }
  1624. void P4SDevice::setTrackArtist(songid_t songid, const wchar_t * value) {
  1625. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAuthor,(BYTE*)value,wcslen(value)*2+2);
  1626. ((Song*)songid)->modified=true;
  1627. PreCommit((Song*)songid);
  1628. }
  1629. void P4SDevice::setTrackAlbum(songid_t songid, const wchar_t * value) {
  1630. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)value,wcslen(value)*2+2);
  1631. ((Song*)songid)->modified=true;
  1632. PreCommit((Song*)songid);
  1633. }
  1634. void P4SDevice::setTrackTitle(songid_t songid, const wchar_t * value) {
  1635. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)value,wcslen(value)*2+2);
  1636. ((Song*)songid)->modified=true;
  1637. PreCommit((Song*)songid);
  1638. }
  1639. void P4SDevice::setTrackGenre(songid_t songid, const wchar_t * value) {
  1640. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)value,wcslen(value)*2+2);
  1641. ((Song*)songid)->modified=true;
  1642. PreCommit((Song*)songid);
  1643. }
  1644. void P4SDevice::setTrackTrackNum(songid_t songid, int value) {
  1645. ((Song*)songid)->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMTrack,(BYTE*)&value,sizeof(DWORD));
  1646. ((Song*)songid)->modified=true;
  1647. PreCommit((Song*)songid);
  1648. }
  1649. void P4SDevice::setTrackYear(songid_t songid, int value) {
  1650. wchar_t buf[10] = {0}; wsprintf(buf,L"%d",value);
  1651. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMYear,(BYTE*)buf,wcslen(buf)*2+2);
  1652. ((Song*)songid)->modified=true;
  1653. PreCommit((Song*)songid);
  1654. }
  1655. void P4SDevice::setTrackPlayCount(songid_t songid, int value) {
  1656. ((Song*)songid)->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMPlayCount,(BYTE*)&value,sizeof(DWORD));
  1657. ((Song*)songid)->modified=true;
  1658. PreCommit((Song*)songid);
  1659. }
  1660. void P4SDevice::setTrackRating(songid_t songid, int value) {
  1661. ((Song*)songid)->meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMUserRating,(BYTE*)&value,sizeof(DWORD));
  1662. ((Song*)songid)->modified=true;
  1663. PreCommit((Song*)songid);
  1664. }
  1665. void P4SDevice::setTrackLastPlayed(songid_t songid, __time64_t value) {
  1666. _WMDMDATETIME time={0};
  1667. getTime(value,&time);
  1668. ((Song*)songid)->meta->AddItem(WMDM_TYPE_DATE,g_wszWMDMUserLastPlayTime,(BYTE*)&time,sizeof(_WMDMDATETIME));
  1669. ((Song*)songid)->modified=true;
  1670. PreCommit((Song*)songid);
  1671. }
  1672. void P4SDevice::setTrackLastUpdated(songid_t songid, __time64_t value) {
  1673. _WMDMDATETIME time={0};
  1674. getTime(value,&time);
  1675. ((Song*)songid)->meta->AddItem(WMDM_TYPE_DATE,g_wszWMDMLastModifiedDate,(BYTE*)&time,sizeof(_WMDMDATETIME));
  1676. ((Song*)songid)->modified=true;
  1677. PreCommit((Song*)songid);
  1678. }
  1679. void P4SDevice::setTrackAlbumArtist(songid_t songid, const wchar_t * value) {
  1680. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)value,wcslen(value)*2+2);
  1681. ((Song*)songid)->modified=true;
  1682. PreCommit((Song*)songid);
  1683. }
  1684. void P4SDevice::setTrackComposer(songid_t songid, const wchar_t * value) {
  1685. ((Song*)songid)->meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMComposer,(BYTE*)value,wcslen(value)*2+2);
  1686. ((Song*)songid)->modified=true;
  1687. PreCommit((Song*)songid);
  1688. }
  1689. int P4SDevice::copyToHardDrive(songid_t s,wchar_t * path,void * callbackContext,void (*callback)(void * callbackContext, wchar_t * status),int * killswitch)
  1690. {
  1691. callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_WAITING));
  1692. EnterCriticalSection(&csTransfers);
  1693. Song * song = (Song*)s;
  1694. IWMDMStorageControl * control;
  1695. if (!SUCCEEDED(song->storage->QueryInterface(&control))) {
  1696. callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_FAILED));
  1697. return -1;
  1698. }
  1699. wchar_t fn[2084] = {0};
  1700. wchar_t *ext = 0;
  1701. if(SUCCEEDED(song->storage->GetName(fn,2084)) && (ext=wcsrchr(fn,L'.'))!=0)
  1702. wcscat(path,ext);
  1703. int ret=-1;
  1704. callback(callbackContext,WASABI_API_LNGSTRINGW(IDS_TRANSFERRING));
  1705. TransferItem t={0};
  1706. t.callback = callback;
  1707. t.callbackContext = callbackContext;
  1708. t.killswitch = killswitch;
  1709. t.progress = new MyProgress(&t);
  1710. if(SUCCEEDED(control->Read(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,path,t.progress,NULL))) ret=0;
  1711. control->Release();
  1712. t.progress->Release();
  1713. callback(callbackContext,WASABI_API_LNGSTRINGW((ret==0?IDS_DONE:IDS_FAILED)));
  1714. LeaveCriticalSection(&csTransfers);
  1715. return ret;
  1716. }
  1717. static IWMDMStorage4* getAlb(P4SDevice * dev, songid_t songid, bool create) {
  1718. wchar_t alb[1024] = {0};
  1719. dev->getTrackAlbum(songid,alb,1020);
  1720. StringCchCat(alb, ARRAYSIZE(alb), L".alb");
  1721. Song * song = (Song*)songid;
  1722. IWMDMStorage * album0=NULL;
  1723. IWMDMStorage * parent=NULL;
  1724. IWMDMStorage4 * parent4=NULL;
  1725. IWMDMStorage4 * album4=NULL;
  1726. song->storage->GetParent(&parent);
  1727. if (parent)
  1728. {
  1729. parent->QueryInterface(&parent4);
  1730. parent->Release();
  1731. if (parent4)
  1732. {
  1733. parent4->GetStorage(alb,&album0);
  1734. //parent4->Release();
  1735. if(album0) {
  1736. album0->QueryInterface(&album4);
  1737. album0->Release();
  1738. }
  1739. }
  1740. }
  1741. if(album4 || !create) { parent4->Release(); return album4; }
  1742. if(!parent4) return NULL;
  1743. // create my own
  1744. album0=0;
  1745. IWMDMStorageControl3 * storeControl=0;
  1746. parent4->QueryInterface(&storeControl);
  1747. if(storeControl) {
  1748. IWMDMMetaData * meta=0;
  1749. parent4->CreateEmptyMetadataObject(&meta);
  1750. if(meta) {
  1751. DWORD formatCode = WMDM_FORMATCODE_ABSTRACTAUDIOALBUM;
  1752. wchar_t album[256]=L"";
  1753. wchar_t artist[256]=L"";
  1754. wchar_t genre[256]=L"";
  1755. dev->getTrackAlbumArtist(songid,artist,256);
  1756. dev->getTrackAlbum(songid,album,256);
  1757. dev->getTrackGenre(songid,genre,256);
  1758. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMFormatCode,(BYTE*)&formatCode,sizeof(DWORD));
  1759. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumTitle,(BYTE*)album,(wcslen(album)*2)+2);
  1760. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMAlbumArtist,(BYTE*)artist,(wcslen(artist)*2)+2);
  1761. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMTitle,(BYTE*)album,(wcslen(album)*2)+2);
  1762. meta->AddItem(WMDM_TYPE_STRING,g_wszWMDMGenre,(BYTE*)genre,(wcslen(genre)*2)+2);
  1763. storeControl->Insert3(WMDM_MODE_BLOCK | WMDM_CONTENT_FILE,0,NULL,alb,NULL,NULL,meta,NULL,&album0);
  1764. meta->Release();
  1765. }
  1766. storeControl->Release();
  1767. }
  1768. parent4->Release();
  1769. if(album0) {
  1770. album0->QueryInterface(&album4);
  1771. album0->Release();
  1772. return album4;
  1773. }
  1774. return NULL;
  1775. }
  1776. void P4SDevice::setArt(songid_t songid, void *buf, int w, int h) { //buf is in format ARGB32*
  1777. if(!songid) return;
  1778. Song * s = (Song *)songid;
  1779. IWMDMStorage4 * album = s->alb;
  1780. if(!album) {
  1781. album = getAlb(this,songid,true);
  1782. if(!album) return;
  1783. s->alb = album;
  1784. s->albmeta = NULL;
  1785. s->alb->GetMetadata(&s->albmeta);
  1786. if(!s->albmeta) return;
  1787. }
  1788. IWMDMMetaData *meta=s->albmeta;
  1789. if(!meta) return;
  1790. IWMDMMetaData *meta2 = ((Song*)songid)->meta;
  1791. if(meta || meta2) {
  1792. if(buf) {
  1793. SkinBitmap art((ARGB32*)buf,w,h);
  1794. w=h=120;
  1795. BltCanvas artc(w,h);
  1796. art.stretch(&artc,0,0,w,h);
  1797. const GUID JPEGwriteguid = { 0x7bc27468, 0x475, 0x4c0d, { 0xae, 0xed, 0xc, 0x51, 0x19, 0x5d, 0xc2, 0xea } };
  1798. svc_imageWriter* jpgWrite=NULL;
  1799. waServiceFactory *sf = plugin.service->service_getServiceByGuid(JPEGwriteguid);
  1800. if(sf) jpgWrite = (svc_imageWriter*)sf->getInterface();
  1801. if(jpgWrite) {
  1802. int length=0;
  1803. void *jpeg = jpgWrite->convert(artc.getBits(),32,w,h,&length);
  1804. if(jpeg) {
  1805. DWORD fmt = WMDM_FORMATCODE_IMAGE_EXIF; // this is the formatcode for jpeg, apparently.
  1806. if(meta) {
  1807. meta->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)jpeg,length);
  1808. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)&w,sizeof(DWORD));
  1809. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)&h,sizeof(DWORD));
  1810. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)&length,sizeof(DWORD));
  1811. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)&fmt,sizeof(DWORD));
  1812. }
  1813. if(meta2) {
  1814. meta2->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)jpeg,length);
  1815. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)&w,sizeof(DWORD));
  1816. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)&h,sizeof(DWORD));
  1817. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)&length,sizeof(DWORD));
  1818. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)&fmt,sizeof(DWORD));
  1819. }
  1820. WASABI_API_MEMMGR->sysFree(jpeg);
  1821. }
  1822. if (sf) sf->releaseInterface(jpgWrite);
  1823. }
  1824. } else { // remove art
  1825. if(meta) {
  1826. meta->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)0,0);
  1827. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)0,0);
  1828. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)0,0);
  1829. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)0,0);
  1830. meta->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)0,0);
  1831. }
  1832. if(meta2) {
  1833. meta2->AddItem(WMDM_TYPE_BINARY,g_wszWMDMAlbumCoverData,(BYTE*)0,0);
  1834. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverWidth,(BYTE*)0,0);
  1835. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverHeight,(BYTE*)0,0);
  1836. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverSize,(BYTE*)0,0);
  1837. meta2->AddItem(WMDM_TYPE_DWORD,g_wszWMDMAlbumCoverFormat,(BYTE*)0,0);
  1838. }
  1839. }
  1840. if(meta) {
  1841. album->SetMetadata(meta);
  1842. }
  1843. }
  1844. ((Song*)songid)->modified=true;
  1845. PreCommit((Song*)songid);
  1846. /*
  1847. g_wszWMDMAlbumCoverData Album art JPEG byte blob WMDM_TYPE_BINARY BYTE*
  1848. g_wszWMDMAlbumCoverDuration Album cover duration WMDM_TYPE_DWORD DWORD
  1849. g_wszWMDMAlbumCoverFormat Album art format WMDM_TYPE_DWORD DWORD
  1850. g_wszWMDMAlbumCoverHeight Album art height WMDM_TYPE_DWORD DWORD
  1851. g_wszWMDMAlbumCoverSize Album art size WMDM_TYPE_DWORD DWORD
  1852. g_wszWMDMAlbumCoverWidth Album art width WMDM_TYPE_DWORD DWORD
  1853. */
  1854. }
  1855. class Art {
  1856. public:
  1857. Art(void * jpegData, int jpegDataLen, int w, int h) : jpegData(jpegData), jpegDataLen(jpegDataLen), w(w), h(h), data(0), resized(0) {
  1858. }
  1859. ~Art() {
  1860. CoTaskMemFree(jpegData);
  1861. if(data) WASABI_API_MEMMGR->sysFree(data); data=0;
  1862. }
  1863. ARGB32 * GetImage() {
  1864. if(data) return data;
  1865. const GUID JPEGguid = { 0xae04fb30, 0x53f5, 0x4032, { 0xbd, 0x29, 0x3, 0x2b, 0x87, 0xec, 0x34, 0x04 } };
  1866. svc_imageLoader* jpgLoad=NULL;
  1867. waServiceFactory *sf = plugin.service->service_getServiceByGuid(JPEGguid);
  1868. if(sf) jpgLoad = (svc_imageLoader*)sf->getInterface();
  1869. if(jpgLoad) {
  1870. data = jpgLoad->loadImage(jpegData,jpegDataLen,&w,&h);
  1871. if (sf) sf->releaseInterface(jpgLoad);
  1872. }
  1873. resized=0;
  1874. return data;
  1875. }
  1876. int resized;
  1877. void Resize(int width, int height) {
  1878. if(w == width && h == height) return;
  1879. if(resized) {
  1880. if(data) WASABI_API_MEMMGR->sysFree(data);
  1881. data=0;
  1882. resized=0;
  1883. }
  1884. GetImage();
  1885. if(!data) return;
  1886. SkinBitmap temp(data,w,h);
  1887. BltCanvas newImage(width,height);
  1888. temp.stretch(&newImage,0,0,width,height);
  1889. w=width;
  1890. h=height;
  1891. WASABI_API_MEMMGR->sysFree(data);
  1892. data = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(w*h*sizeof(ARGB32));
  1893. memcpy(data,newImage.getBits(),w*h*sizeof(ARGB32));
  1894. resized=1;
  1895. }
  1896. int getWidth() {return w;}
  1897. int getHeight() {return h;}
  1898. int cmp(Art * art) {
  1899. if(art->jpegDataLen != jpegDataLen) return art->jpegDataLen - jpegDataLen;
  1900. return memcmp(art->jpegData,jpegData,jpegDataLen);
  1901. }
  1902. protected:
  1903. void * jpegData;
  1904. int jpegDataLen;
  1905. int w,h;
  1906. ARGB32 *data;
  1907. };
  1908. pmpart_t P4SDevice::getArt(songid_t songid) {
  1909. if(!songid) return NULL;
  1910. Song* s = (Song*)songid;
  1911. WMDM_TAG_DATATYPE type;
  1912. BYTE * data=NULL;
  1913. UINT length=0;
  1914. IWMDMMetaData *meta = s->albmeta;
  1915. if(!meta) return NULL;
  1916. HRESULT hr = meta->QueryByName(g_wszWMDMAlbumCoverData,&type,&data,&length);
  1917. if(hr == S_OK && data && length) {
  1918. BYTE * b = GetMetadataItem(meta,g_wszWMDMAlbumCoverWidth);
  1919. int w = b?(int)*((DWORD*)b):0;
  1920. if(b) CoTaskMemFree(b);
  1921. b = GetMetadataItem(meta,g_wszWMDMAlbumCoverHeight);
  1922. int h = b?(int)*((DWORD*)b):0;
  1923. if(b) CoTaskMemFree(b);
  1924. //meta->Release();
  1925. if(!w) w=120; // this happens if the device doesn't store the w and h of the image.
  1926. if(!h) h=120; // but it's ok, cause the real values are in the jpeg data, and these can just be a guide.
  1927. return (pmpart_t) new Art(data,length,w,h);
  1928. }
  1929. //meta->Release();
  1930. if(data) CoTaskMemFree(data);
  1931. return NULL;
  1932. }
  1933. void P4SDevice::releaseArt(pmpart_t art) {
  1934. if(art) delete ((Art *)art);
  1935. }
  1936. int P4SDevice::drawArt(pmpart_t art0, HDC dc, int x, int y, int w, int h) {
  1937. Art* art = (Art*)art0;
  1938. if(!art) return 0;
  1939. ARGB32 * d = art->GetImage();
  1940. if(!d) return 0;
  1941. SkinBitmap(d, art->getWidth(), art->getHeight()).stretch(&DCCanvas(dc),x,y,w,h); // wrap into a SkinBitmap (no copying involved)
  1942. return 1;
  1943. }
  1944. void P4SDevice::getArtNaturalSize(pmpart_t art0, int *w, int *h) {
  1945. Art* art = (Art*)art0;
  1946. *w=art->getWidth();
  1947. *h=art->getWidth();
  1948. if(*w==0 || *h==0) *w=*h=120;
  1949. }
  1950. void P4SDevice::setArtNaturalSize(pmpart_t art0, int w, int h) {
  1951. Art* art = (Art*)art0;
  1952. art->Resize(w,h);
  1953. }
  1954. void P4SDevice::getArtData(pmpart_t art0, void* data) { // data ARGB32* is at natural size
  1955. Art* art = (Art*)art0;
  1956. int w,h;
  1957. getArtNaturalSize(art0,&w,&h);
  1958. setArtNaturalSize(art0,w,h);
  1959. ARGB32 * d = art->GetImage();
  1960. if(d) memcpy(data,d,w*h*sizeof(ARGB32));
  1961. }
  1962. bool P4SDevice::artIsEqual(pmpart_t a, pmpart_t b) {
  1963. if(!a || !b) return false;
  1964. return ((Art*)a)->cmp((Art*)b) == 0;
  1965. }
  1966. extern void checkForDevices();
  1967. intptr_t P4SDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4) {
  1968. switch(param1) {
  1969. case DEVICE_SET_ICON: // icons
  1970. {
  1971. MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
  1972. if(wcsstr(name,L"Zen")) {
  1973. i->hinst = plugin.hDllInstance;
  1974. i->resourceId = IDR_CREATIVE_ZEN_ICON;
  1975. } else if (wcsstr(name,L"Nokia")) {
  1976. i->hinst = plugin.hDllInstance;
  1977. i->resourceId = IDR_NOKIA_ICON;
  1978. }
  1979. break;
  1980. }
  1981. case DEVICE_SUPPORTED_METADATA:
  1982. return noMetadata ? 0x8f : (0xffef | (requiresALB?SUPPORTS_ALBUMART:0));
  1983. case DEVICE_DOES_NOT_SUPPORT_EDITING_METADATA:
  1984. return noMetadata ? 1 : 0;
  1985. case DEVICE_REFRESH:
  1986. {
  1987. bool nm = noMetadata;
  1988. IWMDMDevice3* d = WMDevice;
  1989. d->AddRef();
  1990. Close();
  1991. new P4SDevice(d,nm);
  1992. d->Release();
  1993. }
  1994. return 0;
  1995. case DEVICE_SUPPORTS_VIDEO:
  1996. return 1;
  1997. case DEVICE_GET_ICON:
  1998. {
  1999. if (param2 <= 16 && param3 <= 16)
  2000. {
  2001. int resourceId;
  2002. wchar_t *buffer;
  2003. if(wcsstr(name,L"Zen"))
  2004. resourceId = IDR_CREATIVE_ZEN_ICON;
  2005. else if (wcsstr(name,L"Nokia"))
  2006. resourceId = IDR_NOKIA_ICON;
  2007. else
  2008. resourceId = 0;
  2009. buffer = (wchar_t *)param4;
  2010. if (NULL != buffer &&
  2011. FALSE == FormatResProtocol(MAKEINTRESOURCE(resourceId), RT_RCDATA, buffer, 260))
  2012. {
  2013. buffer[0] = L'\0';
  2014. }
  2015. }
  2016. }
  2017. break;
  2018. }
  2019. return 0;
  2020. }