1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
24 #pragma warning(disable:4740)
25 #endif
26 
27 #include "macros.h"
28 
29 #ifdef __cplusplus
30 #define local inline
31 #else
32 #define local static
33 #endif
34 
SkipBlanks(LPCWSTR lpScan)35 local LPCWSTR SkipBlanks( LPCWSTR lpScan )
36 {
37 	while ( ' ' == *lpScan || '\t' == *lpScan )
38 		lpScan++;
39 
40 	return lpScan;
41 }
42 
43 
SkipArgument(LPCWSTR lpScan)44 local LPCWSTR SkipArgument( LPCWSTR lpScan )
45 {
46 	BOOL	fQuoted = FALSE;
47 	LPCWSTR	lpArgEnd = NULL;
48 
49 	do
50 	{
51 		switch ( *lpScan )
52 		{
53 		case ' ':
54 		case '\t':
55 			if ( fQuoted )
56 				lpScan++;
57 			else
58 				lpArgEnd = lpScan;
59 			break;
60 		case '\"':
61 			lpScan++;
62 			fQuoted = !fQuoted;
63 			break;
64 		case '\0':
65 			lpArgEnd = lpScan;
66 			break;
67 		default:
68 			lpScan++;
69 			break;
70 		}
71 	} while( *lpScan && !lpArgEnd );
72 
73 	return lpScan;
74 }
75 
76 
77 IMPLEMENT_THUNK( shell32, WINDOWS, LPWSTR *, WINAPI, CommandLineToArgvW, ( LPCWSTR lpCmdLineW, int *pNumArgs ) )
78 {
79 	LPWSTR	*lpArgvW = NULL;
80 
81 	if ( !lpCmdLineW || !*lpCmdLineW )
82 	{
83 		CHAR	szFileName[MAX_PATH];
84 
85 		DWORD	dwResult = GetModuleFileNameA( NULL, szFileName, MAX_PATH );
86 
87 		if ( dwResult && dwResult < MAX_PATH )
88 		{
89 			int cchNeeded = MultiByteToWideChar( CP_ACP, 0, szFileName, -1, NULL, 0 );
90 
91 			lpArgvW = (LPWSTR *)GlobalAlloc( 0, cchNeeded * sizeof(WCHAR) + sizeof(LPWSTR) );
92 
93 			if ( lpArgvW )
94 			{
95 				lpArgvW[0] = (LPWSTR)(lpArgvW + 1);
96 
97 				MultiByteToWideChar( CP_ACP, 0, szFileName, -1, lpArgvW[0], cchNeeded );
98 				*pNumArgs = 1;
99 			}
100 			else
101 				SetLastError( ERROR_OUTOFMEMORY );
102 		}
103 	}
104 	else
105 	{
106 		LPCWSTR	lpScan = lpCmdLineW;
107 		int		nTokens = 0;
108 		int		cchNeeded = 0;
109 
110 		// Count arguments and required size
111 
112 		while ( *lpScan )
113 		{
114 			lpScan = SkipBlanks( lpScan );
115 			if ( *lpScan )
116 			{
117 				LPCWSTR	lpArgEnd = SkipArgument( lpScan );
118 
119 				nTokens++;
120 				cchNeeded += lpArgEnd - lpScan + 1;
121 				lpScan = lpArgEnd;
122 			}
123 		}
124 
125 		// Allocate space for one additional NULL pointer to terminate list
126 
127 		lpArgvW = (LPWSTR *)GlobalAlloc( 0, sizeof(LPWSTR) * (nTokens + 1) + sizeof(WCHAR) * cchNeeded );
128 
129 		if ( lpArgvW )
130 		{
131 			// Collect arguments
132 
133 			LPWSTR	lpDestination = (LPWSTR)&lpArgvW[nTokens + 1];
134 
135 			lpScan = lpCmdLineW;
136 			nTokens = 0;
137 
138 			while ( *lpScan )
139 			{
140 				lpScan = SkipBlanks( lpScan );
141 				if ( *lpScan )
142 				{
143 					LPCWSTR	lpArgEnd = SkipArgument( lpScan );
144 
145 					lpArgvW[nTokens++] = lpDestination;
146 
147 					while ( lpScan < lpArgEnd )
148 					{
149 						if ( '\"' != *lpScan )
150 							*lpDestination++ = *lpScan;
151 
152 						lpScan++;
153 					}
154 					*lpDestination++ = 0;
155 				}
156 			}
157 
158 			lpArgvW[nTokens] = NULL;
159 
160 			*pNumArgs = nTokens;
161 		}
162 		else
163 			SetLastError( ERROR_OUTOFMEMORY );
164 
165 	}
166 
167 	return lpArgvW;
168 }