Split and Rejoin Source
Split and Rejoin - functions.cpp
<source lang="c"> /////////////////////////////////////////////////////////////////////////////// // // Filename: functions.cpp // Author: Tim Styles // Date: 27th January 2002 // Dependencies: MFC // Description: File functions for SARJ program. // // Updated: 24/3/02 TRS Added message handling in loops and fixed progress bar // ///////////////////////////////////////////////////////////////////////////////
// Include for function declaration
- include "stdafx.h"
- include "sarj.h"
- include <math.h>
- include <afxtempl.h>
CArray<CString,CString> partFiles; CString partPath;
// Read the beginning of the file to see if it is a SARJ partition file BOOL IsSarjFile( CString* fileName ) {
// Open the file CFile file; if( file.Open( *fileName, CFile::modeRead ) == FALSE ) { *fileName = ""; return FALSE; }
// Read the header CString header; file.Read( header.GetBufferSetLength( HEADER_STRING.GetLength() ), HEADER_STRING.GetLength() ); // Test the header and return the result return header == HEADER_STRING;
}
// Prepare the dialog for joining parts together void PrepareJoinFiles( CSarjDlg* dlg, CString partFileName ) {
dlg->SetDlgItemText( IDC_BUTTON, JOIN_STRING ); dlg->progress.SetPos( 0 ); dlg->GetDescendantWindow( IDC_BUTTON )->ShowWindow( SW_SHOW ); dlg->GetDescendantWindow( IDC_EDIT_NUMBER )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_EDIT_TEXT )->ShowWindow( SW_SHOW );
// Open the file CFile partFile; if( partFile.Open( partFileName, CFile::modeRead ) == FALSE ) { dlg->SetDlgItemText( IDC_TEXT, TEXT_READ_ERROR ); return; }
// Find the path of the part file int lastSlash = 0; while( partFileName.Find( '\\', lastSlash ) != -1 ) lastSlash++; partPath = partFileName.Left( lastSlash );
// Find the part number, original filename and number of parts CString text, originalFileName; char partNumber, totalParts, originalLength; partFile.Seek( HEADER_STRING.GetLength(), 0 ); partFile.Read( &partNumber, 1 ); partFile.Read( &totalParts, 1 ); partFile.Read( &originalLength, 1 ); partFile.Read( originalFileName.GetBufferSetLength( originalLength ), originalLength ); partFile.Close();
// See if this part file ties in with the others partFiles.SetSize( totalParts+1 ); if( partFiles[0] != originalFileName ) {
// First file from group of parts - Re-initialise the part files list partFiles.RemoveAll(); partFiles.SetSize( totalParts+1 ); partFiles[0] = originalFileName; }
// Add this part to the array of part files and find the next missing one partFiles[ partNumber ] = partFileName; for( partNumber = 1; partNumber <= totalParts; partNumber++ ) {
if( partFiles[ partNumber ].IsEmpty() ) {
// Request the next part text.Format( "%s%d (of %d) for %s", TEXT_JOIN, partNumber, totalParts, originalFileName ); dlg->SetDlgItemText( IDC_TEXT, text ); return; } }
// Now all the part files are in the array of Strings dlg->editText = originalFileName; dlg->UpdateData( FALSE ); dlg->SetDlgItemText( IDC_TEXT, TEXT_READY ); dlg->OnChangeEditText();
}
// Prepare the dialog for Splitting the file into parts of the specified size void PrepareSplitFile( CSarjDlg* dlg, CString fileName ) {
dlg->SetDlgItemText( IDC_BUTTON, SPLIT_STRING ); dlg->progress.SetPos( 0 ); dlg->GetDescendantWindow( IDC_BUTTON )->EnableWindow( FALSE ); dlg->GetDescendantWindow( IDC_BUTTON )->ShowWindow( SW_SHOW ); dlg->GetDescendantWindow( IDC_EDIT_TEXT )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_EDIT_NUMBER )->ShowWindow( SW_SHOW ); dlg->SetDlgItemText( IDC_TEXT, TEXT_SPLIT );
}
// Find the other parts and join together void JoinFiles( CSarjDlg* dlg ) {
CString originalFileName = partPath + dlg->editText; CString partFileName;
// Some variables we will need in the 'for' loop CFile file, partFile; int totalBytesWritten = 0; int originalLength = 0; int headerLength = HEADER_STRING.GetLength() +3+ partFiles[0].GetLength();
// Work out how long the originial file is for( int partNumber = 1; partNumber < partFiles.GetSize(); partNumber++ ) { partFileName = partFiles[ partNumber ]; if( partFile.Open( partFileName, CFile::modeRead | CFile::shareDenyNone ) == TRUE ) { originalLength += partFile.GetLength() - headerLength; } partFile.Close(); }
// Open the new file if( file.Open( originalFileName, CFile::modeCreate | CFile::modeWrite ) == FALSE ) { dlg->SetDlgItemText( IDC_TEXT, TEXT_WRITE_ERROR ); return; } char buffer[BUFFER_SIZE];
// Structures for message handling in the loop MSG msg;
// Take the data from each part file and write it to the new file for( partNumber = 1; partNumber < partFiles.GetSize(); partNumber++ ) {
// Create a new file based on the original partFileName = partFiles[ partNumber ]; if( partFile.Open( partFileName, CFile::modeRead | CFile::shareDenyNone ) == FALSE ) { dlg->SetDlgItemText( IDC_TEXT, TEXT_READ_ERROR ); return; }
partFile.Read( buffer, headerLength );
// Show the progress bar as we are about to use it dlg->GetDescendantWindow( IDC_PROGRESS )->ShowWindow( SW_SHOW );
// Read the data in chunks while( partFile.GetPosition() < partFile.GetLength() ) { // Find the amount to copy this buffer int nBytes = __min( BUFFER_SIZE, partFile.GetLength() - partFile.GetPosition() ); totalBytesWritten += nBytes; // Read it into the buffer and then write it to the part file nBytes = partFile.Read( buffer, nBytes ); file.Write( buffer, nBytes );
// Process any messages if( PeekMessage(&msg, dlg->m_hWnd, 0, 0, PM_REMOVE ) != FALSE ) {
// See if it is a 'Quit program' message if( msg.message == WM_CLOSE ) {
// Exit loop partNumber = partFiles.GetSize(); break; } DispatchMessage( &msg ); }
// Update the progress bar float progress = float(totalBytesWritten) / float(originalLength); dlg->progress.SetPos( int( 100 * progress ) ); }
// Close this partition file partFile.Close(); }
file.Close(); dlg->SetDlgItemText( IDC_TEXT, TEXT_INITIAL ); dlg->GetDescendantWindow( IDC_BUTTON )->EnableWindow( FALSE ); dlg->GetDescendantWindow( IDC_BUTTON )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_EDIT_NUMBER )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_EDIT_TEXT )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_PROGRESS )->ShowWindow( SW_HIDE );
}
// Split the file into parts of the specified size void SplitFile( CSarjDlg* dlg, CString wholeFileName ) {
// Open the file CFile file; if( file.Open( wholeFileName, CFile::modeRead ) == FALSE ) { dlg->SetDlgItemText( IDC_TEXT, TEXT_READ_ERROR ); return; }
// Find the file name of the original without any path int lastSlash = 0; while( wholeFileName.Find( '\\', lastSlash ) != -1 ) lastSlash++; CString originalPath = wholeFileName.Left( lastSlash ); CString originalFileName = wholeFileName.Right( wholeFileName.GetLength() - lastSlash );
// Some variables we will need in the 'for' loop CFile partFile; int totalBytesRead = 0; int originalLength = file.GetLength(); int nBytesPerPart = 1024 * dlg->editNumber; int totalParts = int( ceil( originalLength / float(nBytesPerPart) ) ); int dot = originalFileName.Find('.'); CString partFileNameStub = originalFileName.Left( dot ); char buffer[BUFFER_SIZE]; // Structures for message handling in the loop MSG msg;
for( int partNumber = 1; partNumber <= totalParts; partNumber++ ) {
// Create a new file based on the original CString partFileName; partFileName.Format( "%s%s (%d of %d).srj", originalPath, partFileNameStub, partNumber, totalParts );
// Create the header for the file CString partFileHeader = HEADER_STRING; partFileHeader += char(partNumber); partFileHeader += char(totalParts); partFileHeader += char( originalFileName.GetLength() ); partFileHeader += originalFileName;
// Create the file if( partFile.Open( partFileName, CFile::modeCreate | CFile::modeWrite ) == FALSE ) { dlg->SetDlgItemText( IDC_TEXT, TEXT_WRITE_ERROR ); return; } partFile.Write( partFileHeader, partFileHeader.GetLength() );
// Show the progress bar as we are about to use it dlg->GetDescendantWindow( IDC_PROGRESS )->ShowWindow( SW_SHOW );
// Read the required amount of data int partSize = __min( nBytesPerPart - partFileHeader.GetLength(), int( originalLength - file.GetPosition() ) ); int nBytesThisPart = 0; for( int count = 0; nBytesThisPart < partSize; count++ ) {
// Find the amount to copy this buffer int nBytes = __min( BUFFER_SIZE, partSize - count * BUFFER_SIZE ); nBytesThisPart += nBytes; totalBytesRead += nBytes; // Read it into the buffer and then write it to the part file nBytes = file.Read( buffer, nBytes ); partFile.Write( buffer, nBytes );
// Process any messages if( PeekMessage(&msg, dlg->m_hWnd, 0, 0, PM_REMOVE ) != FALSE ) {
// See if it is a 'Quit program' message if( msg.message == WM_CLOSE ) {
// Exit loop partNumber = totalParts; break; } DispatchMessage( &msg ); }
// Update the progress bar float progress = float(totalBytesRead) / float(originalLength); dlg->progress.SetPos( int( 100 * progress ) ); }
// Close this partition file partFile.Close(); }
file.Close(); dlg->SetDlgItemText( IDC_TEXT, TEXT_INITIAL ); dlg->GetDescendantWindow( IDC_BUTTON )->EnableWindow( FALSE ); dlg->GetDescendantWindow( IDC_BUTTON )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_EDIT_NUMBER )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_EDIT_TEXT )->ShowWindow( SW_HIDE ); dlg->GetDescendantWindow( IDC_PROGRESS )->ShowWindow( SW_HIDE );
} </source>
Split and Rejoin - constants.h
<source lang="c"> /////////////////////////////////////////////////////////////////////////////// // // Filename: constants.h // Author: Tim Styles // Date: 27th January 2002 // Dependencies: none // Description: Header file for Split and Re-join application. // ///////////////////////////////////////////////////////////////////////////////
// Labels for button const CString SPLIT_STRING = "Split"; const CString JOIN_STRING = "Join";
// Text phrases const CString TEXT_INITIAL = "Drag and Drop files to be Split or Rejoined"; const CString TEXT_JOIN = "Now drag and drop part "; const CString TEXT_READY = "Ready to join parts, edit file name if required"; const CString TEXT_SPLIT = "Enter the maximum size of the 'part' files in Kb"; const CString TEXT_READ_ERROR = "ERROR: Unable to read file. Please try again"; const CString TEXT_WRITE_ERROR = "ERROR: Unable to write. Please try again";
// Strings used in creation of part files const CString HEADER_STRING = "SARJ part of "; const CString FILE_EXTENSION = "srj";
// Constants for program const int BUFFER_SIZE = 262144; </source>