dolphin/Branches/MusicMod/Player/Src/Path.cpp
2009-01-02 23:54:39 +00:00

243 lines
5.6 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 "Path.h"
#include <ctype.h>
#include <vector>
using namespace std;
////////////////////////////////////////////////////////////////////////////////
/// Applies a virtual root to a filename
///
/// Example:
/// Rootpath: "C:\111\222\333\"
/// Filename before: "C:\111\444\test.mp3"
/// Filename after: "..\..\444\test.mp3"
////////////////////////////////////////////////////////////////////////////////
bool ApplyRootToFilename( TCHAR * szRootpath, TCHAR * szFilename )
{
// returns modified flag
int iFilenameLen = ( int )_tcslen( szFilename );
int iRootLen = ( int )_tcslen( szRootpath );
// Too short?
if( ( iRootLen < 2 ) || ( iFilenameLen < 4 ) )
{
return false;
}
// Ensure trailing backslash
bool bDelOnRet = false;
TCHAR * szFinalRoot;
TCHAR * szFinalRootBackup;
if( szRootpath[ iRootLen - 1 ] != TEXT( '\\' ) )
{
szFinalRoot = new TCHAR[ iRootLen + 2 ];
memcpy( szFinalRoot, szRootpath, iRootLen * sizeof( TCHAR ) );
memcpy( szFinalRoot + iRootLen, TEXT( "\\\0" ), 2 * sizeof( TCHAR ) );
iRootLen++;
szFinalRootBackup = szFinalRoot;
bDelOnRet = true;
}
else
{
szFinalRoot = szRootpath;
szFinalRootBackup = NULL;
bDelOnRet = false;
}
// Different drives?
if( _totlower( *szFilename ) != _totlower( *szFinalRoot ) )
{
if( bDelOnRet ) delete [] szFinalRootBackup;
return false;
}
// Skip drive
if( _tcsnicmp( szFilename, szFinalRoot, 3 ) )
{
szFinalRoot += 3;
iRootLen -= 3;
memmove( szFilename, szFilename + 3, ( iFilenameLen - 2 ) * sizeof( TCHAR ) ); // Plus \0
iFilenameLen -=3;
}
int iBackslashLast = -1;
int iCompLen; // Maximum chars to compare
if( iRootLen > iFilenameLen )
iCompLen = iFilenameLen;
else
iCompLen = iRootLen;
// Walk while equal
int i = 0;
while( i < iCompLen )
{
if( ( szFilename[ i ] == TEXT( '\\' ) ) && ( szFinalRoot[ i ] == TEXT( '\\' ) ) )
{
iBackslashLast = i;
i++;
}
else if( _totlower( szFilename[ i ] ) == _totlower( szFinalRoot[ i ] ) )
{
i++;
}
else
{
break;
}
}
// Does the filename contain the full root?
int iLevelDiff = 0;
if( i != iCompLen )
{
// Calculate level difference
for( i = iBackslashLast + 1; i < iRootLen; i++ )
{
if( szFinalRoot[ i ] == TEXT( '\\' ) )
{
iLevelDiff++;
}
}
}
if( iBackslashLast == -1 )
{
if( bDelOnRet ) delete [] szFinalRootBackup;
return false;
}
TCHAR * szSource = szFilename + iBackslashLast + 1;
if( iLevelDiff > 0 )
{
const int iExtraCharsForPrefix = ( 3 * iLevelDiff ) - iBackslashLast - 1;
const int iCharsToMove = iFilenameLen - iBackslashLast; // One more for '\0'
memmove( szSource + iExtraCharsForPrefix, szSource, sizeof( TCHAR ) * iCharsToMove );
TCHAR * szWalk = szFilename;
while( iLevelDiff-- )
{
memcpy( szWalk, TEXT( "..\\" ), 3 * sizeof( TCHAR ) );
szWalk += 3;
}
}
else
{
const int iCharsToMove = iFilenameLen - iBackslashLast; // One more for '\0'
memmove( szFilename, szSource, sizeof( TCHAR ) * iCharsToMove );
}
if( bDelOnRet ) delete [] szFinalRootBackup;
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// Compresses filenames (inplace)
///
/// Example:
/// Before "C:\111\222\..\333\.\444\..\..\test.mp3"
/// After "C:\111\test.mp3"
////////////////////////////////////////////////////////////////////////////////
bool UnbloatFilename( TCHAR * szFullpath, bool bFixTooDeep )
{
int iLen = ( int )_tcslen( szFullpath );
bool bModified = false;
// Exclude drive letter from conversion "C:\"
if( ( iLen > 3 ) && !_tcsnicmp( szFullpath + 1, TEXT( ":\\" ), 2 ) )
{
szFullpath += 3;
iLen -= 3;
}
vector< TCHAR * > after_backslash;
TCHAR * end = szFullpath + iLen;
TCHAR * szWalk = szFullpath;
while( true )
{
if( !_tcsnicmp( szWalk, TEXT( "..\\" ), 3 ) )
{
TCHAR * szAfterBackslashLast;
if( after_backslash.empty() )
{
// Getting here means we go deeper than root level e.g. "../test"
if( bFixTooDeep )
{
szAfterBackslashLast = szWalk;
}
else
{
break;
}
}
else
{
szAfterBackslashLast = after_backslash.back();
after_backslash.pop_back();
}
const int iBytesToCopy = end - szWalk - ( 3 * sizeof( TCHAR ) );
const int iBytesLess = szWalk + ( 3 * sizeof( TCHAR ) ) - szAfterBackslashLast;
memmove( szAfterBackslashLast, szWalk + 3, iBytesToCopy );
char * byte_end = ( char * )end;
byte_end -= iBytesLess;
end = byte_end;
*end = TEXT( '\0' );
szWalk = szAfterBackslashLast;
bModified = true;
}
else if( !_tcsnicmp( szWalk, TEXT( ".\\" ), 2 ) )
{
const int iBytesToCopy = end - szWalk - ( 2 * sizeof( TCHAR ) );
memmove( szWalk, szWalk + 2, iBytesToCopy );
end -= 2;
*end = TEXT( '\0' );
bModified = true;
}
else
{
if( szWalk >= end ) break;
after_backslash.push_back( szWalk );
// Jump after next backslash
while( ( szWalk < end ) && ( *szWalk != TEXT( '\\' ) ) ) szWalk++;
szWalk++;
}
}
return bModified;
}