Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

/*============================================================================ 
** COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
**============================================================================
**
**  Project/Product :  JATS ( core)devl)
**  Filename        : gunzip.cpp
**  Author(s)       : dpurdie
**  Created         : 08-Mar-18
**
**  Description     : Implement gunzip by invoking gzip with a -d option
**
**
**  Information     :
**   Compiler       : ANSI C++
**   Target         : 
**
***==========================================================================*/

//
//#include "stdafx.h"
#include <Windows.h>
#include <string>
#include <iostream>
using namespace std;

/*----------------------------------------------------------------------------
** FUNCTION           : ArgvQuote
**
** DESCRIPTION        : Append an argument to a string with correct
**                      quoting for passing as a command line argument 
 
                        This routine appends the given argument to a command line such
                        that CommandLineToArgvW will return the argument string unchanged.
                        Arguments in a command line should be separated by spaces; this
                        function does not add these spaces.
**
** INPUTS             : Argument        - Supplies the argument to encode
**                      CommandLine     - Append to this string
**                      Force           - True: Force quotes
** 
** RETURNS            : Nothing
**
----------------------------------------------------------------------------*/

void ArgvQuote( const std::wstring& Argument,std::wstring& CommandLine, bool Force )
{
    //
    // Unless we're told otherwise, don't quote unless we actually
    // need to do so --- hopefully avoid problems if programs won't
    // parse quotes properly
    //

    if (Force == false &&
        Argument.empty() == false &&
        Argument.find_first_of(L" \t\n\v\"") == Argument.npos)
    {
        CommandLine.append(Argument);
    }
    else {
        CommandLine.append(L"\"");

        for (std::wstring::const_iterator It = Argument.begin(); ; ++It) {
            unsigned NumberBackslashes = 0;

            while (It != Argument.end() && *It == L'\\') {
                ++It;
                ++NumberBackslashes;
            }

            if (It == Argument.end()) {

                //
                // Escape all backslashes, but let the terminating
                // double quotation mark we add below be interpreted
                // as a metacharacter.
                //

                CommandLine.append(NumberBackslashes * 2, L'\\');
                break;
            }
            else if (*It == L'"') {

                //
                // Escape all backslashes and the following
                // double quotation mark.
                //

                CommandLine.append(NumberBackslashes * 2 + 1, L'\\');
                CommandLine.append(1, *It);
            }
            else {

                //
                // Backslashes aren't special here.
                //

                CommandLine.append(NumberBackslashes, L'\\');
                CommandLine.append(1, *It);
            }
        }

        CommandLine.append(L"\"");
    }
}

/*----------------------------------------------------------------------------
** FUNCTION           : s2ws
**
** DESCRIPTION        : String to Wide String
**
**
** INPUTS             : str - std:string
**
** RETURNS            : A widestring
**
----------------------------------------------------------------------------*/
std::wstring s2ws(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

/*----------------------------------------------------------------------------
** FUNCTION           : main
**
** DESCRIPTION        : Invoke gzip with a '-d' option
**
**
** INPUTS             : As per gzip
**
** RETURNS            : Exit code of the gzip utility
**
----------------------------------------------------------------------------*/

int main(int argc, char** argv)
{
    BOOL    rv;
    //
    //  Replace gunzip.exe with gzip.exe -d
    //
    //  Retrieve the command line arguments as an array of pointers to strings
    //  First string will be the program path
    //
    //  Remove program name - keep path
    //  Assume we will find the gzip in the same location us this program or via the same path mechanism
    //  Handle aaaa\bbbb\cccc
    //         aaaa/bbbb/ccccc
    //         cccc
    //
    std::wstring arg = s2ws(argv[0]);
    int index = arg.find_last_of(L"\\", arg.size());
    if (index == std::string::npos) {
        index = arg.find_last_of(L"/", arg.size());
        if (index == std::string::npos) {
            index = -1;
        }
    }
    arg.erase(index + 1);
    arg.append(L"gzip.exe");

    //
    //  Convert the arglist into a fully quoted command line string
    //  Inserting a '-d' option
    //
    std::wstring args = wstring();
    ArgvQuote(arg, args, FALSE);
    args.append(L" ");
    ArgvQuote(L"-d", args, FALSE);
    for (int ii = 1; ii < argc; ii++) {
        args.append(L" ");
        ArgvQuote(s2ws(argv[ii]), args, FALSE);
    }

    //std::wcout << L"Cmd:" << args << std::endl;

    // additional information
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    DWORD exitStatus = 250;

    // set the size of the structures
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));

    // start the program up
    rv = CreateProcess
    (
        NULL,                   // the path
        (LPWSTR)args.c_str(),   // Command line
        NULL,                   // Process handle not inheritable
        NULL,                   // Thread handle not inheritable
        TRUE,                   // Set handle inheritance to TRUE
        0,                      // Opens file in a separate console
        NULL,                   // Use parent's environment block
        NULL,                   // Use parent's starting directory 
        &si,                    // Pointer to STARTUPINFO structure
        &pi                     // Pointer to PROCESS_INFORMATION structure
    );
    if (!rv) {
        DWORD eCode = GetLastError();
        exitStatus = eCode;
        //std::wcout << L"CreateProcess Error:" << eCode << std::endl;
        return exitStatus;
    }

    // Close process and thread handles.
    WaitForSingleObject(pi.hProcess, INFINITE);
    rv = GetExitCodeProcess(pi.hProcess, &exitStatus);
    if (!rv) {
        DWORD eCode = GetLastError();
        //std::wcout << L"GetExitCodeProcess Error:" << eCode << std::endl;
        exitStatus = 248;
    }
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    //std::wcout << L"Exit Status:" << exitStatus << std::endl;
    return exitStatus;
}