「C言語/C++/fdmp3」の編集履歴(バックアップ)一覧はこちら

C言語/C++/fdmp3」(2013/03/07 (木) 22:14:12) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

|開発環境|Microsoft Visual C++ 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Win32 コンソール アプリケーション| |プロジェクト名|fdmp3| |アプリケーションの種類|コンソール アプリケーション| |追加のオプション|空のプロジェクト| fdmp3.cpp #highlight(cpp){{ #pragma comment(lib, "winmm") #include <fcntl.h> // _O_WTEXT #include <io.h> // _setmode #include <stdio.h> // _fileno #include <string.h> // memcmp #include <tchar.h> #include <Windows.h> #include <map> #include <set> #include <string> #define BUF_SIZE (10 * 1024 * 1024) // 型定義 typedef struct { // ファイル情報構造体 std::wstring strPath; DWORD offset; int iDelFlag; // 削除フラグ int iDupFlag; // 重複フラグ } FileInfo; typedef std::multimap<DWORD, FileInfo> mmfsfi; typedef std::set<std::wstring> setstr; // 関数プロトタイプ宣言 int files(const _TCHAR *ptcDir); int filecmp(LPCTSTR ptcFile1, LPCTSTR ptcFile2, DWORD offset1, DWORD offset2, DWORD size); int filedel(void); BOOL LoadMP3(LPCTSTR path, DWORD &dataOffset, DWORD &dataSize); // グローバル変数 mmfsfi g_mmap; setstr g_set; int g_iDelFlag = 0; //============================================================================== int _tmain(int argc, _TCHAR *argv[]) { mmfsfi::iterator it; mmfsfi::iterator itTarget; FileInfo *pfi; FileInfo *pfiTarget; _TCHAR atcDir[_MAX_PATH]; size_t size; int iCount; int i; // BOMなしUTF-16LE _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); if (argc < 2) { _ftprintf(stderr, _T("usage: fdmp3 [-d] dir [...]\n")); return 1; } for (i = 1; i < argc; i++) { if (argv[i][0] == _T('-')) { if (argv[i][1] == _T('d')) { g_iDelFlag = 1; } } else { _tcscpy_s(atcDir, argv[i]); size = _tcslen(atcDir); if (0 < size && atcDir[size - 1] == _T('\\')) { atcDir[size - 1] = _T('\0'); } files(atcDir); } } for (it = g_mmap.begin(); it != g_mmap.end(); it++) { pfi = &(it->second); if (pfi->iDupFlag) continue; iCount = 0; for (itTarget = it; ++itTarget != g_mmap.end(); ) { if (itTarget->first != it->first) break; pfiTarget = &(itTarget->second); if (pfiTarget->iDupFlag) continue; int ret = filecmp(pfi->strPath.c_str(), pfiTarget->strPath.c_str(), pfi->offset, pfiTarget->offset, it->first); if (ret == 0) { pfiTarget->iDupFlag = 1; if (iCount == 0) { _tprintf(_T("\n%u KB (%u B)\n"), (it->first + 1023) / 1024, it->first); _tprintf(_T("%s\n"), pfi->strPath.c_str()); } _tprintf(_T("%s\n"), pfiTarget->strPath.c_str()); iCount++; } } } if (g_iDelFlag) filedel(); return 0; } //------------------------------------------------------------------------------ int files(const TCHAR *ptcDir) { size_t sizeDir = _tcslen(ptcDir); if (_MAX_PATH <= sizeDir + 4) { _ftprintf(stderr, _T("error: パスが長過ぎます。%u[%s]\n"), sizeDir, ptcDir); return -1; } TCHAR atcPath[_MAX_PATH]; _stprintf_s(atcPath, _T("%s\\*.*"), ptcDir); FileInfo fi; fi.iDelFlag = g_iDelFlag; fi.iDupFlag = 0; _wfinddata_t fd; intptr_t handle = _tfindfirst(atcPath, &fd); if (handle == -1) { _ftprintf(stderr, _T("error: _tfindfirst[%s]\n"), ptcDir); return -1; } bool empty = true; do { if (_MAX_PATH <= sizeDir + 1 + _tcslen(fd.name)) { _ftprintf(stderr, _T("error: パスが長過ぎます。[%s][%s]\n"), ptcDir, fd.name); continue; } _stprintf_s(atcPath, _T("%s\\%s"), ptcDir, fd.name); if (fd.attrib & _A_SUBDIR) { if (_tcscmp(fd.name, _T(".")) && _tcscmp(fd.name, _T(".."))) { files(atcPath); empty = false; } } else { size_t len = _tcslen(fd.name); if (len <= 4 || _tcsicmp(fd.name + len - 4, _T(".mp3"))) continue; std::pair<setstr::iterator, bool> pair = g_set.insert(atcPath); if (pair.second == true) { DWORD size; if (LoadMP3(atcPath, fi.offset, size)) { fi.strPath = atcPath; g_mmap.insert(mmfsfi::value_type(size, fi)); //_tprintf(_T("%u %u %s\n"), fi.offset, size, atcPath); } } empty = false; } } while (_tfindnext(handle, &fd) == 0); _findclose(handle); if (empty) { _ftprintf(stderr, _T("empty: [%s]\n"), ptcDir); } return 0; } //------------------------------------------------------------------------------ int filecmp(LPCTSTR ptcFile1, LPCTSTR ptcFile2, DWORD offset1, DWORD offset2, DWORD size) { static char acBuf1[BUF_SIZE]; static char acBuf2[BUF_SIZE]; FILE *pFile1 = NULL; FILE *pFile2 = NULL; int iRetVal = -1; if (_tfopen_s(&pFile1, ptcFile1, _T("rb")) != 0) { _ftprintf(stderr, _T("%s を開けません\n"), ptcFile1); goto Exit; } if (_tfopen_s(&pFile2, ptcFile2, _T("rb")) != 0) { _ftprintf(stderr, _T("%s を開けません\n"), ptcFile2); goto Exit; } // offset分読み飛ばす fseek(pFile1, offset1, SEEK_SET); fseek(pFile2, offset2, SEEK_SET); for (size_t read = 0; ; ) { size_t count = min(size - read, BUF_SIZE); size_t sizeRead1 = fread(acBuf1, 1, count, pFile1); if (ferror(pFile1) != 0 || sizeRead1 != count) { _ftprintf(stderr, _T("error: fread[%s]\n"), ptcFile1); goto Exit; } size_t sizeRead2 = fread(acBuf2, 1, count, pFile2); if (ferror(pFile2) != 0 || sizeRead2 != count) { _ftprintf(stderr, _T("error: fread[%s]\n"), ptcFile2); goto Exit; } if (memcmp(acBuf1, acBuf2, sizeRead1) != 0) { iRetVal = 1; break; } read += count; if (size <= read) { iRetVal = 0; break; } } Exit: if (pFile2) fclose(pFile2); if (pFile1) fclose(pFile1); return iRetVal; } //------------------------------------------------------------------------------ int filedel(void) { mmfsfi::iterator it; FileInfo *pfi; FILE *pFile; if (_tfopen_s(&pFile, _T("finddup.log"), _T("wt,ccs=UNICODE"))) { _ftprintf(stderr, _T("ログファイルの作成に失敗しました\n")); return -1; } for(it = g_mmap.begin(); it != g_mmap.end(); it++) { pfi = &(it->second); if (pfi->iDupFlag && pfi->iDelFlag) { _ftprintf(pFile, _T("del \"%s\"\n"), pfi->strPath.c_str()); } } fclose(pFile); return 0; } BOOL LoadMP3(LPCTSTR path, DWORD &dataOffset, DWORD &dataSize) { // MP3ファイル部 HMMIO hmmio = mmioOpen((LPTSTR)path, NULL, MMIO_READ); if (hmmio == NULL) { _ftprintf(stderr, _T("%s を開けません\n"), path); return FALSE; } DWORD dwFile = mmioSeek(hmmio, 0, SEEK_END); LPBYTE lpFile = new BYTE[dwFile]; mmioSeek(hmmio, 0, SEEK_SET); mmioRead(hmmio, (HPSTR)lpFile, dwFile); mmioClose(hmmio, 0); // MP3データ部 dataOffset = 0; dataSize = dwFile; // ID3v1 if (128 <= dwFile && memcmp(lpFile + dwFile - 128, "TAG", 3) == 0) { dataSize -= 128; } // ID3v2 if (10 <= dataSize && memcmp(lpFile, "ID3", 3) == 0) { LPBYTE size = lpFile + 6; DWORD dwTagSize = ((size[0]<<21)|(size[1]<<14)|(size[2]<<7)|size[3]) + 10; dataOffset = dwTagSize; dataSize -= dwTagSize; } delete[] lpFile; return TRUE; } }}

表示オプション

横に並べて表示:
変化行の前後のみ表示: