www.pudn.com > LECTEUR-MP3.zip > RepExplorer.cpp
/**************************************************************
********** RepExplorer fait par kt_system (12/2007) **********
***************************************************************/
/*
26 Mai 2008 : Modification du ConstructTree pour qui recherche chaque sous-dossier et modification du FindFile pour qui recherche chaque fichier dans chaque sous-dossier
Version 1.0
- Gestion basique des dossiers
- Methode d'ajout, modif suppression de fichier
- Systeme simple de filtrage des fichiers (par extension)
- Systeme simple de recherche de dossier ou fichier
Version 1.1
- Correction de quelques Bugs
- Ajout de la classe abstraite CAudioFile
- Ajout de la classe CMp3File
*/
#include "stdafx.h"
#include "MusGest.h"
#include "RepExplorer.h"
#include "fmod.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/**************************************************************************
**************************** CRepExplorer *******************************
***************************************************************************/
//-------------------------------------------------------------------------
CRepExplorer::CRepExplorer()
{
m_pRootRep = NULL;
m_bUseFilter = false;
}
//-------------------------------------------------------------------------
CRepExplorer::CRepExplorer(CString strRootPath)
{
m_pRootRep = NULL;
ConstructTree(strRootPath, false);
}
//-------------------------------------------------------------------------
CRepExplorer::~CRepExplorer()
{
if (m_pRootRep)
delete m_pRootRep;
m_pRootRep = NULL;
}
//-------------------------------------------------------------------------
bool CRepExplorer::ConstructTree(CString strRootPath,bool bOnlyFolderDetect /*= false*/)
{
m_strRootPath = strRootPath;
m_bOnlyFolderDetect = bOnlyFolderDetect;
if (m_pRootRep)
delete m_pRootRep;
//Construit le premier rep
//(Fct recursive il construira les autre rep tous seul)
//(Attention peut etre long si beaucoup de dossier)
m_pRootRep = new CRep(strRootPath, this, NULL);
if (m_pRootRep)
return true;
else
return false;
}
//-------------------------------------------------------------------------
void CRepExplorer::AddFileExtInFilter(CString strFileExt)
{
strFileExt.Remove('.');
strFileExt.Remove('*');
strFileExt.MakeUpper();
m_FileExtFilterList.AddHead(strFileExt);
}
//-------------------------------------------------------------------------
bool CRepExplorer::DelFileExtInFilter(CString strFileExt)
{
strFileExt.Remove('.');
strFileExt.Remove('*');
strFileExt.Remove(' ');
strFileExt.MakeUpper();
POSITION pos = m_FileExtFilterList.GetHeadPosition();
POSITION oldPos = NULL;
while (pos)
{
CString strTmp = m_FileExtFilterList.GetNext(pos);
if (strTmp == strFileExt)
{
m_FileExtFilterList.RemoveAt(oldPos);
return true;
}
oldPos = pos;
}
return false;
}
//-------------------------------------------------------------------------
CList * CRepExplorer::FindRepByName(CString strRepName)
{
m_RepFindList.RemoveAll();
RecurRepFind(m_pRootRep, strRepName);
if (m_RepFindList.GetCount() > 0)
return &m_RepFindList;
else
return NULL;
}
//-------------------------------------------------------------------------
CRep * CRepExplorer::RecurRepFind(CRep * pRep, CString strRepName)
{
CRep * pFindRep = NULL;
CRep * pNavRep = NULL;
if (pRep)
{
POSITION pos = pRep->GetFirstRepPos();
while (pos)
{
pNavRep = pRep->GetNextRep(pos);
if (pNavRep->GetRepName() == strRepName)
m_RepFindList.AddTail(pNavRep);
else
if (pNavRep->bIsExistSubRep())
pFindRep = RecurRepFind(pNavRep, strRepName);
}
}
return pFindRep;
}
//-------------------------------------------------------------------------
CList * CRepExplorer::FindFileByName(CString strFileName)
{
m_RepFileFindList.RemoveAll();
RecurRepFileFind(m_pRootRep, strFileName);
if (m_RepFileFindList.GetCount() > 0)
return &m_RepFileFindList;
else
return NULL;
}
//-------------------------------------------------------------------------
void CRepExplorer::RecurRepFileFind(CRep * pRep, CString strFileName)
{
CRep * pFindRep = NULL;
CRep * pNavRep = NULL;
if (pRep)
{
POSITION pos = pRep->GetFirstRepPos();
while (pos)
{
pNavRep = pRep->GetNextRep(pos);
if (pNavRep->bIsExistFile())
{
POSITION pos2 = NULL;
pNavRep->GetFirstFilePos();
while(pos2)
{
CRepFile * pFile = pNavRep->GetNextFile(pos2);
if (pFile)
{
if (pFile->GetFileName() == strFileName)
m_RepFileFindList.AddTail(pFile);
}
}
}
else
if (pNavRep->bIsExistSubRep())
RecurRepFind(pNavRep, strFileName);
}
}
}
/**************************************************************************
******************************** CRep ***********************************
***************************************************************************/
//-------------------------------------------------------------------------
//Fonction récursive, qui est appeler un fois par CRepExplorer
//avec le dossier de plus haut niveau, ensuite elle se charge de trouver et
//créé tous ces dossiers fils
//-------------------------------------------------------------------------
CRep::CRep(CString strPath, CRepExplorer * pRepExplorer,CRep * pParent)
{
WIN32_FIND_DATA FindFileData;
char chTmpPath[255];
//Met a jour les variables
m_ListChildRep.RemoveAll();
m_ListRepFile.RemoveAll();
m_bExistFile = false;
m_bFileDetected = false;
m_pRepExplorer = pRepExplorer;
m_pParentRep = pParent;
//Ajoute *.* a la fin pour detecter tous les type de fichier
strPath += "\\*.*";
HANDLE hFind = FindFirstFile(strPath, &FindFileData);
strPath.Delete(strPath.GetLength()-4,4);
int iPos = strPath.ReverseFind('\\');
m_strRepName = strPath;
m_strRepName.Delete(0,iPos+1);
m_strRepPath = strPath;
//Si rien n'a ete trouver on retourne
if (hFind==INVALID_HANDLE_VALUE)
return;
DWORD a = 0;
while (a != ERROR_NO_MORE_FILES)
{
if (!FindNextFile(hFind, &FindFileData))
a = GetLastError();
else
{
if (strcmp(FindFileData.cFileName,".")!=0 && strcmp(FindFileData.cFileName,"..")!=0)
{
strcpy(chTmpPath,strPath);
strcat(chTmpPath,"\\");
strcat(chTmpPath,FindFileData.cFileName);
//ATTENTION il ne faut pas comparer directement , mais il faut dabort fire un & avec
//la cte FILE_ATTRIBUTE_DIRECTORY
if ((FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
{
//C'est un dossier donc on va le créé (fct recursive)
CRep * pRep = new CRep(chTmpPath, m_pRepExplorer, this);
if (pRep)
{
//Si il a été bien créé on l'ajoute a liste de dossier fils
m_ListChildRep.AddTail(pRep);
}
}
else
{
if (VerifExtInFilterList(CRepFile::ExtractExt(FindFileData.cFileName)))
m_bExistFile = true;
//Ne detecte les fichiers que si OnlyFolderDetect = false
//(C'est un option de constructTree)
if (!pRepExplorer->IsOnlyFolderDectect())
{
m_bFileDetected = true;
CRepFile * pRepFile = NULL;
pRepFile = CreateFilebyType(&FindFileData);
//Le fichier a été créé
if (pRepFile)
{
//Ajoute a la liste de fichier fils si sont extension
//est ds la liste de filtre (ou si on utilise pas de filtres)
if (VerifFileInFilterList(pRepFile))
m_ListRepFile.AddTail(pRepFile);
else
delete pRepFile;// Sinon on le supprime
}
}
}
}
}
}
FindClose(hFind);
}
//-------------------------------------------------------------------------
//C'est ici que vous devez rajouter vos instanciation de classe
//si vous créé des classes pour gerer des nouveau type de fichier
//-------------------------------------------------------------------------
CRepFile * CRep::CreateFilebyType(WIN32_FIND_DATA * pFindFileData)
{
CRepFile * pRet = NULL;
CString strExtension;
strExtension = CRepFile::ExtractExt(pFindFileData->cFileName);
if (strExtension == "MP3")
{
//fichier de type mp3 , je créé un object
//d'une classe speciale pour gerr le mp3
pRet = new CMp3File(pFindFileData, this);
}
else
{
//Je créé un fichier standart
pRet = new CRepFile(pFindFileData, this);
}
return pRet;
}
//-------------------------------------------------------------------------
CRep::~CRep()
{
CRep * pNavRep = NULL;
POSITION pos = m_ListChildRep.GetHeadPosition();
while (pos)
{
pNavRep = m_ListChildRep.GetNext(pos);
if (pNavRep)
delete pNavRep;
}
CRepFile * pRepFile = NULL;
pos = m_ListRepFile.GetHeadPosition();
while (pos)
{
pRepFile = m_ListRepFile.GetNext(pos);
if (pRepFile)
delete pRepFile;
}
}
//-------------------------------------------------------------------------
bool CRep::VerifFileInFilterList(CRepFile * pRepFile)
{
return VerifExtInFilterList(pRepFile->GetFileExt());
}
//-------------------------------------------------------------------------
bool CRep::VerifExtInFilterList(CString strExt)
{
if (m_pRepExplorer)
{
if (m_pRepExplorer->bUseFilter())
{
CList * pList = m_pRepExplorer->GetFileExtFilterList();
if (pList)
{
POSITION pos = pList->GetHeadPosition();
while (pos)
{
CString strTmp = pList->GetNext(pos);
if (strTmp == strExt)
return true;
}
}
}
else
return true;
}
return false;
}
//-------------------------------------------------------------------------
CRep * CRep::GetRepByName(CString strRepName) const
{
CRep * pNavRep = NULL;
CRep * pRetRep = NULL;
POSITION pos = m_ListChildRep.GetHeadPosition();
while (pos)
{
pNavRep = m_ListChildRep.GetNext(pos);
if (pNavRep->m_strRepName == strRepName)
{
pos = NULL;
pRetRep = pNavRep;
}
}
return pRetRep;
}
//-------------------------------------------------------------------------
POSITION CRep::GetFirstRepPos() const
{
return m_ListChildRep.GetHeadPosition();
}
//-------------------------------------------------------------------------
CRep * CRep::GetNextRep(POSITION &pos) const
{
CRep * pNavRep = NULL;
if (pos && !m_ListChildRep.IsEmpty())
pNavRep = m_ListChildRep.GetNext(pos);
else
pos = NULL;
return pNavRep;
}
//-------------------------------------------------------------------------
POSITION CRep::GetFirstFilePos()
{
GetFolderFile();
return m_ListRepFile.GetHeadPosition();
}
//-------------------------------------------------------------------------
CRepFile * CRep::GetNextFile(POSITION &pos) const
{
CRepFile * pNavFile = NULL;
if(pos && !m_ListRepFile.IsEmpty())
pNavFile = m_ListRepFile.GetNext(pos);
else
pos = NULL;
return pNavFile;
}
//-------------------------------------------------------------------------
bool CRep::bIsExistFile()
{
if (!m_pRepExplorer->IsOnlyFolderDectect())
return !m_ListRepFile.IsEmpty();
else
return m_bExistFile;
}
//-------------------------------------------------------------------------
//Si les fichier n'ont pas été detecter pendant le construct tree
//On le fait lors de l'appel a GetFirstFilePos() qui appele cette fct
//qui s'occupe de detecter les fichier du dossier
//-------------------------------------------------------------------------
void CRep::GetFolderFile()
{
//Si on n'a pas fait la detection des fichier il
//faut la faire maintenant, si m_bFileDetected = true c'est que les fichiers
//on déja été detecter , on ne passe pas ds cette boucle
if (m_pRepExplorer->IsOnlyFolderDectect() && !m_bFileDetected)
{
CString strPath = m_strRepPath + "\\*.*";
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(strPath, &FindFileData);
if (hFind != INVALID_HANDLE_VALUE)
{
DWORD a = 0;
while (a != ERROR_NO_MORE_FILES)
{
if (!FindNextFile(hFind, &FindFileData))
a = GetLastError();
else
{
if (FindFileData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY)
{
if (strcmp(FindFileData.cFileName,".")!=0 && strcmp(FindFileData.cFileName,"..")!=0)
{
CRepFile * pRepFile = NULL;
pRepFile = CreateFilebyType(&FindFileData);
if (pRepFile)
{
if (VerifFileInFilterList(pRepFile))
m_ListRepFile.AddTail(pRepFile);
else
delete pRepFile;
}
}
}
}
m_bFileDetected = true;
}
}
}
}
//-------------------------------------------------------------------------
CRep * CRep::AddSubRep(CString strRepName)
{
CString strPath = m_strRepPath + "\\" + strRepName;
CRep * pRep = NULL;
LPSECURITY_ATTRIBUTES lpSecure = new SECURITY_ATTRIBUTES;
lpSecure->nLength = sizeof(SECURITY_ATTRIBUTES);
lpSecure->lpSecurityDescriptor = NULL;
if(CreateDirectory(strPath, lpSecure) != 0)
{
pRep = new CRep(strPath,m_pRepExplorer,this);
if (pRep)
m_ListChildRep.AddTail(pRep);
}
if (lpSecure)
delete lpSecure;
return pRep;
}
//-------------------------------------------------------------------------
bool CRep::ModifRepName(CString strRepNewName)
{
CString strSrcPath = m_strRepPath;
CString strDestPath = m_strRepPath;
int iPos = strDestPath.ReverseFind('\\');
strDestPath.Delete(iPos, strDestPath.GetLength()-iPos);
strDestPath += "\\" + strRepNewName;
if (MoveFile(strSrcPath,strDestPath) != 0)
{
m_strRepName = strRepNewName;
m_strRepPath = strDestPath;
return true;
}
return false;
}
//-------------------------------------------------------------------------
bool CRep::bIsExistSubFile()
{
POSITION pos = m_ListChildRep.GetHeadPosition();
while (pos)
{
CRep * pRep = m_ListChildRep.GetNext(pos);
if (pRep)
{
if (pRep->bIsExistFile())
return true;
else
if (pRep->bIsExistSubFile() == true)
return true;
}
}
return false;
}
//-------------------------------------------------------------------------
bool CRep::DeleteSubRep(CString strRepName)
{
bool bRet = false;
CRep * pRepToDel = GetRepByName(strRepName);
if (pRepToDel)
{
bRet = DeleteRoutine(pRepToDel->m_strRepPath);
if (pRepToDel)
{
if (DeleteInChildList(pRepToDel))
delete pRepToDel;
}
}
return bRet;
}
//-------------------------------------------------------------------------
bool CRep::DeleteThisRep()
{
bool bRet = false;
bRet = DeleteRoutine(m_strRepPath);
if (bRet)
{
CRep * pParent = GetParentRep();
//On se supprime de la liste du pere
if (pParent)
if (pParent->DeleteInChildList(this))
delete this;//on se supprime
}
return bRet;
}
//-------------------------------------------------------------------------
bool CRep::DeleteInChildList(CRep * pRep)
{
if (pRep)
{
POSITION pos = m_ListChildRep.GetHeadPosition();
POSITION oldPos = pos;//Sinon si c'est le premier sa explose
while (pos)
{
CRep * pRepToDel = m_ListChildRep.GetNext(pos);
if (pRepToDel == pRep)
{
//On delete oldpos car sinon on va supprimer le prochain
m_ListChildRep.RemoveAt(oldPos);
return true;
}
oldPos = pos;
}
if (m_ListChildRep.IsEmpty())
m_bExistFile = false;
}
return false;
}
//-------------------------------------------------------------------------
bool CRep::DeleteRoutine(CString strRepPath)
{
//Detruit recursivement tous les fichier est dossier
int s = strlen(strRepPath);
TCHAR * rep = new TCHAR[strlen(strRepPath)+2];
strcpy(rep, strRepPath);
rep[strlen(strRepPath)+1] = '\0';
SHFILEOPSTRUCT sh;
sh.hwnd = NULL;
sh.wFunc = FO_DELETE;
sh.pFrom = rep;
sh.pTo = NULL;
sh.fFlags = FOF_NOCONFIRMATION|FOF_SILENT;
sh.fFlags |= FOF_ALLOWUNDO;
sh.fAnyOperationsAborted = FALSE;
sh.lpszProgressTitle = NULL;
sh.hNameMappings = NULL;
bool iRet = (SHFileOperation(&sh)==0);
delete [] rep;
return iRet;
}
/**************************************************************************
******************************* CRepFile ********************************
***************************************************************************/
//-------------------------------------------------------------------------
CRepFile::CRepFile(WIN32_FIND_DATA * pFindFileData, CRep * pFileRep)
{
if (pFindFileData)
{
m_iFileSize = (pFindFileData->nFileSizeHigh * ((long)MAXDWORD+1) + pFindFileData->nFileSizeLow);
m_strFileName = pFindFileData->cFileName;
m_ftCreationTime = pFindFileData->ftCreationTime;
m_ftLastAccessTime = pFindFileData->ftLastAccessTime;
m_ftLastWriteTime = pFindFileData->ftLastWriteTime;
m_pFileRep = pFileRep;
m_strFileExt = ExtractExt(m_strFileName);
}
}
//-------------------------------------------------------------------------
CRepFile::~CRepFile()
{
}
//-------------------------------------------------------------------------
void CRepFile::GetTimeAttribute(FILETIME * pftCreationTime, FILETIME * pftLastAccessTime,
FILETIME * pftLastWriteTime)
{
pftCreationTime = &m_ftCreationTime;
pftLastWriteTime = &m_ftLastWriteTime;
pftLastAccessTime = &m_ftLastAccessTime;
}
//-------------------------------------------------------------------------
CString CRepFile::ExtractExt(CString strFileName)
{
CString strFileExt = strFileName;
int iPos = strFileExt.ReverseFind('.');
strFileExt.Delete(0,iPos+1);
strFileExt.Remove('.');
strFileExt.MakeUpper();
return strFileExt;
}
/**************************************************************************
******************************* CAudioFile ********************************
***************************************************************************/
CAudioFile::CAudioFile(WIN32_FIND_DATA * pFindFileData, CRep * pFileRep) : CRepFile(pFindFileData,pFileRep)
{
}
//---------------------------------------------------------------------------
CTimeSpan CAudioFile::GetFileLenght()
{
return m_FileLenght ;
}
//---------------------------------------------------------------------------
CString CAudioFile::GetStringLenght()
{
CString strTmp;
strTmp.Format("%d min : %d s",m_FileLenght.GetMinutes(), m_FileLenght.GetSeconds());
return strTmp;
}
/**************************************************************************
******************************* CMp3File ********************************
***************************************************************************/
CMp3File::CMp3File(WIN32_FIND_DATA * pFindFileData, CRep * pFileRep) : CAudioFile(pFindFileData,pFileRep)
{
HANDLE hFile;
LPSTR lpRead;
DWORD nLus;
CString strFilePath;
char szTitle[30];
char szArtist[30];
char szAlbum[30];
char szYear[4];
char szComment[30];
szTitle[0] = '\0';
szArtist[0] = '\0';
szAlbum[0] = '\0';
szYear[0] = '\0';
szComment[0] = '\0';
// si le nom du fichier n'est pas spécifié
if(pFindFileData->cFileName[0] == '\0')
{
return;
}
else
{
strFilePath = pFileRep->GetRepPath();
strFilePath += "\\";
strFilePath += m_strFileName;
}
hFile = CreateFile(strFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
// si erreur pendant CreateFile
if(hFile == INVALID_HANDLE_VALUE)
{
return;
}
// si la taille du mp3 ne permet pas la place du tag
if(m_iFileSize < 129)
{
CloseHandle(hFile);
return;
}
// on se déplace ds le fichier
SetFilePointer(hFile, - 128, 0, FILE_END);
// allocation mémoire pr le buffer de lecture
lpRead = (LPSTR) GlobalAlloc(GPTR, 128);
// lecture du tag
ReadFile(hFile, lpRead, 128, &nLus, NULL);
// si la chaine de commence pas par 'TAG'
if(lpRead[0] != 'T' || lpRead[1] != 'A' || lpRead[2] != 'G')
{
CloseHandle(hFile);
return;
}
// extraction des informations
Copy(3, 30, lpRead, szTitle);
Copy(33, 30, lpRead, szArtist);
Copy(63, 30, lpRead, szAlbum);
Copy(93, 4, lpRead, szYear);
Copy(97, 30, lpRead, szComment);
m_nGenre = lpRead[127];
m_strTitle = szTitle;
m_strArtist = szArtist;
m_strAlbum = szAlbum;
m_strYear = szYear;
m_strComment = szComment;
CloseHandle(hFile);
GlobalFree(lpRead);
m_FileLenght = ReadLenght(strFilePath);
}
//-------------------------------------------------------------
CTimeSpan CMp3File::ReadLenght(CString strFilePath)
{
//On suppose qu'on est en Version 1, layer 3
long size;
unsigned char c;
FILE* file;
int b,s;
/* ouvre le mp3 */
file=fopen(strFilePath,"rb");
/* boucle pour trouver le bitrate */
do
{
do
{
/* cherche un octet dont tous */
/* les bits sont positifs */
do
{
c=fgetc(file);
} while (c!=0xFF);
/* lit un second octet */
c=fgetc(file);
/* sort de la boucle si les 4 premiers bits sont positifs */
} while ((c&0xF0)!=0xF0);
/* lit les 4 premiers bits de l'octet suivant */
c=(fgetc(file)&0xF0)>>4;
/* regarde a quel bitrate les 4 bits correspondent */
switch (c)
{
case 0x01: b = 32 ;break;
case 0x02: b = 40 ;break;
case 0x03: b = 48 ;break;
case 0x04: b = 56 ;break;
case 0x05: b = 64 ;break;
case 0x06: b = 80 ;break;
case 0x07: b = 96 ;break;
case 0x08: b = 112 ;break;
case 0x09: b = 128 ;break;
case 0x10: b = 160 ;break;
case 0xA: b = 192 ;break;
case 0xB: b = 224 ;break;
case 0xC: b = 256 ;break;
case 0xD: b = 320 ;break;
default : b = 1 ;break;
}
/* recommence si on a un bitrate erronee */
} while ((b==0)||(b==999));
/* va a la fin du mp3 */
fseek(file,0,SEEK_END);
/* recupere la position (donc la taille du mp3) */
size=ftell(file);
/* ferme le mp3 */
fclose(file);
/* calcule la duree d'apres le bitrate et la taille du fichier */
s=(size/((b)<<7));
/* attention la duree obtenue est aproximative ! */
int iTimeMin = abs(s/60);
float iTmp = ((float)s/60) - iTimeMin;
int iTimeSec = (int)(iTmp * 60);
return CTimeSpan(0,0,iTimeMin,iTimeSec+5);
}
//-------------------------------------------------------------
CMp3File::~CMp3File()
{
}
//-------------------------------------------------------------
void CMp3File::Copy(DWORD nBegin, DWORD nLength, LPSTR lpSrc, char szDest[])
{
char *dest, *src;
DWORD i;
src = lpSrc;
dest = szDest;
src += nBegin;
for(i = 0; i < nLength; i++)
*dest++ = *src++;
}