update all the functiosn now used in the msvc pack

This commit is contained in:
U-XPBUILDBOT\mario 2013-09-11 00:13:08 +02:00
parent df3c29f0d9
commit 8ad86744fc
22 changed files with 1422 additions and 30 deletions

View File

@ -44,6 +44,10 @@ PRG=$(readlink -f $0)
BASEDIR=`dirname "$PRG"`
BASEDIR=`cd "$BASEDIR" && pwd`/..
OLDPATH=$PATH
export PATH=$BASEDIR/libexec:$PATH
echo $PATH
# Parameters
PRODUCT_DIR=$1
TARGET=$2
@ -64,6 +68,8 @@ fi
# call main
builder_controller
export PATH=$OLDPATH
# exit
exit 0

160
doc/beautify_bash.py Normal file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#**************************************************************************
# Copyright (C) 2011, Paul Lutus *
# *
# 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 2 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, write to the *
# Free Software Foundation, Inc., *
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
#**************************************************************************
import re, sys
PVERSION = '1.0'
class BeautifyBash:
def __init__(self):
self.tab_str = ' '
self.tab_size = 2
def read_file(self,fp):
with open(fp) as f:
return f.read()
def write_file(self,fp,data):
with open(fp,'w') as f:
f.write(data)
def beautify_string(self,data,path = ''):
tab = 0
case_stack = []
in_here_doc = False
defer_ext_quote = False
in_ext_quote = False
ext_quote_string = ''
here_string = ''
output = []
line = 1
for record in re.split('\n',data):
record = record.rstrip()
stripped_record = record.strip()
# collapse multiple quotes between ' ... '
test_record = re.sub(r'\'.*?\'','',stripped_record)
# collapse multiple quotes between " ... "
test_record = re.sub(r'".*?"','',test_record)
# collapse multiple quotes between ` ... `
test_record = re.sub(r'`.*?`','',test_record)
# collapse multiple quotes between \` ... ' (weird case)
test_record = re.sub(r'\\`.*?\'','',test_record)
# strip out any escaped single characters
test_record = re.sub(r'\\.','',test_record)
# remove '#' comments
test_record = re.sub(r'(\A|\s)(#.*)','',test_record,1)
if(not in_here_doc):
if(re.search('<<-?',test_record)):
here_string = re.sub('.*<<-?\s*[\'|"]?([_|\w]+)[\'|"]?.*','\\1',stripped_record,1)
in_here_doc = (len(here_string) > 0)
if(in_here_doc): # pass on with no changes
output.append(record)
# now test for here-doc termination string
if(re.search(here_string,test_record) and not re.search('<<',test_record)):
in_here_doc = False
else: # not in here doc
if(in_ext_quote):
if(re.search(ext_quote_string,test_record)):
# provide line after quotes
test_record = re.sub('.*%s(.*)' % ext_quote_string,'\\1',test_record,1)
in_ext_quote = False
else: # not in ext quote
if(re.search(r'(\A|\s)(\'|")',test_record)):
# apply only after this line has been processed
defer_ext_quote = True
ext_quote_string = re.sub('.*([\'"]).*','\\1',test_record,1)
# provide line before quote
test_record = re.sub('(.*)%s.*' % ext_quote_string,'\\1',test_record,1)
if(in_ext_quote):
# pass on unchanged
output.append(record)
else: # not in ext quote
inc = len(re.findall('(\s|\A|;)(case|then|do)(;|\Z|\s)',test_record))
inc += len(re.findall('(\{|\(|\[)',test_record))
outc = len(re.findall('(\s|\A|;)(esac|fi|done|elif)(;|\)|\||\Z|\s)',test_record))
outc += len(re.findall('(\}|\)|\])',test_record))
if(re.search(r'\besac\b',test_record)):
if(len(case_stack) == 0):
sys.stderr.write(
'File %s: error: "esac" before "case" in line %d.\n' % (path,line)
)
else:
outc += case_stack.pop()
# sepcial handling for bad syntax within case ... esac
if(len(case_stack) > 0):
if(re.search('\A[^(]*\)',test_record)):
# avoid overcount
outc -= 2
case_stack[-1] += 1
if(re.search(';;',test_record)):
outc += 1
case_stack[-1] -= 1
# an ad-hoc solution for the "else" keyword
else_case = (0,-1)[re.search('^(else)',test_record) != None]
net = inc - outc
tab += min(net,0)
extab = tab + else_case
extab = max(0,extab)
output.append((self.tab_str * self.tab_size * extab) + stripped_record)
tab += max(net,0)
if(defer_ext_quote):
in_ext_quote = True
defer_ext_quote = False
if(re.search(r'\bcase\b',test_record)):
case_stack.append(0)
line += 1
error = (tab != 0)
if(error):
sys.stderr.write('File %s: error: indent/outdent mismatch: %d.\n' % (path,tab))
return '\n'.join(output), error
def beautify_file(self,path):
error = False
if(path == '-'):
data = sys.stdin.read()
result,error = self.beautify_string(data,'(stdin)')
sys.stdout.write(result)
else: # named file
data = self.read_file(path)
result,error = self.beautify_string(data,path)
if(data != result):
# make a backup copy
self.write_file(path + '~',data)
self.write_file(path,result)
return error
def main(self):
error = False
sys.argv.pop(0)
if(len(sys.argv) < 1):
sys.stderr.write('usage: shell script filenames or \"-\" for stdin.\n')
else:
for path in sys.argv:
error |= self.beautify_file(path)
sys.exit((0,1)[error])
# if not called as a module
if(__name__ == '__main__'):
BeautifyBash().main()

View File

@ -11,18 +11,20 @@
builder_config() {
# Define commands
CMD_7z="`which 7z.exe`" ; builder_check_error "Command '7z' not installed"
CMD_unzip="`which unzip.exe`" ; builder_check_error "Command 'unzip' not installed"
CMD_unrar="`which UnRAR.exe`" ; builder_check_error "Command 'UnRAR' not installed"
CMD_zip="`which zip.exe`" ; builder_check_error "Command 'zip' not installed"
CMD_lha="`which lha.exe`" ; builder_check_error "Command 'lha' not installed"
CMD_tar="`which tar.exe`" ; builder_check_error "Command 'tar' not installed"
CMD_cabextract="`which cabextract.exe`" ; builder_check_error "Command 'cabextract' not installed"
CMD_unix2dos="`which unix2dos.exe`" ; builder_check_error "Command 'unix2dos' not installed"
CMD_sha1sum="`which sha1sum.exe`" ; builder_check_error "Command 'sha1sum' not installed"
CMD_inifile="`which inifile.exe`" ; builder_check_error "Command 'inifile' not installed (http://www.horstmuc.de/wbat32d.htm#inifile)"
CMD_showver="`which ShowVer.exe`" ; builder_check_error "Command 'ShowVer' not installed (http://www.codeproject.com/Articles/2457/ShowVer-exe-command-line-VERSIONINFO-display-progr)"
CMD_tidy="`which tidy.exe`" ; builder_check_error "Command 'tidy' not installed"
CMD_7z="`which 7z`" ; builder_check_error "Command '7z' not installed"
CMD_unzip="`which unzip.exe`" ; builder_check_error "Command 'unzip' not installed"
CMD_unrar="`which UnRAR.exe`" ; builder_check_error "Command 'UnRAR' not installed"
CMD_zip="`which zip.exe`" ; builder_check_error "Command 'zip' not installed"
CMD_tar="`which tar.exe`" ; builder_check_error "Command 'tar' not installed"
CMD_cabextract="`which cabextract.exe`" ; builder_check_error "Command 'cabextract' not installed"
CMD_unix2dos="`which unix2dos.exe`" ; builder_check_error "Command 'unix2dos' not installed"
CMD_sha1sum="`which sha1sum.exe`" ; builder_check_error "Command 'sha1sum' not installed"
CMD_inifile="`which inifile.exe`" ; builder_check_error "Command 'inifile' not installed (http://www.horstmuc.de/wbat32d.htm#inifile)"
CMD_showver="`which ShowVer.exe`" ; builder_check_error "Command 'ShowVer' not installed (http://www.codeproject.com/Articles/2457/ShowVer-exe-command-line-VERSIONINFO-display-progr)"
CMD_tidy="`which tidy.exe`" ; builder_check_error "Command 'tidy' not installed"
CMD_msiexec="`which msiexec.exe`" ; builder_check_error "Command 'msiexec' not installed"
CMD_innounp="`which innounp.exe`" ; builder_check_error "Command 'innounp' not installed"
CMD_xmlstarlet="`which xmlstarlet.exe`" ; builder_check_error "Command 'xmlstarlat' not installed"
# Check temp dir
test -d ${TMP_DIR}
@ -188,14 +190,14 @@ builder_create() {
# Copy files and convert text files to dos format
# cp -Rv ${PRODUCT_DIR}/AIO $INST_DIR
# cp -Rv ${PRODUCT_DIR}/CLIENT_DATA $INST_DIR
# cp -Rv ${PRODUCT_DIR}/Temp $INST_DIR
# if [ -d "${PRODUCT_DIR}/SERVER_DATA" ] ; then
# cp -Rv ${PRODUCT_DIR}/SERVER_DATA $INST_DIR
# fi
# copy binaries
for (( i = 0 ; i < ${#DL_SOURCE[@]} ; i++ )) ; do
DL_EXTRACT_PATH[$i]=${INST_DIR}/CLIENT_DATA/${DL_ARCH[$i]}/${DL_EXTRACT_TO[$i]}
DL_EXTRACT_PATH[$i]=${INST_DIR}/Temp/${DL_ARCH[$i]}/${DL_EXTRACT_TO[$i]}
local format=${DL_EXTRACT_FORMAT[$i]}
if [ -z "$format" ] ; then format="cp"; fi
local option=${DL_EXTRACT_OPTION[$i]}
@ -240,9 +242,10 @@ builder_package() {
local release_new=${CREATOR_TAG}${RELEASE}
local aio_file=${PN}_${VERSION}-${release_new}.7z
rm -rf $INST_DIR/Temp
pushd ${OUTPUT_DIR}
rm -f ${aio_file} ${AIO_REPOS_FILE_PATTERN}.7z
7z a ${AIO_REPOS_FILE_PATTERN}.7z -v $INST_DIR/*
$CMD_7z a ${AIO_REPOS_FILE_PATTERN}.7z $INST_DIR/*
builder_check_error "Building AIO-package"
popd

View File

@ -1,3 +1,4 @@
#############################################
# void retrieve_file (src, dst)
#
@ -67,8 +68,6 @@ function process_file() {
$CMD_unzip $option -o $src -d $dst
elif [ "$format" = "unrar" ]; then
$CMD_unrar x -y $option $src $dst
elif [ "$format" = "lha" ]; then
$CMD_lha x $option -w=$dst $src
elif [ "$format" = "targz" ]; then
$CMD_tar xzvf $option $src -C $dst
elif [ "$format" = "tarbz2" ]; then
@ -201,16 +200,28 @@ write_ini_file() {
# Var:
#
###################
get_file_version() {
local getver_file=$1
local getver_var=$2
vercomp() {
[ ! $(echo -e "$1\n$2" | sort --version-sort | head -1) = "$1" ]
}
if [ -f "$getver_file" ] ; then
$CMD_showver $getver_file | grep FileVersion: | rev | cut -d: -f1 | rev | tr -d ' ' > $getver_ver
echo "file $getver_file has version $getver_ver"
else
echo "$getver_file not found"
fi
###################
# Get Verison of File
#
# Copy file only if it is newer
#
# Parameter
# File: to process
# Var:
#
###################
get_file_ver() {
local getver_file=$2
local __resultvar=$1
local myresult=`$CMD_showver $(cygpath -pw "$getver_file") | grep FileVersion: | rev | cut -d: -f1 | rev | tr -d ' '`
echo "$getver_file -> $myresult"
eval $__resultvar="'$myresult'"
}
###################
@ -226,10 +237,29 @@ get_file_version() {
copyver() {
local source_file=$1
local target_file=$2
local source_ver
local target_ver
local source_ver=""
local target_ver=""
get_file_version $source_file $source_ver
echo "Source File: $source_file Target Version: $target_file"
if [ -f "$source_file" ] && [ -f "$target_file" ] ; then
get_file_ver source_ver $source_file
get_file_ver target_ver $target_file
if [ vercomp $source_ver $target_ver ] ; then
echo "Source Verssion: $source_ver > Target Version: $target_ver"
echo "Copying File"
cp $source_file $target_file
else
echo "Source Verssion: $source_ver =< Target Version: $target_ver"
echo "Not Copying File"
fi
elif [ -f "$source_file" ] && [ ! -f "$target_file" ] ; then
source_ver=$(get_file_version $source_file)
echo "Source Verssion: $source_ver"
echo "Copying File"
cp $source_file $target_file
else
echo "Nothing to copy"
fi
}
###################
@ -249,3 +279,68 @@ tidy_xml() {
cat $source_file | $CMD_tidy -utf8 -xml -w 255 -i -c -q -asxml | sed -e 's!&gt;!>!g' -e 's!&lt;!<!g' > $target_file
}
#############################################
# void extract_file (format, src, dst)
#
# Description: Extract a file
#
# Parameter
# format: compression format
# src: source file to be used
# dst: path to extract the file
#
#############################################
function extract_file() {
local format=$1
local src=$2
local dst=$3
local option=$4
local src_dir=`dirname "$src"`
local src_file=`basename "$src"`
local dst_dir=`dirname "$dst"`
local dst_file=`basename "$dst"`
log_debug "Compression format: $format"
mkdir -p $dst
if [ "$format" = "msi-a" ]; then
mkdir /cygdrive/c/msi-adm
pushd $src_dir
echo $src_file
$CMD_msiexec /a "$src_file" $option TARGETDIR="c:\msi-adm"
popd
cp -r /cygdrive/c/msi-adm/* $dst
rm -rf /cygdrive/c/msi-adm
elif [ "$format" = "msp-a" ]; then
pushd $dst_dir
cp $src $dst_dir
$CMD_msiexec /p "$src_file" /a "$dst_file" SHORTFILENAMES=TRUE /qb
popd
elif [ "$format" = "7zip" ]; then
$CMD_7z x -y $option -o$dst $src
elif [ "$format" = "unzip" ]; then
$CMD_unzip $option -o $src -d $dst
elif [ "$format" = "unrar" ]; then
$CMD_unrar x -y $option $(cygpath -pw "$src") $(cygpath -pw "$dst")
elif [ "$format" = "cab" ]; then
$CMD_cabextract $option -d $dst $src
elif [ "$format" = "cab-sfx" ]; then
$CMD_cabextract $option -d $dst $src
$CMD_xmlstarlet sel -N X="http://schemas.microsoft.com/wix/2008/Burn" -t -m "//X:Payload" -v "concat(@SourcePath,'-',@FilePath)" -n $dst/0 | tr '\\' '/' > $dst/rename.list
for i in `cat $dst/rename.list`
do
pushd $dst
local src_var=$(echo $i | cut -f1 -d-)
local dst_var=$(echo $i | cut -f2 -d-)
mkdir -p $(dirname $dst_var)
mv -v $src_var $dst_var
popd
done
elif [ "$format" = "inno" ]; then
$CMD_innounp $option -d $dst $src
else
fatal_error "Unknown compression format: $format"
fi
}

BIN
libexec/MsiX.exe Executable file

Binary file not shown.

534
libexec/MsiX/MsiX.cpp Normal file
View File

@ -0,0 +1,534 @@
#include "msix.h"
#pragma comment(lib, "msi.lib")
// Entry point.
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwError = NOERROR;
HRESULT hr = NOERROR;
ARGS args = { 0 };
IStorage* pRootStorage = NULL;
IEnumSTATSTG* pEnum = NULL;
LPCTSTR pszPersist = (LPTSTR)MSIDBOPEN_READONLY;
STATSTG stg = { 0 };
PMSIHANDLE hDatabase = NULL;
PMSIHANDLE hView = NULL;
PMSIHANDLE hRecord = NULL;
dwError = ParseArguments(argc, argv, &args);
if (ERROR_SUCCESS != dwError)
{
return dwError;
}
// Open the root storage file and extract storages first. Storages cannot
// be extracted using MSI APIs so we must use the compound file implementation
// for IStorage.
hr = StgOpenStorage(
CT2W(args.Path),
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
NULL,
0,
&pRootStorage);
if (SUCCEEDED(hr) && pRootStorage)
{
// Determine if the file path specifies an MSP file.
// This will be used later to open the database with MSI APIs.
if (IsPatch(pRootStorage))
{
pszPersist = MSIDBOPEN_READONLY + MSIDBOPEN_PATCHFILE;
}
hr = pRootStorage->EnumElements(0, NULL, 0, &pEnum);
if (SUCCEEDED(hr))
{
while (S_OK == (hr = pEnum->Next(1, &stg, NULL)))
{
if (STGTY_STORAGE == stg.type)
{
hr = SaveStorage(pRootStorage, args.Directory, stg.pwcsName,
args.IncludeExtension ? TEXT(".mst") : NULL);
if (FAILED(hr))
{
break;
}
}
}
SAFE_RELEASE(pEnum);
}
}
SAFE_RELEASE(pRootStorage);
// Now open the database using MSI APIs. Patches cannot be opened simultaneously
// since exclusive access is required and no MSI APIs are exported that accept
// an IStorage pointer.
if (SUCCEEDED(hr))
{
dwError = MsiOpenDatabase(args.Path, pszPersist, &hDatabase);
if (ERROR_SUCCESS == dwError)
{
dwError = MsiDatabaseOpenView(hDatabase,
TEXT("SELECT `Name`, `Data` FROM `_Streams`"), &hView);
if (ERROR_SUCCESS == dwError)
{
dwError = MsiViewExecute(hView, NULL);
if (ERROR_SUCCESS == dwError)
{
while (ERROR_SUCCESS == (dwError = MsiViewFetch(hView, &hRecord)))
{
dwError = SaveStream(hRecord, args.Directory, args.IncludeExtension);
if (ERROR_SUCCESS != dwError)
{
break;
}
}
// If there are no more records indicate success.
if (ERROR_NO_MORE_ITEMS == dwError)
{
dwError = ERROR_SUCCESS;
}
}
}
}
}
// If a Win32 error has occurred return only the win32 error portion.
if (FACILITY_WIN32 == HRESULT_FACILITY(hr))
{
dwError = HRESULT_CODE(hr);
}
else if (FAILED(hr))
{
// Just set it to the HRESULT. Many common HRESULTs
// will yield an error string from FormatMessage.
dwError = hr;
}
// Print the error to the console.
if (ERROR_SUCCESS != dwError)
{
win32_error(dwError);
}
return dwError;
}
// Parse the file path, and optionally output directory and extension guessing switch.
DWORD ParseArguments(int argc, [Pre(Null=No)] _TCHAR* argv[], [Pre(Null=No)] LPARGS args)
{
_ASSERTE(argv);
_ASSERTE(args);
int iParamIndex = 1;
// Validate arguments.
if (2 > argc)
{
error(TEXT("Error: you must specify a Windows Installer file from which to extract files.\n"));
usage(argv[0], stderr);
return ERROR_INVALID_PARAMETER;
}
if (0 == _tcsicmp(TEXT("/?"), argv[iParamIndex]) || 0 == _tcsicmp(TEXT("-?"), argv[iParamIndex]))
{
// Display the usage text.
usage(argv[0], stdout);
return ERROR_SUCCESS;
}
else if (TEXT('/') == argv[iParamIndex][0] || TEXT('-') == argv[iParamIndex][0])
{
// Filename should not begin with a command-switch character.
error(TEXT("Error: invalid file name.\n"));
usage(argv[0], stderr);
return ERROR_INVALID_PARAMETER;
}
else
{
// Set the path argument.
args->Path = const_cast<LPTSTR>(argv[iParamIndex]);
}
// Get the output directory if requested.
while (++iParamIndex < argc)
{
// The directory in which files are extracted.
if (0 == _tcsicmp(TEXT("/out"), argv[iParamIndex]) || 0 == _tcsicmp(TEXT("-out"), argv[iParamIndex]))
{
if (++iParamIndex < argc && TEXT('/') != argv[iParamIndex][0] && TEXT('-') != argv[iParamIndex][0])
{
args->Directory = const_cast<LPTSTR>(argv[iParamIndex]);
}
else
{
error(TEXT("Error: you must specify an output directory with /out.\n"));
usage(argv[0], stderr);
return ERROR_INVALID_PARAMETER;
}
}
// Whether or not to include or guess at extensions for output file names.
else if (0 == _tcsicmp(TEXT("/ext"), argv[iParamIndex]) || 0 == _tcsicmp(TEXT("-ext"), argv[iParamIndex]))
{
args->IncludeExtension = TRUE;
}
else
{
error(TEXT("Error: unknown option: %s.\n"), argv[iParamIndex]);
usage (argv[0], stderr);
return ERROR_INVALID_PARAMETER;
}
}
return ERROR_SUCCESS;
}
// Prints usage to the given output file stream.
void usage(LPCTSTR pszPath, FILE* out)
{
_ASSERTE(pszPath);
_ASSERTE(out);
LPTSTR pszName = NULL;
pszName = (LPTSTR)_tcsrchr(pszPath, TEXT('\\'));
if (pszName)
{
// Advance past the backslash.
pszName++;
}
else
{
// Set the executable name.
pszName = const_cast<LPTSTR>(pszPath);
}
_ftprintf(out, TEXT("Usage: %s <file> [/out <output>] [/ext]\n\n"), pszName);
_ftprintf(out, TEXT("\tfile - Path to an MSI, MSM, MSP, or PCP file.\n"));
_ftprintf(out, TEXT("\tout - Extract streams and storages to the <output> directory.\n"));
_ftprintf(out, TEXT("\text - Append appropriate extensions to output files.\n"));
_ftprintf(out, TEXT("\nExtracts transforms and cabinets from a Windows Installer file.\n"));
}
// Colors errors on the console red and prints the formatted error.
// You can use positional format specifiers with CRT8.
void error(LPCTSTR pszFormat, ...)
{
_ASSERTE(pszFormat);
CONSOLE_SCREEN_BUFFER_INFO csbi;
HANDLE hStdErr = INVALID_HANDLE_VALUE;
va_list args;
// Set console colors to error values.
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
if (INVALID_HANDLE_VALUE != hStdErr)
{
if (GetConsoleScreenBufferInfo(hStdErr, &csbi))
{
// Set new console colors.
SetConsoleTextAttribute(hStdErr, COLOR_ERROR);
}
}
// Print error.
va_start(args, pszFormat);
_vftprintf_p(stderr, pszFormat, args);
va_end(args);
// Reset the console colors to original values.
if (INVALID_HANDLE_VALUE != hStdErr)
{
SetConsoleTextAttribute(hStdErr, csbi.wAttributes);
}
}
// Wrapper around FormatMessage for getting error text.
// Calls error() to print the error to the console.
void win32_error(DWORD dwError)
{
LPTSTR pszError;
// Format the error. Error ends with new line.
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &pszError,
0,
NULL))
{
error(TEXT("Error 0x%1$08x (%1$d): %2$s"), dwError, pszError);
LocalFree(pszError);
}
}
// Creates a patch from components, using the current working
// directory if pszDir is NULL.
// pszExt should be either NULL or start with a ".".
LPTSTR MakePath(LPTSTR pszDest, size_t cchDest, LPCTSTR pszDir, LPCTSTR pszName, LPCTSTR pszExt)
{
size_t len = 0;
_ASSERTE(pszDest);
_ASSERTE(cchDest);
_ASSERTE(pszName);
// Make sure pszDest is NULL-terminated.
pszDest[0] = TEXT('\0');
if (pszDir)
{
// Get the length of pszDir.
len = _tcslen(pszDir);
if (len && 0 != _tcsncpy_s(pszDest, cchDest, pszDir, len))
{
return NULL;
}
if (len && TEXT('\\') != pszDest[len - 1])
{
// Make sure the path ends with a "\".
if (0 != _tcsncat_s(pszDest, cchDest, TEXT("\\"), _TRUNCATE))
{
return NULL;
}
}
}
// Append the file name.
if (0 != _tcsncat_s(pszDest, cchDest, pszName, _TRUNCATE))
{
return NULL;
}
// Append the extension.
if (pszExt)
{
if (0 != _tcsncat_s(pszDest, cchDest, pszExt, _TRUNCATE))
{
return NULL;
}
}
return pszDest;
}
// Wrapper around allocating and filling a buffer using MsiRecordGetString().
UINT GetString(MSIHANDLE hRecord, UINT iField, LPTSTR* ppszProperty, DWORD* pcchProperty)
{
_ASSERTE(hRecord);
_ASSERTE(iField > 0);
_ASSERTE(ppszProperty);
_ASSERTE(pcchProperty);
UINT iErr = NOERROR;
DWORD cchProperty = 0;
iErr = MsiRecordGetString(hRecord, iField, TEXT(""), &cchProperty);
if (ERROR_MORE_DATA == iErr)
{
*ppszProperty = new TCHAR[++cchProperty];
*pcchProperty = cchProperty;
iErr = MsiRecordGetString(hRecord, iField, *ppszProperty, &cchProperty);
if (ERROR_SUCCESS != iErr)
{
delete [] *ppszProperty;
*ppszProperty = NULL;
*pcchProperty = 0;
}
}
return iErr;
}
// Determines if the given IStorage* is for a patch
// using the STATSTG for the IStorage object.
BOOL IsPatch(IStorage* pStorage)
{
_ASSERTE(pStorage);
HRESULT hr = NOERROR;
STATSTG stg = { 0 };
hr = pStorage->Stat(&stg, STATFLAG_NONAME);
if (SUCCEEDED(hr))
{
return !memcmp(&stg.clsid, &CLSID_MsiPatch, sizeof(CLSID));
}
return FALSE;
}
// Creates a new storage file and saves the named sub-storage of pRootStorage
// to the new storage file.
HRESULT SaveStorage(IStorage* pRootStorage, LPCTSTR pszDir, PCWSTR pszName, LPCTSTR pszExt)
{
HRESULT hr = NOERROR;
TCHAR szPath[MAX_PATH] = { TEXT('\0') };
IStorage* pStg = NULL;
IStorage* pFileStg = NULL;
_ASSERTE(pRootStorage);
_ASSERTE(pszName);
hr = pRootStorage->OpenStorage(
pszName,
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
NULL,
0,
&pStg);
if (SUCCEEDED(hr) && pStg)
{
if (!MakePath(szPath, MAX_PATH, pszDir, CW2T(pszName), pszExt))
{
hr = E_INVALIDARG;
}
else
{
_tprintf(TEXT("%s\n"), szPath);
// Create the storage file.
hr = StgCreateDocfile(
CT2W(szPath),
STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
0,
&pFileStg);
if (SUCCEEDED(hr) && pFileStg)
{
hr = pStg->CopyTo(0, NULL, NULL, pFileStg);
}
}
}
SAFE_RELEASE(pFileStg);
SAFE_RELEASE(pStg);
if (FAILED(hr))
{
error(TEXT("Error: failed to save storage '%s'.\n"), CW2T(pszName));
}
return hr;
}
// Saves the stream from the given record to a file with or without
// an extension based on whether or not fIncludeExt is set to TRUE.
UINT SaveStream(MSIHANDLE hRecord, [Pre(Null=Maybe)] LPCTSTR pszDir, BOOL fIncludeExt)
{
UINT uiError = NOERROR;
TCHAR szPath[MAX_PATH];
LPTSTR pszName = NULL;
DWORD cchName = 0;
CHAR szBuffer[256];
DWORD cbBuffer = sizeof(szBuffer);
std::ofstream file;
try
{
// Get the name of the stream but skip if \005SummaryInformation stream.
if (ERROR_SUCCESS == GetString(hRecord, 1, &pszName, &cchName) &&
0 != _tcsncmp(pszName, TEXT("\005"), 1))
{
// Create the local file with the simple CFile write-only class.
do
{
uiError = MsiRecordReadStream(hRecord, 2, szBuffer, &cbBuffer);
if (ERROR_SUCCESS == uiError)
{
if (!file.is_open())
{
// Create the file path if the file is not created and assume the extension
// if requested by fIncludeExt.
if (!MakePathForData(szPath, MAX_PATH, pszDir, pszName, szBuffer, cbBuffer, fIncludeExt))
{
throw std::exception("Could not create the output path name");
}
// Create the local file in which data is written.
_tprintf(TEXT("%s\n"), szPath);
file.open(CT2A(szPath), std::ios_base::binary);
}
file.write(szBuffer, cbBuffer );
}
else
{
throw std::exception("Could not read from stream.");
}
} while (cbBuffer);
}
}
catch (std::exception& ex)
{
error(TEXT("Error: %s\n"), CA2T(ex.what()));
uiError = ERROR_CANNOT_MAKE;
}
file.close();
if (pszName)
{
delete [] pszName;
pszName = NULL;
}
return uiError;
}
// Creates a patch for the given file using MakePath, but uses what of the
// buffer it can to guess the file type and infer a common file extension.
LPTSTR MakePathForData(LPTSTR pszDest, size_t cchDest, LPCTSTR pszDir, LPCTSTR pszName,
LPCVOID pBuffer, size_t cbBuffer, BOOL fIncludeExt)
{
LPTSTR pszExt = NULL;
if (fIncludeExt)
{
// Cabinet (*.cab) files.
if (0 == memcmp(pBuffer, "MSCF", 4))
{
pszExt = TEXT(".cab");
}
// Executable files. Assumed to be .dll (more common).
else if (0 == memcmp(pBuffer, "MZ", 2))
{
pszExt = TEXT(".dll");
}
// Icon (*.ico) files. Only assumed because they're common.
else if (0 == memcmp(pBuffer, "\0\0\1\0", 4))
{
pszExt = TEXT(".ico");
}
// Bitmap (*.bmp) files.
else if (0 == memcmp(pBuffer, "BM", 2))
{
pszExt = TEXT(".bmp");
}
// GIF (*.gif) files.
else if (0 == memcmp(pBuffer, "GIF", 3))
{
pszExt = TEXT(".gif");
}
// PING (*.png) files.
else if (0 == memcmp(pBuffer, "\x89PNG", 4))
{
pszExt = TEXT(".png");
}
// TIFF (*.tif) files.
else if (0 == memcmp(pBuffer, "II", 2))
{
pszExt = TEXT(".tif");
}
}
return MakePath(pszDest, cchDest, pszDir, pszName, pszExt);
}

266
libexec/MsiX/MsiX.h Normal file
View File

@ -0,0 +1,266 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>
#include <windows.h>
#include <objbase.h>
#include <msiquery.h>
#include <exception>
#include <fstream>
#include <codeanalysis/sourceannotations.h>
using namespace vc_attributes;
#define SAFE_RELEASE(ptr) if (ptr) { (ptr)->Release(); ptr = NULL; }
#define COLOR_ERROR FOREGROUND_RED | FOREGROUND_INTENSITY
void usage([Pre(Null=No)] LPCTSTR pszPath, [Pre(Null=No)] FILE* out);
void error([Pre(Null=No)] LPCTSTR pszFormat, ...);
void win32_error(DWORD dwError);
typedef struct _ARGS
{
LPTSTR Path;
LPTSTR Directory;
BOOL IncludeExtension;
} ARGS, *LPARGS;
DWORD ParseArguments(int argc, [Pre(Null=No)] _TCHAR* argv[], [Pre(Null=No)] LPARGS args);
LPTSTR MakePath([Pre(Null=No)] LPTSTR pszDest, size_t cchDest, [Pre(Null=Maybe)] LPCTSTR pszDir,
[Pre(Null=No)] LPCTSTR pszName, [Pre(Null=Maybe)] LPCTSTR pszExt);
UINT GetString(MSIHANDLE hRecord, UINT iField,
[Pre(Null=No)] LPTSTR* ppszProperty, [Pre(Null=No)] DWORD* pcchProperty);
HRESULT SaveStorage([Pre(Null=No)] IStorage* pRootStorage, [Pre(Null=Maybe)] LPCTSTR pszDir,
[Pre(Null=No)] PCWSTR pszName, [Pre(Null=Maybe)] LPCTSTR pszExt);
UINT SaveStream(MSIHANDLE hRecord, [Pre(Null=Maybe)] LPCTSTR pszDir, BOOL fIncludeExt);
LPTSTR MakePathForData([Pre(Null=No)] LPTSTR pszDest, size_t cchDest,
[Pre(Null=Maybe)] LPCTSTR pszDir, [Pre(Null=No)] LPCTSTR pszName,
[Pre(Null=No)] LPCVOID pBuffer, size_t cbBuffer, BOOL fIncludeExt);
BOOL IsPatch([Pre(Null=No)] IStorage* pStorage);
EXTERN_C const CLSID CLSID_MsiPatch = {0xC1086, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}};
// Simple string conversion classes.
class CW2W
{
public:
CW2W(LPCWSTR psz) throw(...) :
m_psz(psz)
{
_ASSERTE(psz);
}
CW2W(LPCWSTR psz, UINT nCodePage) throw(...) :
m_psz(psz)
{
_ASSERTE(psz);
(void)nCodePage;
}
~CW2W() throw()
{
}
operator LPWSTR() const throw()
{
return const_cast<LPWSTR>(m_psz);
}
private:
LPCWSTR m_psz;
// Hide the copy constructor and assignment operator.
CW2W( const CW2W& ) throw();
CW2W& operator=( const CW2W& ) throw();
};
class CW2A
{
public:
CW2A(LPCWSTR psz) throw(...) :
m_psz(NULL)
{
_ASSERTE(psz);
Init(psz, CP_ACP);
}
CW2A(LPCWSTR psz, UINT nCodePage) throw(...) :
m_psz(NULL)
{
_ASSERTE(psz);
Init(psz, nCodePage);
}
~CW2A() throw()
{
if (m_psz)
{
delete [] m_psz;
m_psz = NULL;
}
}
operator LPSTR() const throw()
{
return m_psz;
}
private:
LPSTR m_psz;
void Init(LPCWSTR psz, UINT nCodePage) throw(...)
{
int iErr = NOERROR;
int cch = 0;
cch = WideCharToMultiByte(nCodePage, 0, psz, -1, NULL, 0, NULL, NULL);
if (cch)
{
// cch includes the NULL terminator character.
m_psz = new CHAR[cch]; // Throws if no memory.
if (!WideCharToMultiByte(nCodePage, 0, psz, -1, m_psz, cch, NULL, NULL))
{
iErr = (int)GetLastError();
}
}
else
{
iErr = (int)GetLastError();
}
if (ERROR_SUCCESS != iErr)
{
throw iErr;
}
}
// Hide the copy constructor and assignment operator.
CW2A( const CW2A& ) throw();
CW2A& operator=( const CW2A& ) throw();
};
class CA2W
{
public:
CA2W(LPCSTR psz) throw(...) :
m_psz(NULL)
{
_ASSERTE(psz);
Init(psz, CP_ACP);
}
CA2W(LPCSTR psz, UINT nCodePage) throw(...) :
m_psz(NULL)
{
_ASSERTE(psz);
Init(psz, nCodePage);
}
~CA2W() throw()
{
if (m_psz)
{
delete [] m_psz;
m_psz = NULL;
}
}
operator LPWSTR() const throw()
{
return m_psz;
}
private:
LPWSTR m_psz;
void Init(LPCSTR psz, UINT nCodePage) throw(...)
{
int iErr = NOERROR;
int cch = 0;
cch = MultiByteToWideChar(nCodePage, MB_PRECOMPOSED, psz, -1, NULL, 0);
if (cch)
{
// cch includes the NULL terminator character.
m_psz = new WCHAR[cch]; // Throws if no memory.
if (!MultiByteToWideChar(nCodePage, MB_PRECOMPOSED, psz, -1, m_psz, cch))
{
iErr = (int)GetLastError();
}
}
else
{
iErr = (int)GetLastError();
}
if (ERROR_SUCCESS != iErr)
{
throw iErr;
}
}
// Hide the copy constructor and assignment operator.
CA2W( const CA2W& ) throw();
CA2W& operator=( const CA2W& ) throw();
};
class CA2A
{
public:
CA2A(LPCSTR psz) throw(...) :
m_psz(psz)
{
_ASSERTE(psz);
}
CA2A(LPCSTR psz, UINT nCodePage) throw(...) :
m_psz(psz)
{
_ASSERTE(psz);
(void)nCodePage;
}
~CA2A() throw()
{
}
operator LPSTR() const throw()
{
return const_cast<LPSTR>(m_psz);
}
private:
LPCSTR m_psz;
// Hide the copy constructor and assignment operator.
CA2A( const CA2A& ) throw();
CA2A& operator=( const CA2A& ) throw();
};
// Declare macros for proper conversion
// based on whether UNICODE being defined.
#ifdef UNICODE
#define CT2W CW2W
#define CT2A CW2A
#define CW2T CW2W
#define CA2T CA2W
#else
#define CT2W CA2W
#define CT2A CA2A
#define CW2T CW2A
#define CA2T CA2A
#endif // UNICODE

BIN
libexec/MsiX/MsiX.pdb Normal file

Binary file not shown.

103
libexec/MsiX/MsiX.rc Normal file
View File

@ -0,0 +1,103 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", "Extracts transforms and streams from Windows Installer files."
VALUE "CompanyName", "Microsoft Corporation"
VALUE "FileDescription", "MSI Extractor"
VALUE "FileVersion", "1, 0, 0, 0"
VALUE "InternalName", "MsiX"
VALUE "LegalCopyright", "Copyright (C) Microsoft Corporation"
VALUE "OriginalFilename", "MsiX.exe"
VALUE "ProductName", "MSI Extractor"
VALUE "ProductVersion", "1, 0, 0, 0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

211
libexec/MsiX/MsiX.vcproj Normal file
View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="MsiX"
ProjectGUID="{CC64C520-EFC5-4947-B7FC-B50C54D9D734}"
RootNamespace="MsiX"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
EmbedManifest="false"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
EmbedManifest="false"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\MsiX.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\MsiX.h"
>
</File>
<File
RelativePath=".\resource.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath=".\MsiX.rc"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

14
libexec/MsiX/resource.h Normal file
View File

@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by MsiX.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

0
libexec/ShowVer.exe Normal file → Executable file
View File

0
libexec/UnRAR.exe Normal file → Executable file
View File

BIN
libexec/infozip/funzip.exe Normal file

Binary file not shown.

BIN
libexec/infozip/unzip.exe Normal file

Binary file not shown.

Binary file not shown.

BIN
libexec/infozip/zip.exe Normal file

Binary file not shown.

Binary file not shown.

BIN
libexec/infozip/zipnote.exe Normal file

Binary file not shown.

Binary file not shown.

0
libexec/inifile.exe Normal file → Executable file
View File

0
libexec/innounp.exe Normal file → Executable file
View File