367 lines
11 KiB
C++
367 lines
11 KiB
C++
|
#include "main.h"
|
||
|
#include "api__ml_iso.h"
|
||
|
#include <api/service/waservicefactory.h>
|
||
|
#include "../burner/obj_isocreator.h"
|
||
|
#include "../playlist/ifc_playlistloadercallback.h"
|
||
|
#include <shlwapi.h>
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
/**
|
||
|
** Playlist Loader callback class
|
||
|
** Used when this plugin loads a playlist file
|
||
|
** the playlist loader will call the OnFile() function
|
||
|
** for each playlist item
|
||
|
*/
|
||
|
class ISOPlaylistLoader : public ifc_playlistloadercallback
|
||
|
{
|
||
|
public:
|
||
|
ISOPlaylistLoader(obj_isocreator *_creator);
|
||
|
|
||
|
protected:
|
||
|
RECVS_DISPATCH;
|
||
|
|
||
|
private:
|
||
|
void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
|
||
|
obj_isocreator *creator;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
** helper function
|
||
|
** for getting a filename location
|
||
|
** of where to save the ISO file
|
||
|
**/
|
||
|
static bool PromptForFilename(wchar_t *filename, size_t filenameCch)
|
||
|
{
|
||
|
wchar_t oldCurPath[MAX_PATH], newCurPath[MAX_PATH];
|
||
|
OPENFILENAMEW openfilename;
|
||
|
|
||
|
// null terminate the string or else we'll get a garbage filename as the 'default' filename
|
||
|
filename[0]=0;
|
||
|
|
||
|
// GetSaveFileName changes Window's working directory
|
||
|
// which locks that folder from being deleted until Winamp closes
|
||
|
// so we save the old working directory name
|
||
|
// and restore it on complete
|
||
|
// Winamp maintains its own concept of a working directory
|
||
|
// to help us avoid this problem
|
||
|
GetCurrentDirectoryW(MAX_PATH, oldCurPath);
|
||
|
|
||
|
|
||
|
// initialize the open file name struct
|
||
|
openfilename.lStructSize = sizeof(openfilename);
|
||
|
openfilename.hwndOwner = plugin.hwndLibraryParent;
|
||
|
openfilename.hInstance = plugin.hDllInstance;
|
||
|
openfilename.lpstrFilter = L"ISO Files\0*.iso\0";
|
||
|
openfilename.lpstrCustomFilter = 0;
|
||
|
openfilename.nMaxCustFilter = 0;
|
||
|
openfilename.nFilterIndex = 0;
|
||
|
openfilename.lpstrFile = filename;
|
||
|
openfilename.nMaxFile = filenameCch;
|
||
|
openfilename.lpstrFileTitle = 0;
|
||
|
openfilename.nMaxFileTitle = 0;
|
||
|
// we set the initial directory based on winamp's working path
|
||
|
openfilename.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
|
||
|
openfilename.lpstrTitle = 0;
|
||
|
// despite the big note about working directory
|
||
|
// we don't want to use OFN_NOCHANGEDIR
|
||
|
// because we're going to manually sync Winamp's working path
|
||
|
openfilename.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_LONGNAMES;
|
||
|
openfilename.nFileOffset = 0;
|
||
|
openfilename.nFileExtension = 0;
|
||
|
openfilename.lpstrDefExt = L".iso";
|
||
|
openfilename.lCustData = 0;
|
||
|
openfilename.lpfnHook = 0;
|
||
|
openfilename.lpTemplateName = 0;
|
||
|
|
||
|
if (GetSaveFileNameW(&openfilename))
|
||
|
{
|
||
|
// let's re-synch Winamp's working directory
|
||
|
GetCurrentDirectoryW(MAX_PATH, newCurPath);
|
||
|
WASABI_API_APP->path_setWorkingPath(newCurPath);
|
||
|
|
||
|
// set the old path back
|
||
|
SetCurrentDirectoryW(oldCurPath);
|
||
|
return true; // success!
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// set the old path back
|
||
|
SetCurrentDirectoryW(oldCurPath);
|
||
|
return false; // user hit cancel or something else happened
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
** helper functions
|
||
|
** for creating and deleting
|
||
|
** an iso creator object
|
||
|
** through the wasabi service manager
|
||
|
**/
|
||
|
static obj_isocreator *CreateISOCreator()
|
||
|
{
|
||
|
waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(obj_isocreatorGUID);
|
||
|
if (factory)
|
||
|
return (obj_isocreator *)factory->getInterface();
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void ReleaseISOCreator(obj_isocreator *creator)
|
||
|
{
|
||
|
if (creator)
|
||
|
{
|
||
|
waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(obj_isocreatorGUID);
|
||
|
if (factory)
|
||
|
factory->releaseInterface(creator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ConvertItemRecordListToISO(const itemRecordList *list)
|
||
|
{
|
||
|
obj_isocreator *isocreator = CreateISOCreator();
|
||
|
if (isocreator)
|
||
|
{
|
||
|
wchar_t destination[MAX_PATH];
|
||
|
|
||
|
if (PromptForFilename(destination, MAX_PATH))
|
||
|
{
|
||
|
// these values are hardcoded for this example.
|
||
|
isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
|
||
|
|
||
|
char destinationPath[MAX_PATH];
|
||
|
|
||
|
// loop through the files and add them
|
||
|
for (int i=0;i<list->Size;i++)
|
||
|
{
|
||
|
itemRecord &item = list->Items[i];
|
||
|
|
||
|
// since we have metadata, we're going to auto-generate folders based on the album name
|
||
|
const char *album = item.album;
|
||
|
if (!album || !*album)
|
||
|
album = "Unknown Album";
|
||
|
|
||
|
// isocreator requires a preceding backslash
|
||
|
StringCbPrintfA(destinationPath, sizeof(destinationPath), "\\%s\\%s", album, PathFindFileNameA(item.filename));
|
||
|
|
||
|
// convert to unicode since that's what obj_isocreator requires
|
||
|
wchar_t unicodeSource[MAX_PATH];
|
||
|
wchar_t unicodeDest[MAX_PATH];
|
||
|
MultiByteToWideChar(CP_ACP, 0, item.filename, -1, unicodeSource, MAX_PATH);
|
||
|
MultiByteToWideChar(CP_ACP, 0, destinationPath, -1, unicodeDest, MAX_PATH);
|
||
|
isocreator->AddFile(unicodeSource, unicodeDest);
|
||
|
}
|
||
|
|
||
|
isocreator->Write(destination, 0);
|
||
|
}
|
||
|
ReleaseISOCreator(isocreator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ConvertFilenamesToISO(const char *filenames)
|
||
|
{
|
||
|
obj_isocreator *isocreator = CreateISOCreator();
|
||
|
if (isocreator)
|
||
|
{
|
||
|
wchar_t destination[MAX_PATH];
|
||
|
|
||
|
if (PromptForFilename(destination, MAX_PATH))
|
||
|
{
|
||
|
// these values are hardcoded for this example.
|
||
|
isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
|
||
|
|
||
|
wchar_t destinationPath[MAX_PATH];
|
||
|
|
||
|
// loop through the files and add them
|
||
|
while (*filenames)
|
||
|
{
|
||
|
/**
|
||
|
** both playlist loader and iso creator want unicode filenames
|
||
|
** so we'll convert it first
|
||
|
*/
|
||
|
wchar_t unicodeFilename[MAX_PATH];
|
||
|
MultiByteToWideChar(CP_ACP, 0, filenames, -1, unicodeFilename, MAX_PATH);
|
||
|
|
||
|
/**
|
||
|
** see if this file is a playlist file
|
||
|
** we'll do that by trying to load it
|
||
|
** the Load() function will fail gracefully if it's not a playlist file
|
||
|
** if it succeeds, it will call loader.OnFile() which adds it to the iso file
|
||
|
**/
|
||
|
ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
|
||
|
if (AGAVE_API_PLAYLISTMANAGER->Load(unicodeFilename, &loader) == PLAYLISTMANAGER_LOAD_NO_LOADER)
|
||
|
{
|
||
|
// not a playlist file, so load it normally
|
||
|
|
||
|
// isocreator requires a preceding backslash
|
||
|
StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s", PathFindFileNameW(unicodeFilename));
|
||
|
|
||
|
isocreator->AddFile(unicodeFilename, destinationPath);
|
||
|
}
|
||
|
filenames+=strlen(filenames)+1;
|
||
|
}
|
||
|
isocreator->Write(destination, 0);
|
||
|
}
|
||
|
ReleaseISOCreator(isocreator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
** Load Playlist and write it to the ISO file
|
||
|
** this function is a bit complex, since we have to load the playlist
|
||
|
** through api_playlistmanager. This involves creating an playlist loader callback
|
||
|
** (ifc_playlistloadercallback) which gets called for each playlist item
|
||
|
**/
|
||
|
void ConvertPlaylistToISO(const mlPlaylist *playlist)
|
||
|
{
|
||
|
obj_isocreator *isocreator = CreateISOCreator();
|
||
|
if (isocreator)
|
||
|
{
|
||
|
wchar_t destination[MAX_PATH];
|
||
|
|
||
|
if (PromptForFilename(destination, MAX_PATH))
|
||
|
{
|
||
|
// these values are hardcoded for this example.
|
||
|
const wchar_t *title=L"WinampISO";
|
||
|
if (playlist->title) // if there's a playlist title, use it as the volume name
|
||
|
title = playlist->title;
|
||
|
|
||
|
isocreator->Open(title, obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
|
||
|
|
||
|
ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
|
||
|
AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
|
||
|
|
||
|
isocreator->Write(destination, 0);
|
||
|
}
|
||
|
ReleaseISOCreator(isocreator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Load all playlists and write them to the ISO file
|
||
|
** this function is a bit complex, since we have to load the playlist
|
||
|
** through api_playlistmanager. This involves creating an playlist loader callback
|
||
|
** (ifc_playlistloadercallback) which gets called for each playlist item
|
||
|
**/
|
||
|
void ConvertPlaylistsToISO(const mlPlaylist **playlists)
|
||
|
{
|
||
|
obj_isocreator *isocreator = CreateISOCreator();
|
||
|
if (isocreator)
|
||
|
{
|
||
|
wchar_t destination[MAX_PATH];
|
||
|
|
||
|
if (PromptForFilename(destination, MAX_PATH))
|
||
|
{
|
||
|
// these values are hardcoded for this example.
|
||
|
isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
|
||
|
while (*playlists)
|
||
|
{
|
||
|
const mlPlaylist *playlist = *playlists;
|
||
|
ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
|
||
|
AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
|
||
|
playlists++;
|
||
|
}
|
||
|
isocreator->Write(destination, 0);
|
||
|
}
|
||
|
ReleaseISOCreator(isocreator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ConvertUnicodeItemRecordListToISO(const itemRecordListW *list)
|
||
|
{
|
||
|
obj_isocreator *isocreator = CreateISOCreator();
|
||
|
if (isocreator)
|
||
|
{
|
||
|
wchar_t destination[MAX_PATH];
|
||
|
|
||
|
if (PromptForFilename(destination, MAX_PATH))
|
||
|
{
|
||
|
// these values are hardcoded for this example.
|
||
|
isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
|
||
|
|
||
|
wchar_t destinationPath[MAX_PATH];
|
||
|
|
||
|
// loop through the files and add them
|
||
|
for (int i=0;i<list->Size;i++)
|
||
|
{
|
||
|
itemRecordW &item = list->Items[i];
|
||
|
|
||
|
// since we have metadata, we're going to auto-generate folders based on the album name
|
||
|
const wchar_t *album = item.album;
|
||
|
if (!album || !*album)
|
||
|
album = L"Unknown Album";
|
||
|
|
||
|
// isocreator requires a preceding backslash
|
||
|
StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s\\%s", album, PathFindFileNameW(item.filename));
|
||
|
|
||
|
isocreator->AddFile(item.filename, destinationPath);
|
||
|
}
|
||
|
isocreator->Write(destination, 0);
|
||
|
}
|
||
|
ReleaseISOCreator(isocreator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ConvertUnicodeFilenamesToISO(const wchar_t *filenames)
|
||
|
{
|
||
|
obj_isocreator *isocreator = CreateISOCreator();
|
||
|
if (isocreator)
|
||
|
{
|
||
|
wchar_t destination[MAX_PATH];
|
||
|
|
||
|
if (PromptForFilename(destination, MAX_PATH))
|
||
|
{
|
||
|
// these values are hardcoded for this example.
|
||
|
isocreator->Open(L"WinampISO", obj_isocreator::FORMAT_JOLIET, obj_isocreator::MEDIA_CD);
|
||
|
|
||
|
wchar_t destinationPath[MAX_PATH];
|
||
|
|
||
|
// loop through the files and add them
|
||
|
while (*filenames)
|
||
|
{
|
||
|
/**
|
||
|
** see if this file is a playlist file
|
||
|
** we'll do that by trying to load it
|
||
|
** the Load() function will fail gracefully if it's not a playlist file
|
||
|
** if it succeeds, it will call loader.OnFile() which adds it to the iso file
|
||
|
**/
|
||
|
ISOPlaylistLoader loader(isocreator); // make a callback object for playlist loading
|
||
|
if (AGAVE_API_PLAYLISTMANAGER->Load(filenames, &loader) == PLAYLISTMANAGER_LOAD_NO_LOADER)
|
||
|
{
|
||
|
// not a playlist file, so load it normally
|
||
|
|
||
|
// isocreator requires a preceding backslash
|
||
|
StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s", PathFindFileNameW(filenames));
|
||
|
|
||
|
isocreator->AddFile(filenames, destinationPath);
|
||
|
}
|
||
|
filenames+=wcslen(filenames)+1;
|
||
|
}
|
||
|
|
||
|
isocreator->Write(destination, 0);
|
||
|
}
|
||
|
ReleaseISOCreator(isocreator);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* --- Playlist Loader definition --- */
|
||
|
ISOPlaylistLoader::ISOPlaylistLoader(obj_isocreator *_creator)
|
||
|
{
|
||
|
creator=_creator;
|
||
|
}
|
||
|
|
||
|
void ISOPlaylistLoader::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info)
|
||
|
{
|
||
|
// isocreator requires a preceding backslash
|
||
|
wchar_t destinationPath[MAX_PATH];
|
||
|
StringCbPrintfW(destinationPath, sizeof(destinationPath), L"\\%s", PathFindFileNameW(filename));
|
||
|
// add file to .iso image
|
||
|
creator->AddFile(filename, destinationPath);
|
||
|
}
|
||
|
|
||
|
#define CBCLASS ISOPlaylistLoader
|
||
|
START_DISPATCH;
|
||
|
VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
|
||
|
//VCB(IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO, OnPlaylistInfo)
|
||
|
END_DISPATCH;
|