dolphin/Branches/MusicMod/Player/Src/Playlist.cpp

1348 lines
30 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// Plainamp, Open source Winamp core
//
// Copyright © 2005 Sebastian Pipping <webmaster@hartwork.org>
//
// --> http://www.hartwork.org
//
// This source code is released under the GNU General Public License (GPL).
// See GPL.txt for details. Any non-GPL usage is strictly forbidden.
////////////////////////////////////////////////////////////////////////////////
#include "Playlist.h"
#include "AddDirectory.h"
#include "Rebar.h"
#include "Main.h"
#include "Status.h"
#include "Console.h"
#include "Font.h"
#include "Playback.h"
#include "InputPlugin.h"
#include "Prefs.h"
#include "Config.h"
#include "Unicode.h"
#include "Path.h"
#include "commdlg.h"
HWND WindowPlaylist = NULL; // extern
// WNDPROC WndprocPlaylistBackup = NULL;
// int iCurIndex = -1;
// int iMaxIndex = -1;
// LRESULT CALLBACK WndprocPlaylist( HWND hwnd, UINT message, WPARAM wp, LPARAM lp );
void Playlist_SelectSingle( int iIndex );
struct PlaylistEntry
{
TCHAR * szFilename;
// More to come
};
/*
///////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Playlist::GetCurIndex()
{
return iCurIndex;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Playlist::GetMaxIndex()
{
return iMaxIndex;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::SetCurIndex( int iIndex )
{
if( iIndex < 0 || iIndex > iMaxIndex ) return false;
iCurIndex = iIndex;
if( bPlaylistFollow )
{
Playlist_SelectSingle( iCurIndex );
}
return true;
}
*/
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::Create()
{
if( WindowPlaylist ) return false;
PlaylistView::Create();
/*
RECT ClientMain;
GetClientRect( WindowMain, &ClientMain );
const int iClientHeight = ClientMain.bottom - ClientMain.top;
const int iClientWidth = ClientMain.right - ClientMain.left;
const int iPlaylistHeight = iClientHeight - iRebarHeight - iStatusHeight;
WindowPlaylist = CreateWindowEx(
WS_EX_CLIENTEDGE,
TEXT( "LISTBOX" ),
NULL,
WS_VSCROLL |
LBS_DISABLENOSCROLL |
LBS_EXTENDEDSEL |
LBS_HASSTRINGS |
LBS_NOTIFY |
LBS_NOINTEGRALHEIGHT |
WS_CHILD |
WS_VISIBLE, //
0,
iRebarHeight, // + -2,
iClientWidth,
iPlaylistHeight,
WindowMain,
NULL,
g_hInstance,
NULL
);
// Exchange window procedure
WndprocPlaylistBackup = ( WNDPROC )GetWindowLong( WindowPlaylist, GWL_WNDPROC );
if( WndprocPlaylistBackup != NULL )
{
SetWindowLong( WindowPlaylist, GWL_WNDPROC, ( LONG )WndprocPlaylist );
}
*/
Font::Apply( WindowPlaylist );
TCHAR * szPlaylistMind = new TCHAR[ iHomeDirLen + 12 + 1 ];
memcpy( szPlaylistMind, szHomeDir, iHomeDirLen * sizeof( TCHAR ) );
memcpy( szPlaylistMind + iHomeDirLen, TEXT( "Plainamp.m3u" ), 12 * sizeof( TCHAR ) );
szPlaylistMind[ iHomeDirLen + 12 ] = TEXT( '\0' );
Playlist::AppendPlaylistFile( szPlaylistMind );
return true;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline void Playlist_SelectSingle( int iIndex )
{
SendMessage(
WindowPlaylist,
LB_SETSEL,
FALSE,
-1
);
SendMessage(
WindowPlaylist,
LB_SETSEL,
TRUE,
iIndex
);
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline bool Playlist_IsSelected( int iIndex )
{
return ( 0 != SendMessage(
WindowPlaylist,
LB_GETSEL,
( WPARAM )iIndex,
0
) );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline bool Playlist_SelectModify( int iIndex, bool bSelected )
{
return ( LB_ERR != SendMessage(
WindowPlaylist,
LB_SETSEL,
( WPARAM )( bSelected ? TRUE : FALSE ),
iIndex
) );
}
/*
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist_Remove( int iIndex )
{
if( iIndex < 0 || iIndex > iMaxIndex ) return false;
// Get entry data
PlaylistEntry * entry = ( PlaylistEntry * )SendMessage(
WindowPlaylist,
LB_GETITEMDATA,
iIndex,
0
);
// Free data
if( entry )
{
if( entry->szFilename ) delete [] entry->szFilename;
delete entry;
}
SendMessage(
WindowPlaylist,
LB_DELETESTRING,
iIndex,
0
);
if( iIndex < iCurIndex )
iCurIndex--;
if( ( iIndex == iCurIndex ) && ( iCurIndex == iMaxIndex ) )
iCurIndex = iMaxIndex - 1;
iMaxIndex--;
return true;
}
*/
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline int Playlist_GetCount()
{
return ( int )SendMessage(
WindowPlaylist,
LB_GETCOUNT,
0,
0
);
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline int Playlist_GetCaretIndex()
{
return ( int )SendMessage(
WindowPlaylist,
LB_GETCARETINDEX,
0,
0
);
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline bool Playlist_SetCaretIndex( int iIndex )
{
return ( LB_OKAY == SendMessage(
WindowPlaylist,
LB_SETCARETINDEX,
( WPARAM )iIndex,
FALSE
) );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
inline int Playlist_GetSelCount()
{
return ( int )SendMessage(
WindowPlaylist,
LB_GETSELCOUNT,
0,
0
);
}
/*
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Playlist_MouseToIndex()
{
POINT p;
GetCursorPos( &p );
ScreenToClient( WindowPlaylist, &p );
int iIndex = ( int )SendMessage(
WindowPlaylist,
LB_ITEMFROMPOINT,
0,
p.x | ( p.y << 16 )
);
if( ( iIndex < 0 ) || ( iIndex > iMaxIndex ) )
return -1;
else
return iIndex;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::Clear()
{
if( iMaxIndex < 0 ) return false;
int iCount = iMaxIndex + 1;
while( iCount-- )
{
Playlist_Remove( iCount );
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::RemoveSelected()
{
int iSelCount = Playlist_GetSelCount();
if( iSelCount < 0 ) return false;
// Which items are selected?
int * sel = new int[ iSelCount ];
LRESULT lResult = SendMessage(
WindowPlaylist,
LB_GETSELITEMS,
( WPARAM )iSelCount,
( LPARAM )sel
);
// Remove
if( lResult > 0 )
{
while( lResult-- )
{
int iIndex = sel[ lResult ];
Playlist_Remove( iIndex );
}
}
delete [] sel;
return true;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::Crop()
{
int iAllCount = Playlist_GetCount();
if( iAllCount < 1 ) return false;
int iSelCount = Playlist_GetSelCount();
if( iSelCount < 0 )
{
return false;
}
else if( iSelCount == 0 )
{
// None selected
return Clear();
}
// Which items are selected?
int * sel = new int[ iSelCount ];
LRESULT lResult = SendMessage(
WindowPlaylist,
LB_GETSELITEMS,
( WPARAM )iSelCount,
( LPARAM )sel
);
int iLowerEqualIndex = iSelCount - 1;
for( int i = iAllCount - 1; i >= 0; i-- )
{
while( ( sel[ iLowerEqualIndex ] > i ) && ( iLowerEqualIndex > 0 ) )
{
iLowerEqualIndex--;
}
if( i != sel[ iLowerEqualIndex ] )
{
// Not selected -> remove
Playlist_Remove( i );
}
}
delete [] sel;
return true;
}
*/
/*
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist_MoveSel( bool bUpOrDown )
{
static bool bMoving = false;
if( bMoving ) return false;
bMoving = true;
const int iSelCount = Playlist_GetSelCount();
if( iSelCount < 0 )
{
// No items selected
bMoving = false;
return false;
}
// Which items are selected?
int * sel = new int[ iSelCount ];
LRESULT lResult = SendMessage(
WindowPlaylist,
LB_GETSELITEMS,
( WPARAM )iSelCount,
( LPARAM )sel
);
if( lResult <= 0 )
{
// Nothing to move
delete [] sel;
bMoving = false;
return false;
}
if( ( bUpOrDown && ( sel[ 0 ] == 0 ) ) ||
( !bUpOrDown && ( sel[ iSelCount - 1 ] == iMaxIndex ) ) )
{
// Cannot move
delete [] sel;
bMoving = false;
return false;
}
const int iOldTop = ( int )SendMessage(
WindowPlaylist,
LB_GETTOPINDEX,
0,
0
);
// 1 _2_[3][4][5] 6 7 [8] 9
// --> 1 [3][4][5]_2_ 6 [8]_7_ 9
// Redrawing OFF
// SendMessage( WindowPlaylist, WM_SETREDRAW, ( WPARAM )FALSE, 0 );
int i = ( bUpOrDown ? 0 : iSelCount - 1 );
do
{
// Backup the jumper
PlaylistEntry * entry_old = ( PlaylistEntry * )SendMessage(
WindowPlaylist,
LB_GETITEMDATA,
sel[ i ] + ( bUpOrDown ? -1 : 1 ),
0
);
do
{
// Copy <n> on <n +/- 1>
PlaylistEntry * entry_new = ( PlaylistEntry * )SendMessage(
WindowPlaylist,
LB_GETITEMDATA,
sel[ i ],
0
);
int iDest = sel[ i ] + ( bUpOrDown ? -1 : 1 );
// Update entry display == delete, insert, set data
SendMessage(
WindowPlaylist,
LB_DELETESTRING,
iDest,
0
);
iDest = ( int )SendMessage(
WindowPlaylist,
LB_INSERTSTRING,
iDest,
( LPARAM )entry_new->szFilename
);
SendMessage(
WindowPlaylist,
LB_SETITEMDATA,
iDest,
( LPARAM )entry_new
);
if( sel[ i ] == iCurIndex )
{
iCurIndex += ( bUpOrDown ? -1 : 1 );
}
i += ( bUpOrDown ? 1 : -1 );
} while( bUpOrDown
?
( i < iSelCount ) && ( sel[ i - 1 ] + 1 == sel[ i ] )
:
( i >= 0 ) && ( sel[ i + 1 ] - 1 == sel[ i ] )
);
// Place the jumper
int iLast = ( bUpOrDown ? sel[ i - 1 ] : sel[ i + 1 ] );
// Update entry display == delete, insert, set data
SendMessage(
WindowPlaylist,
LB_DELETESTRING,
iLast,
0
);
iLast = ( int )SendMessage(
WindowPlaylist,
LB_INSERTSTRING,
iLast,
( LPARAM )entry_old->szFilename
);
SendMessage(
WindowPlaylist,
LB_SETITEMDATA,
iLast,
( LPARAM )entry_old
);
} while( bUpOrDown
?
( i < iSelCount )
:
( i >= 0 )
);
// Select new indices (old selection went away on insert/delete
if( bUpOrDown )
{
for( i = 0; i < iSelCount; i++ )
SendMessage( WindowPlaylist, LB_SETSEL, TRUE, sel[ i ] - 1 );
}
else
{
for( i = 0; i < iSelCount; i++ )
SendMessage( WindowPlaylist, LB_SETSEL, TRUE, sel[ i ] + 1 );
}
// Prevent scrolling
SendMessage(
WindowPlaylist,
LB_SETTOPINDEX,
( WPARAM )iOldTop,
0
);
// Redrawing ON
// SendMessage( WindowPlaylist, WM_SETREDRAW, ( WPARAM )TRUE, 0 );
delete [] sel;
bMoving = false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndprocPlaylist( HWND hwnd, UINT message, WPARAM wp, LPARAM lp )
{
static bool bDragging = false;
static bool bMoveLock = false;
static int iDragStartY;
static int iItemHeight = 0x7fffffff;
switch( message )
{
case WM_MOUSEMOVE:
{
if( !bDragging || bMoveLock ) break;
bMoveLock = true;
const int y = HIWORD( lp );
const int diff = y - iDragStartY;
if( abs( diff ) > iItemHeight / 2 )
{
iDragStartY += ( ( diff > 0 ) ? iItemHeight : -iItemHeight );
Playlist_MoveSel( diff < 0 );
}
bMoveLock = false;
break;
}
case WM_LBUTTONDOWN:
{
if( GetKeyState( VK_MENU ) >= 0 ) break;
// Dragging ON
iDragStartY = HIWORD( lp );
iItemHeight = ( int )SendMessage(
WindowPlaylist,
LB_GETITEMHEIGHT,
0,
0
);
bDragging = true;
return 0;
}
case WM_LBUTTONUP:
// Dragging OFF
bDragging = false;
break;
case WM_SYSKEYDOWN:
switch( wp ) // [Alt]+[...]
{
case VK_UP:
Playlist_MoveSel( true );
break;
case VK_DOWN:
Playlist_MoveSel( false );
break;
}
break;
case WM_CHAR:
case WM_KEYUP:
// SMALL LETTERS!!!!!!
switch( wp )
{
case 'z':
case 'y':
case 'x':
case 'c':
case 'v':
case 'b':
case 'l':
return 0;
}
break;
case WM_KEYDOWN:
{
const bool bShift = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
const bool bControl = ( ( GetKeyState( VK_CONTROL ) & 0x8000 ) != 0 );
// const bool bAlt = ( ( GetKeyState( VK_MENU ) & 0x8000 ) != 0 );
switch( wp )
{
case VK_LEFT:
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_REW5S, 0 );
return 0;
case VK_RIGHT:
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_FFWD5S, 0 );
return 0;
case VK_UP:
if( bControl && !bShift )
{
// Move caret not selection
const int iCaretBefore = Playlist_GetCaretIndex();
if( iCaretBefore > 0 )
{
Playlist_SetCaretIndex( iCaretBefore - 1 );
}
else if( ( iCaretBefore == 0 ) && bInfinitePlaylist )
{
Playlist_SetCaretIndex( iMaxIndex );
}
return 0;
}
else
{
if( bInfinitePlaylist )
{
if( Playlist_GetCaretIndex() != 0 ) break;
Playlist_SelectSingle( iMaxIndex );
return 0; // Or it will increase one more
}
}
break;
case VK_DOWN:
if( bControl && !bShift )
{
// Move caret not selection
const int iCaretBefore = Playlist_GetCaretIndex();
if( ( iCaretBefore < iMaxIndex ) && ( iCaretBefore >= 0 ) )
{
Playlist_SetCaretIndex( iCaretBefore + 1 );
}
else if( ( iCaretBefore == iMaxIndex ) && bInfinitePlaylist )
{
Playlist_SetCaretIndex( 0 );
}
return 0;
}
else
{
if( bInfinitePlaylist )
{
if( Playlist_GetCaretIndex() != iMaxIndex ) break;
Playlist_SelectSingle( 0 );
return 0; // Or it will increase one more
}
}
break;
case VK_SPACE:
if( bControl && !bShift )
{
const int iCaret = Playlist_GetCaretIndex();
if( iCaret == -1 ) return 0;
bool bSelected = Playlist_IsSelected( iCaret );
Playlist_SelectModify( iCaret, !bSelected );
}
return 0;
case VK_DELETE:
{
if( bShift ) break;
if( bControl )
playlist->RemoveSelected( false );
else
playlist->RemoveSelected( true );
break;
}
case VK_RETURN:
iCurIndex = Playlist_GetCaretIndex();
SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON2, 0 );
return 0;
case 'Y':
case 'Z':
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON1, 0 );
return 0;
case 'X':
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON2, 0 );
return 0;
case 'C':
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON3, 0 );
return 0;
case 'V':
// Todo modifiers pressed? -> fadeout/...
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON4, 0 );
return 0;
case 'B':
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_BUTTON5, 0 );
return 0;
/
case 'J':
if( bShift || bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, WINAMP_JUMPFILE, 0 );
return 0;
/
case 'L':
if( bControl ) return 0;
SendMessage( WindowMain, WM_COMMAND, bShift ? WINAMP_FILE_DIR : WINAMP_FILE_PLAY, 0 );
return 0;
}
break;
}
case WM_LBUTTONDBLCLK:
iCurIndex = Playlist_MouseToIndex();
if( iCurIndex < 0 ) break;
Playback::Play();
Playback::UpdateSeek();
break;
}
return CallWindowProc( WndprocPlaylistBackup, hwnd, message, wp, lp );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::Add( int iIndex, TCHAR * szDisplay, TCHAR * szFilename )
{
iMaxIndex++;
if( iIndex < 0 || iIndex > iMaxIndex ) iIndex = iMaxIndex;
if( iIndex <= iCurIndex )
{
iCurIndex++;
}
// Create entry data
PlaylistEntry * new_entry = new PlaylistEntry;
new_entry->szFilename = szFilename;
iIndex = ( int )SendMessage(
WindowPlaylist,
LB_INSERTSTRING, // LB_ADDSTRING,
iIndex,
( LPARAM )szDisplay
);
// Associate data
SendMessage(
WindowPlaylist,
LB_SETITEMDATA,
iIndex,
( LPARAM )new_entry
);
return true;
}
*/
////////////////////////////////////////////////////////////////////////////////
/// Opens a dialog box and loads the playlist if <bOpenOrSave> is [true],
/// or saves the playlist if it is [false].
////////////////////////////////////////////////////////////////////////////////
bool Playlist_DialogBoth( bool bOpenOrSave )
{
TCHAR szFilters[] = TEXT(
"All files (*.*)\0*.*\0"
"Playlist files (*.M3U)\0*.m3u\0"
"\0"
);
TCHAR szFilename[ MAX_PATH ] = TEXT( "\0" );
OPENFILENAME ofn;
memset( &ofn, 0, sizeof( OPENFILENAME ) );
ofn.lStructSize = sizeof( OPENFILENAME );
ofn.hwndOwner = WindowMain;
ofn.hInstance = g_hInstance;
ofn.lpstrFilter = szFilters;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 2;
ofn.lpstrFile = szFilename;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER |
OFN_ENABLESIZING |
( bOpenOrSave ? OFN_FILEMUSTEXIST : OFN_OVERWRITEPROMPT ) |
OFN_PATHMUSTEXIST |
OFN_HIDEREADONLY;
ofn.nMaxFileTitle = 0,
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = ( bOpenOrSave ? TEXT( "Open playlist" ) : TEXT( "Save playlist" ) );
if( bOpenOrSave )
{
if( !GetOpenFileName( &ofn ) ) return false;
}
else
{
if( !GetSaveFileName( &ofn ) ) return false;
}
if( bOpenOrSave )
{
// Open
const int iFilenameLen = ( int )_tcslen( szFilename );
if( !_tcsncmp( szFilename + iFilenameLen - 3, TEXT( "m3u" ), 3 ) )
{
// Playlist file
playlist->RemoveAll();
Playlist::AppendPlaylistFile( szFilename );
Playback::Play();
}
}
else
{
// TODO: Check extension, ask for appending if missing
// Save
Playlist::ExportPlaylistFile( szFilename );
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// Opens a dialog box and loads the selected playlist
////////////////////////////////////////////////////////////////////////////////
bool Playlist::DialogOpen()
{
return Playlist_DialogBoth( true );
}
////////////////////////////////////////////////////////////////////////////////
/// Opens a dialog box and saves the playlist to the filename selected
////////////////////////////////////////////////////////////////////////////////
bool Playlist::DialogSaveAs()
{
return Playlist_DialogBoth( false );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::AppendPlaylistFile( TCHAR * szFilename )
{
// Open playlist file
HANDLE hFile = CreateFile(
szFilename, // LPCTSTR lpFileName
FILE_READ_DATA, // DWORD dwDesiredAccess
FILE_SHARE_READ, // DWORD dwShareMode
NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes
OPEN_EXISTING, // DWORD dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // DWORD dwFlagsAndAttributes
NULL // HANDLE hTemplateFile
);
if( hFile == INVALID_HANDLE_VALUE )
{
// MessageBox( 0, TEXT( "Could not read playlist file" ), TEXT( "Error" ), MB_ICONERROR );
return false;
}
const bool bEmptyBefore = ( playlist->GetSize() == 0 );
// Remove filename from <szFilename> so we can
// use it as relative directory root
TCHAR * szWalk = szFilename + _tcslen( szFilename ) - 1;
while( ( szWalk > szFilename ) && ( *szWalk != TEXT( '\\' ) ) ) szWalk--;
szWalk++;
*szWalk = TEXT( '\0' );
TCHAR * szBaseDir = szFilename;
const int iBaseDirLen = ( int )_tcslen( szBaseDir );
DWORD iSizeBytes = GetFileSize( hFile, NULL );
if( iSizeBytes <= 0 )
{
CloseHandle( hFile );
return false;
}
// Allocate
char * rawdata = new char[ iSizeBytes + 1 ]; // One more so we can write '\0' on EOF
DWORD iBytesRead;
// Read whole file
ReadFile(
hFile, // HANDLE hFile
rawdata, // LPVOID lpBuffer
iSizeBytes, // DWORD nNumberOfBytesToRead
&iBytesRead, // LPDWORD lpNumberOfBytesRead
NULL // LPOVERLAPPED lpOverlapped
);
if( iBytesRead < iSizeBytes )
{
delete [] rawdata;
CloseHandle( hFile );
MessageBox( 0, TEXT( "Could not read whole file" ), TEXT( "Error" ), MB_ICONERROR );
return false;
}
// Parse file content
// File must be
// * M3U
// * ANSI
char * walk = rawdata;
const char * eof = rawdata + iSizeBytes;
char * beg = rawdata;
char * end;
while( true )
{
// Find newline or eof
while( ( walk < eof ) && ( *walk != '\015' ) && ( *walk != '\012' ) ) walk++;
end = walk;
if( ( end - beg > 2 ) && ( *beg != '#' ) )
{
TCHAR * szKeep;
if( beg[ 1 ] == ':' )
{
// TODO: Better detection, network path?
// Absolute path
const int iLen = end - beg;
szKeep = new TCHAR[ iLen + 1 ];
ToTchar( szKeep, beg, iLen );
szKeep[ iLen ] = TEXT( '\0' );
}
else
{
// Skip initial so we don't get a double backslash in between
while( ( beg[ 0 ] == '\\' ) && ( beg < end ) ) beg++;
// Relative path
const int iSecondLen = end - beg;
szKeep = new TCHAR[ iBaseDirLen + iSecondLen + 1 ];
memcpy( szKeep, szBaseDir, iBaseDirLen * sizeof( TCHAR ) );
ToTchar( szKeep + iBaseDirLen, beg, iSecondLen );
szKeep[ iBaseDirLen + iSecondLen ] = TEXT( '\0' );
UnbloatFilename( szKeep, false );
}
// if( !Add( iMaxIndex + 1, szKeep, szKeep ) ) break;
playlist->PushBack( szKeep );
}
// Skip newlines
while( ( walk < eof ) && ( ( *walk == '\015' ) || ( *walk == '\012' ) ) ) walk++;
if( walk == eof )
{
break;
}
beg = walk;
}
delete [] rawdata;
CloseHandle( hFile );
/*
if( bEmptyBefore )
{
iCurIndex = 0;
}
*/
return true;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::ExportPlaylistFile( TCHAR * szFilename )
{
// Open playlist file
HANDLE hFile = CreateFile(
szFilename, // LPCTSTR lpFileName
FILE_WRITE_DATA, // DWORD dwDesiredAccess
0, // DWORD dwShareMode
NULL, // LPSECURITY_ATTRIBUTES lpSecurityAttributes
CREATE_ALWAYS, // DWORD dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // DWORD dwFlagsAndAttributes
NULL // HANDLE hTemplateFile
);
if( hFile == INVALID_HANDLE_VALUE )
{
MessageBox( 0, TEXT( "Could not write playlist file" ), TEXT( "Error" ), MB_ICONERROR );
return false;
}
// Remove filename from <szFilename> so we can
// use it as relative directory root
TCHAR * szWalk = szFilename + _tcslen( szFilename ) - 1;
while( ( szWalk > szFilename ) && ( *szWalk != TEXT( '\\' ) ) ) szWalk--;
szWalk++;
*szWalk = TEXT( '\0' );
TCHAR * szBaseDir = szFilename;
const int iBaseDirLen = ( int )_tcslen( szBaseDir );
char * rawdata = new char[ ( playlist->GetMaxIndex() + 1 ) * ( MAX_PATH + 2 ) ];
char * walk = rawdata;
// Write playlist to buffer
const int iMaxMax = playlist->GetMaxIndex();
for( int i = 0; i <= iMaxMax; i++ )
{
// Get
TCHAR * szEntry = GetFilename( i );
if( !szEntry ) break;
int iEntryLen = ( int )_tcslen( szEntry );
// Copy
TCHAR * szTemp = new TCHAR[ iEntryLen + 1 ];
memcpy( szTemp, szEntry, iEntryLen * sizeof( TCHAR ) );
szTemp[ iEntryLen ] = TEXT( '\0' );
// Convert
if( ApplyRootToFilename( szBaseDir, szTemp ) )
{
// Update length or we are writing too much
iEntryLen = ( int )_tcslen( szTemp );
}
// Copy
#ifdef PA_UNICODE
ToAnsi( walk, szTemp, iEntryLen );
#else
memcpy( walk, szTemp, iEntryLen );
#endif
delete [] szTemp;
walk += iEntryLen;
memcpy( walk, "\015\012", 2 );
walk += 2;
}
const DWORD iSizeBytes = walk - rawdata;
DWORD iBytesRead;
WriteFile(
hFile, // HANDLE hFile,
rawdata, // LPCVOID lpBuffer,
iSizeBytes, // DWORD nNumberOfBytesToWrite,
&iBytesRead, // LPDWORD lpNumberOfBytesWritten,
NULL // LPOVERLAPPED lpOverlapped
);
if( iBytesRead < iSizeBytes )
{
delete [] rawdata;
CloseHandle( hFile );
MessageBox( 0, TEXT( "Could not write whole file" ), TEXT( "Error" ), MB_ICONERROR );
return false;
}
delete [] rawdata;
CloseHandle( hFile );
return true;
}
/*
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::Append( TCHAR * szDisplay, TCHAR * szFilename )
{
return Add( iMaxIndex + 1, szDisplay, szFilename );
}
*/
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
TCHAR * Playlist::GetFilename( int iIndex )
{
// if( iIndex < 0 || iIndex > iMaxIndex ) return NULL;
/*
PlaylistEntry * entry = ( PlaylistEntry * )SendMessage(
WindowPlaylist,
LB_GETITEMDATA,
iIndex,
0
);
return ( entry ? entry->szFilename : NULL );
*/
return ( TCHAR * )playlist->Get( iIndex );
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Playlist::GetFilename( int iIndex, char * szAnsiFilename, int iChars )
{
// if( iIndex < 0 || iIndex > iMaxIndex ) return 0;
/*
PlaylistEntry * entry = ( PlaylistEntry * )SendMessage(
WindowPlaylist,
LB_GETITEMDATA,
iIndex,
0
);
if( !entry || !entry->szFilename ) return 0;
TCHAR * & szFilename = entry->szFilename;
*/
TCHAR * szFilename = ( TCHAR * )playlist->Get( iIndex );
const int iFilenameLen = ( int )_tcslen( szFilename );
const int iCopyLen = ( iFilenameLen < iChars ) ? iFilenameLen : iChars;
#ifdef PA_UNICODE
ToAnsi( szAnsiFilename, szFilename, iCopyLen );
#else
memcpy( szAnsiFilename, szFilename, iCopyLen );
#endif
szAnsiFilename[ iCopyLen ] = '\0';
return iCopyLen;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
int Playlist::GetTitle( int iIndex, char * szAnsiTitle, int iChars )
{
// if( iIndex < 0 || iIndex > iMaxIndex ) return 0;
/*
TCHAR * szFilename = ( TCHAR * )SendMessage(
WindowPlaylist,
LB_GETITEMDATA,
iIndex,
0
);
if( !szFilename ) return 0;
*/
TCHAR * szFilename = ( TCHAR * )playlist->Get( iIndex );
// Get extension
const int iFilenameLen = ( int )_tcslen( szFilename );
TCHAR * szExt = szFilename + iFilenameLen - 1;
while( ( szExt > szFilename ) && ( *szExt != TEXT( '.' ) ) ) szExt--;
szExt++;
// Get plugin for extension
map <TCHAR *, InputPlugin *, TextCompare>::iterator iter = ext_map.find( szExt );
if( iter == ext_map.end() ) return 0;
InputPlugin * input_plugin = iter->second;
#ifdef PA_UNICODE
// Filename
char * szTemp = new char[ iFilenameLen + 1 ];
ToAnsi( szTemp, szFilename, iFilenameLen );
szTemp[ iFilenameLen ] = '\0';
// Ansi Title
char szTitle[ 2000 ] = "\0";
int length_in_ms;
input_plugin->plugin->GetFileInfo( szTemp, szTitle, &length_in_ms );
const int iTitleLen = strlen( szTitle );
memcpy( szAnsiTitle, szTitle, iChars * sizeof( char ) );
szTitle[ iChars ] = '\0';
#else
char szTitle[ 2000 ] = "\0";
int length_in_ms;
input_plugin->plugin->GetFileInfo( szFilename, szTitle, &length_in_ms );
const int iTitleLen = ( int )strlen( szAnsiTitle );
memcpy( szAnsiTitle, szTitle, iChars * sizeof( char ) );
szTitle[ iChars ] = '\0';
#endif
return ( iTitleLen < iChars ) ? iTitleLen : iChars;
}
/*
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::SelectZero()
{
SendMessage(
WindowPlaylist,
LB_SETSEL,
FALSE,
-1
);
return true;
}
////////////////////////////////////////////////////////////////////////////////
///
////////////////////////////////////////////////////////////////////////////////
bool Playlist::SelectAll()
{
SendMessage(
WindowPlaylist,
LB_SETSEL,
TRUE,
-1
);
return true;
}
*/