From Tim's website
Jump to: navigation, search

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

  1. include "stdafx.h"
  2. include "sarj.h"
  3. include <math.h>
  4. 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>