| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWAudio *
- * *
- * $Archive:: /Commando/Code/Tools/MixViewer/duplicatecombiner.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 2/21/02 5:25p $*
- * *
- * $Revision:: 3 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "stdafx.h"
- #include "duplicatecombiner.h"
- #include "ffactory.h"
- #include "mixfile.h"
- #include "rawfile.h"
- #include "bittype.h"
- #include "mixcombiningdialog.h"
- //////////////////////////////////////////////////////////////
- //
- // DuplicateRemoverClass
- //
- //////////////////////////////////////////////////////////////
- DuplicateRemoverClass::DuplicateRemoverClass (void) :
- TempFilenameStart (0),
- Dialog (NULL)
- {
- return ;
- }
- //////////////////////////////////////////////////////////////
- //
- // ~DuplicateRemoverClass
- //
- //////////////////////////////////////////////////////////////
- DuplicateRemoverClass::~DuplicateRemoverClass (void)
- {
- return ;
- }
- //////////////////////////////////////////////////////////////
- //
- // Process
- //
- //////////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Process (void)
- {
- //
- // Kick off the worker thread...
- //
- ::AfxBeginThread (fnThreadProc, (LPVOID)this);
- //
- // Show the UI
- //
- MixCombiningDialogClass dialog;
- Dialog = &dialog;
- dialog.DoModal ();
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // fnThreadProc
- //
- ////////////////////////////////////////////////////////////////////////////
- UINT
- DuplicateRemoverClass::fnThreadProc (LPVOID pParam)
- {
- //
- // Simply ask the combiner to start processing
- //
- DuplicateRemoverClass *remover = (DuplicateRemoverClass *)pParam;
- if (remover != NULL) {
- remover->Internal_Process ();
- }
- return 1;
- }
- //////////////////////////////////////////////////////////////
- //
- // Internal_Process
- //
- //////////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Internal_Process (void)
- {
- Make_Temp_Directory ();
- //
- // Open the source mix files
- //
- DynamicVectorClass<MixFileFactoryClass *> mix_file_list;
- Open_Mix_Files (mix_file_list);
- //
- // Open the destination mix factory
- //
- MixFileFactoryClass dest_factory (DestinationMixFilename, _TheFileFactory);
- if (dest_factory.Is_Valid () && dest_factory.Build_Internal_Filename_List ()) {
- Dialog->Set_Status_Text ("Building temporary files...");
- Dialog->Set_Progress_Percent (0);
-
- //
- // Loop over each mix file...
- //
- for (int mix_index = 0; mix_index < mix_file_list.Count (); mix_index ++) {
- //
- // Get the list of filenames inside this mix file
- //
- DynamicVectorClass<StringClass> filename_list;
- mix_file_list[mix_index]->Get_Filename_List (filename_list);
- for (int file_index = 0; file_index < filename_list.Count (); file_index ++) {
- StringClass filename = ::strlwr (filename_list[file_index].Peek_Buffer ());
- DynamicVectorClass<int> dup_indices;
- dup_indices.Add (mix_index);
- //
- // Try to find this file in any of the other mix files
- //
- for (int test_mix_index = 0; test_mix_index < mix_file_list.Count (); test_mix_index ++) {
- if (test_mix_index != mix_index && Is_File_In_Factory (filename, mix_file_list[test_mix_index])) {
- dup_indices.Add (test_mix_index);
- }
- }
- //
- // Check to see if this file is already in the "destination" file
- //
- bool is_in_dest = Is_File_In_Factory (filename, &dest_factory);
- //
- // Were there any duplicates?
- //
- if (dup_indices.Count () > 1 || is_in_dest) {
- //
- // Copy the file from the source to the destination factory
- //
- if (is_in_dest == false) {
- Copy_File (mix_file_list[mix_index], &dest_factory, filename);
- }
-
- //
- // Remove all the duplicates from the mix files
- //
- for (int dup_index = 0; dup_index < dup_indices.Count (); dup_index ++) {
- mix_file_list[dup_indices[dup_index]]->Delete_File (filename);
- }
- }
- }
- //
- // Update the UI
- //
- Dialog->Set_Progress_Percent ((float)mix_index / float(mix_file_list.Count () + 1));
- }
- //
- // Save the changes
- //
- Dialog->Set_Status_Text ("Reconstructing mix files...");
- Dialog->Set_Progress_Percent (0);
- dest_factory.Flush_Changes ();
- Dialog->Set_Progress_Percent (1.0F / float(mix_file_list.Count () + 1));
- for (int index = 0; index < mix_file_list.Count (); index ++) {
- mix_file_list[index]->Flush_Changes ();
- Dialog->Set_Progress_Percent ((float)index / float(mix_file_list.Count () + 1));
- }
- Dialog->Set_Progress_Percent (1.0F);
- }
- //
- // Free each of the mix file factories
- //
- Close_Mix_Files (mix_file_list);
- //
- // Remove the temporary directory we created
- //
- Delete_Temp_Directory ();
- //
- // Close the dialog
- //
- Dialog->PostMessage (WM_COMMAND, MAKELPARAM (IDOK, BN_CLICKED));
- return ;
- }
- //////////////////////////////////////////////////////////////
- //
- // Copy_File
- //
- //////////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Copy_File
- (
- MixFileFactoryClass * src_mix,
- MixFileFactoryClass * dest_mix,
- const char * filename
- )
- {
- //
- // Get the file data from the source mix
- //
- FileClass *src_file = src_mix->Get_File (filename);
- src_file->Open ();
- //
- // Create a destination file for the data
- //
- StringClass full_path;
- Get_Temp_Filename (full_path);
- RawFileClass dest_file;
- dest_file.Set_Name (full_path);
- if (dest_file.Open (RawFileClass::WRITE)) {
- //
- // Copy the data from the source mix file to the destination file
- //
- int file_size = src_file->Size ();
- uint8 buffer[4096];
- while (file_size > 0) {
-
- //
- // Read the data from the source file
- //
- int bytes = min (file_size, (int)sizeof (buffer));
- int copied_size = src_file->Read (buffer, bytes);
- file_size -= copied_size;
- if (copied_size <= 0) {
- break;
- }
-
- //
- // Copy the data to the dest file
- //
- dest_file.Write (buffer, copied_size);
- }
- //
- // Add the file to the destination mix file
- //
- dest_mix->Add_File (full_path, filename);
- //
- // Close the temporary data file
- //
- dest_file.Close ();
- }
- //
- // Return the file
- //
- src_mix->Return_File (src_file);
- return ;
- }
- //////////////////////////////////////////////////////////////
- //
- // Open_Mix_Files
- //
- //////////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Open_Mix_Files (DynamicVectorClass<MixFileFactoryClass *> &list)
- {
- //
- // Loop over all the mix filenames in our list
- //
- for (int index = 0; index < MixFileList.Count (); index ++) {
-
- //
- // Create this mix file factory and add it to our list
- //
- MixFileFactoryClass *mix_factory = new MixFileFactoryClass (MixFileList[index], _TheFileFactory);
- if (mix_factory->Is_Valid () && mix_factory->Build_Internal_Filename_List ()) {
- list.Add (mix_factory);
- } else {
- delete mix_factory;
- mix_factory = NULL;
- }
- //
- // Update the UI
- //
- Dialog->Set_Progress_Percent ((float)index / float(MixFileList.Count () + 1));
- }
- return ;
- }
- //////////////////////////////////////////////////////////////
- //
- // Close_Mix_Files
- //
- //////////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Close_Mix_Files (DynamicVectorClass<MixFileFactoryClass *> &list)
- {
- //
- // Simply free each entry in the list
- //
- for (int index = 0; index < list.Count (); index ++) {
- delete list[index];
- }
- list.Delete_All ();
- return ;
- }
- /////////////////////////////////////////////////////////
- //
- // Make_Temp_Directory
- //
- /////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Make_Temp_Directory (void)
- {
- //
- // Get the path of the temp directory
- //
- char temp_dir[MAX_PATH] = { 0 };
- ::GetTempPath (sizeof (temp_dir), temp_dir);
- CString temp_path = Make_Path (temp_dir, "mixcombiner");
-
- //
- // Try to find a unique temp directory to store our data
- //
- int index = 0;
- do {
- TempDirectory.Format ("%s%.2d.DIR", (const char *)temp_path, index++);
- } while (GetFileAttributes (TempDirectory) != 0xFFFFFFFF);
- //
- // Create the directory
- //
- ::CreateDirectory (TempDirectory, NULL);
- ::SetCurrentDirectory (TempDirectory);
- return ;
- }
- /////////////////////////////////////////////////////////
- //
- // Delete_Temp_Directory
- //
- /////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Delete_Temp_Directory (void)
- {
- //
- // Change the current directory so we can remove the temporary one
- //
- ::SetCurrentDirectory ("c:\\");
-
- //
- // Remove the temporary directory
- //
- Clean_Directory (TempDirectory);
- ::RemoveDirectory (TempDirectory);
- return ;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Clean_Directory
- //
- //////////////////////////////////////////////////////////////////////////////////
- bool
- DuplicateRemoverClass::Clean_Directory (LPCTSTR local_dir)
- {
- bool retval = true;
- //
- // Build a search mask from the directory
- //
- StringClass search_mask = StringClass (local_dir) + "\\*.*";
-
- //
- // Loop through all the files in this directory and add them
- // to our list
- //
- DynamicVectorClass<StringClass> file_list;
- BOOL keep_going = TRUE;
- WIN32_FIND_DATA find_info = { 0 };
- for (HANDLE hfind = ::FindFirstFile (search_mask, &find_info);
- (hfind != INVALID_HANDLE_VALUE) && keep_going;
- keep_going = ::FindNextFile (hfind, &find_info))
- {
-
- //
- // If this file isn't a directory, add it to the list
- //
- if (!(find_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
- StringClass filename = find_info.cFileName;
- file_list.Add (filename);
- } else if (find_info.cFileName[0] != '.') {
-
- //
- // Recurse into this subdirectory
- //
- StringClass full_path = Make_Path (local_dir, find_info.cFileName);
- Clean_Directory (full_path);
-
- //
- // Add this directory to the list so it will get
- // deleted with the files...
- //
- StringClass filename = find_info.cFileName;
- file_list.Add (filename);
- }
- }
- //
- // Close the search handle
- //
- if (hfind != NULL) {
- ::FindClose (hfind);
- }
-
- //
- // Now loop through all the files and delete them
- //
- for (int index = 0; index < file_list.Count (); index ++) {
- StringClass &filename = file_list[index];
- StringClass full_path = Make_Path (local_dir, filename);
- Delete_File (full_path);
- }
- return retval;
- }
- //////////////////////////////////////////////////////////////////////////////////
- //
- // Make_Path
- //
- //////////////////////////////////////////////////////////////////////////////////
- StringClass
- DuplicateRemoverClass::Make_Path (LPCTSTR path, LPCTSTR filename)
- {
- StringClass full_path = path;
- //
- // Delimit the path if necessary
- //
- if (full_path[full_path.Get_Length () - 1] != '\\') {
- full_path += "\\";
- }
- //
- // Concatenate the filename onto the path
- //
- full_path += filename;
- return full_path;
- }
- /////////////////////////////////////////////////////////
- //
- // Get_Temp_Filename
- //
- /////////////////////////////////////////////////////////
- void
- DuplicateRemoverClass::Get_Temp_Filename (StringClass &full_path)
- {
- CString temp_path = Make_Path (TempDirectory, "tempfile");
-
- //
- // Try to find a unique temp filename
- //
- do {
- full_path.Format ("%s%.5d.dat", (const char *)temp_path, TempFilenameStart++);
- } while (GetFileAttributes (full_path) != 0xFFFFFFFF);
- return ;
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // Delete_File
- //
- ////////////////////////////////////////////////////////////////////////////
- bool
- DuplicateRemoverClass::Delete_File (LPCTSTR filename)
- {
- bool retval = false;
- ASSERT (filename != NULL);
- if (filename != NULL) {
- //
- // Strip the readonly bit off if necessary
- //
- DWORD attributes = ::GetFileAttributes (filename);
- if ((attributes != 0xFFFFFFFF) &&
- ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY))
- {
- ::SetFileAttributes (filename, attributes & (~FILE_ATTRIBUTE_READONLY));
- }
- //
- // Perform the delete operation!
- //
- if ((attributes != 0xFFFFFFFF) &&
- ((attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY))
- {
- retval = (::RemoveDirectory (filename) == TRUE);
- } else {
- retval = (::DeleteFile (filename) == TRUE);
- }
- }
- return retval;
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // Is_File_In_Factory
- //
- ////////////////////////////////////////////////////////////////////////////
- bool
- DuplicateRemoverClass::Is_File_In_Factory (const StringClass &filename, MixFileFactoryClass *factory)
- {
- bool retval = false;
- //
- // Get the list of filenames inside this mix file
- //
- DynamicVectorClass<StringClass> *test_filename_list = NULL;
- factory->Get_Filename_List (&test_filename_list);
-
- //
- // Try to find the file inside this mix file
- //
- for (int index = 0; index < test_filename_list->Count (); index ++) {
- if (filename.Compare_No_Case ((*test_filename_list)[index]) == 0) {
- retval = true;
- break;
- }
- }
- return retval;
- }
|