244 lines
5.6 KiB
C++
244 lines
5.6 KiB
C++
|
////////////////////////////////////////////////////////////////////////////////
|
|||
|
// Plainamp, Open source Winamp core
|
|||
|
//
|
|||
|
// Copyright <20> 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;
|
|||
|
}
|