1 /*
2 * regexpl - Console Registry Explorer
3 *
4 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 // ShellCommandValue.cpp: implementation of the CShellCommandValue class.
23 //
24 //////////////////////////////////////////////////////////////////////
25
26 #include "ph.h"
27 #include "RegistryExplorer.h"
28 #include "ShellCommandValue.h"
29 #include "RegistryTree.h"
30 #include "RegistryKey.h"
31
32 #define VALUE_CMD _T("VV")
33 #define VALUE_CMD_LENGTH COMMAND_LENGTH(VALUE_CMD)
34 #define VALUE_CMD_SHORT_DESC VALUE_CMD _T(" command is used to view value.\n")
35
36 //////////////////////////////////////////////////////////////////////
37 // Construction/Destruction
38 //////////////////////////////////////////////////////////////////////
39
CShellCommandValue(CRegistryTree & rTree)40 CShellCommandValue::CShellCommandValue(CRegistryTree& rTree):m_rTree(rTree)
41 {
42 }
43
~CShellCommandValue()44 CShellCommandValue::~CShellCommandValue()
45 {
46 }
47
Match(const TCHAR * pchCommand)48 BOOL CShellCommandValue::Match(const TCHAR *pchCommand)
49 {
50 if (_tcsicmp(pchCommand,VALUE_CMD) == 0)
51 return TRUE;
52 if (_tcsnicmp(pchCommand,VALUE_CMD _T(".."),VALUE_CMD_LENGTH+2*sizeof(TCHAR)) == 0)
53 return TRUE;
54 if (_tcsnicmp(pchCommand,VALUE_CMD _T("/"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
55 return TRUE;
56 if (_tcsnicmp(pchCommand,VALUE_CMD _T("\\"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
57 return TRUE;
58 return FALSE;
59 }
60
Execute(CConsole & rConsole,CArgumentParser & rArguments)61 int CShellCommandValue::Execute(CConsole &rConsole, CArgumentParser& rArguments)
62 {
63 rArguments.ResetArgumentIteration();
64 TCHAR *pchCommandItself = rArguments.GetNextArgument();
65
66 TCHAR *pchParameter;
67 TCHAR *pchValueFull = NULL;
68 BOOL blnUnicodeDump = FALSE;
69 BOOL blnBadParameter = FALSE;
70 BOOL blnHelp = FALSE;
71 LONG nError;
72 DWORD dwValueSize;
73 DWORD dwType = REG_NONE;
74 BYTE *pDataBuffer = NULL;
75 TCHAR *pchFilename = NULL;
76
77 if ((_tcsnicmp(pchCommandItself,VALUE_CMD _T(".."),VALUE_CMD_LENGTH+2*sizeof(TCHAR)) == 0)||
78 (_tcsnicmp(pchCommandItself,VALUE_CMD _T("\\"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0))
79 {
80 pchValueFull = pchCommandItself + VALUE_CMD_LENGTH;
81 }
82 else if (_tcsnicmp(pchCommandItself,VALUE_CMD _T("/"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0)
83 {
84 pchParameter = pchCommandItself + VALUE_CMD_LENGTH;
85 goto CheckValueArgument;
86 }
87
88 while((pchParameter = rArguments.GetNextArgument()) != NULL)
89 {
90 CheckValueArgument:
91 blnBadParameter = FALSE;
92 if ((_tcsicmp(pchParameter,_T("/?")) == 0)
93 ||(_tcsicmp(pchParameter,_T("-?")) == 0))
94 {
95 blnHelp = TRUE;
96 break;
97 }
98 else if (_tcsicmp(pchParameter,_T("/u")) == 0)
99 {
100 blnUnicodeDump = TRUE;
101 }
102 else if ((*pchParameter == _T('/'))&&(*(pchParameter+1) == _T('f')))
103 {
104 pchFilename = pchParameter+2;
105 }
106 else if (!pchValueFull)
107 {
108 pchValueFull = pchParameter;
109 }
110 else
111 {
112 blnBadParameter = TRUE;
113 }
114 if (blnBadParameter)
115 {
116 rConsole.Write(_T("Bad parameter: "));
117 rConsole.Write(pchParameter);
118 rConsole.Write(_T("\n"));
119 }
120 }
121
122 CRegistryKey Key;
123 TCHAR *pchValueName;
124 const TCHAR *pszEmpty = _T("");
125 const TCHAR *pszPath;
126
127 if (blnHelp)
128 {
129 rConsole.Write(GetHelpString());
130
131 if (pDataBuffer)
132 delete pDataBuffer;
133
134 return 0;
135 }
136
137 if (pchValueFull)
138 {
139 if (_tcscmp(pchValueFull,_T("\\")) == 0)
140 goto ValueCommandNAonRoot;
141
142 TCHAR *pchSep = _tcsrchr(pchValueFull,_T('\\'));
143 pchValueName = pchSep?(pchSep+1):(pchValueFull);
144 pszPath = pchSep?pchValueFull:_T(".");
145
146 //if (_tcsrchr(pchValueName,_T('.')))
147 //{
148 // pchValueName = _T("");
149 // pchPath = pchValueFull;
150 //}
151 //else
152 if (pchSep)
153 *pchSep = 0;
154 }
155 else
156 {
157 pchValueName = (TCHAR*)pszEmpty;
158 pszPath = _T(".");
159 }
160
161 if (!m_rTree.GetKey(pszPath,KEY_READ,Key))
162 {
163 rConsole.Write(m_rTree.GetLastErrorDescription());
164 goto SkipValueCommand;
165 }
166
167 if (Key.IsRoot())
168 goto ValueCommandNAonRoot;
169
170 {
171 rConsole.Write(_T("Value name : \""));
172 rConsole.Write(_T("\\"));
173 rConsole.Write(Key.GetKeyName());
174 size_t l = _tcslen(pchValueName);
175 if (l&&
176 (*pchValueName == _T('\"'))&&
177 (pchValueName[l-1] == _T('\"')))
178 {
179 pchValueName[l-1] = 0;
180 pchValueName++;
181 }
182 rConsole.Write(pchValueName);
183 rConsole.Write(_T("\"\n"));
184
185 nError = Key.GetValue(pchValueName,NULL,NULL,&dwValueSize);
186 if (nError == ERROR_SUCCESS)
187 {
188 pDataBuffer = new BYTE [dwValueSize];
189 Key.GetValue(pchValueName,&dwType,pDataBuffer,&dwValueSize);
190 rConsole.Write(_T("Value type : "));
191 rConsole.Write(CRegistryKey::GetValueTypeName(dwType));
192 rConsole.Write(_T("\nValue data : "));
193 switch(dwType)
194 {
195 case REG_DWORD_LITTLE_ENDIAN:
196 {
197 TCHAR Buffer[3];
198 rConsole.Write(_T("0x"));
199 for (unsigned int i = 0 ; i < dwValueSize ; i++)
200 {
201 _stprintf(Buffer,_T("%02X"),*(pDataBuffer+((dwValueSize-1)-i)));
202 rConsole.Write(Buffer);
203 }
204 }
205 rConsole.Write(_T("\n"));
206 break;
207 case REG_DWORD_BIG_ENDIAN:
208 {
209 TCHAR Buffer[3];
210 rConsole.Write(_T("0x"));
211 for (unsigned int i = 0 ; i < dwValueSize ; i++)
212 {
213 _stprintf(Buffer,_T("%02X"),*(pDataBuffer+i));
214 rConsole.Write(Buffer);
215 }
216 }
217 rConsole.Write(_T("\n"));
218 break;
219 case REG_LINK:
220 break;
221 case REG_MULTI_SZ:
222 {
223 TCHAR *pchCurrentString = (TCHAR *)pDataBuffer;
224 rConsole.Write(_T("\n"));
225 while(*pchCurrentString)
226 {
227 rConsole.Write(_T("\""));
228 rConsole.Write(pchCurrentString);
229 rConsole.Write(_T("\"\n"));
230 pchCurrentString += _tcslen(pchCurrentString)+1;
231 }
232 }
233 break;
234 case REG_RESOURCE_LIST:
235 break;
236 case REG_SZ:
237 case REG_EXPAND_SZ:
238 rConsole.Write(_T("\""));
239 rConsole.Write((TCHAR *)pDataBuffer);
240 rConsole.Write(_T("\"\n"));
241 break;
242 case REG_BINARY:
243 default:
244 {
245 TCHAR Buffer[256];
246 DWORD i, j;
247 for (i = 0 ; i < dwValueSize ; i++)
248 {
249 if (i%16 == 0)
250 { // ok this is begining of line
251 rConsole.Write(_T("\n"));
252 // print offset
253 _stprintf(Buffer,_T("0x%08X "),(unsigned int)i);
254 rConsole.Write(Buffer);
255 }
256 else if (i%8 == 0)
257 { // this is the additional space between 7th and 8th byte in current line
258 rConsole.Write(_T(" "));
259 }
260
261 // print current byte
262 unsigned int n = *(pDataBuffer+i);
263 _stprintf(Buffer,_T("%02X "),n);
264 rConsole.Write(Buffer);
265
266 if (i && (i%16 == 15))
267 { // if this is the last byte in line
268 // Dump text representation
269 for (j = i-15; j <= i; j += blnUnicodeDump?2:1)\
270 {
271 if ((j%8 == 0)&&(j%16 != 0))
272 { // this is the additional space between 7th and 8th byte in current line
273 rConsole.Write(_T(" "));
274 }
275 ASSERT(i-j < 16);
276 // write current char representation
277 if (blnUnicodeDump)
278 {
279 ASSERT(j%2 == 0);
280 wchar_t ch = *(TCHAR *)(pDataBuffer+j);
281
282 _stprintf(Buffer,
283 #ifdef _UNICODE
284 _T("%c"),
285 #else
286 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3))
287 // %C in format string is a Microsoft extension.
288 _T("%C"),
289 #endif
290 iswprint(ch)?ch:L'.');
291 }
292 else
293 {
294 unsigned char ch = *(pDataBuffer+j);
295
296 _stprintf(Buffer,
297 #ifdef _UNICODE
298 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3))
299 // %C in format string is a Microsoft extension.
300 _T("%C"),
301 #else
302 _T("%c"),
303 #endif
304 isprint(ch)?ch:'.');
305 }
306 rConsole.Write(Buffer);
307 } // for
308 } // if
309 } // for
310
311 // print text representation of last line if it is not full (it have less than 16 bytes)
312 // k is pseudo offset
313 for (DWORD k = i; k%16 != 0; k++)
314 {
315 if (k%8 == 0)
316 { // this is the additional space between 7th and 8th byte in current line
317 rConsole.Write(_T(" "));
318 }
319 _tcscpy(Buffer,_T(" ")); // the replacement of two digit of current byte + spacing
320 rConsole.Write(Buffer);
321 if (k && (k%16 == 15))
322 { // if this is the last byte in line
323 ASSERT((k-15)%16 == 0); // k-15 must point at begin of last line
324 for (j = k-15; j < i; j += blnUnicodeDump?2:1)
325 {
326 if (blnUnicodeDump&&(j+1 >= i))
327 { // ok, buffer size is odd number, so we don't display last byte.
328 ASSERT(j+1 == i);
329 break;
330 }
331 if ((j%8 == 0)&&(j%16 != 0))
332 { // this is the additional space between 7th and 8th byte in current line
333 rConsole.Write(_T(" "));
334 }
335
336 // write current char representation
337 if (blnUnicodeDump)
338 {
339 ASSERT(j%2 == 0);
340 wchar_t ch = *(TCHAR *)(pDataBuffer+j);
341
342 _stprintf(Buffer,
343 #ifdef _UNICODE
344 _T("%c"),
345 #else
346 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3))
347 // %C in format string is a Microsoft extension.
348 _T("%C"),
349 #endif
350 iswprint(ch)?ch:L'.');
351 }
352 else
353 {
354 unsigned char ch = *(pDataBuffer+j);
355
356 _stprintf(Buffer,
357 #ifdef _UNICODE
358 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3))
359 // %C in format string is a Microsoft extension.
360 _T("%C"),
361 #else
362 _T("%c"),
363 #endif
364 isprint(ch)?ch:'.');
365 }
366 rConsole.Write(Buffer);
367 } // for
368 } // if
369 } // for
370 } // default:
371 rConsole.Write(_T("\n"));
372 } // switch
373 rConsole.Write(_T("\n"));
374
375 if (pchFilename)
376 {
377 rConsole.Write(_T("Exporting value data to "));
378 rConsole.Write(pchFilename);
379 rConsole.Write(_T(" ...\n"));
380
381 HANDLE hFile = CreateFile(pchFilename,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
382 if (hFile == INVALID_HANDLE_VALUE)
383 {
384 rConsole.Write(_T("Cannot create new file "));
385 rConsole.Write(pchFilename);
386 rConsole.Write(_T("\n"));
387 goto SkipValueCommand;
388 }
389
390 DWORD dwBytesWritten;
391 if (!WriteFile(hFile,pDataBuffer,dwValueSize,&dwBytesWritten,NULL))
392 {
393 rConsole.Write(_T("Error writing file.\n"));
394 VERIFY(CloseHandle(hFile));
395 goto SkipValueCommand;
396 }
397
398 ASSERT(dwBytesWritten == dwValueSize);
399 VERIFY(CloseHandle(hFile));
400 }
401 }
402 else
403 {
404 rConsole.Write(_T("Error "));
405 TCHAR Buffer[256];
406 rConsole.Write(_itoa(nError,Buffer,10));
407 rConsole.Write(_T("\n"));
408 if (nError == ERROR_FILE_NOT_FOUND)
409 {
410 rConsole.Write(_T("(System cannot find the value specified)\n"));
411 }
412 }
413 }
414
415 SkipValueCommand:
416 if (pDataBuffer)
417 delete[] pDataBuffer;
418 return 0;
419 ValueCommandNAonRoot:
420 rConsole.Write(VALUE_CMD COMMAND_NA_ON_ROOT);
421 return 0;
422 }
423
GetHelpString()424 const TCHAR * CShellCommandValue::GetHelpString()
425 {
426 return VALUE_CMD_SHORT_DESC
427 _T("Syntax: ") VALUE_CMD _T(" [<PATH>][<VALUE_NAME>] [/u] [/?]\n\n")
428 _T(" <PATH> - Optional relative path of key which value will be processed.\n")
429 _T(" <VALUE_NAME> - Name of key's value. Default is key's default value.\n")
430 _T(" /u - On binary dump view as Unicode.\n")
431 _T(" /fFILE - Export value data to FILE.\n")
432 _T(" /? - This help.\n\n")
433 _T("Without parameters, command displays default value of current key.\n");
434 }
435
GetHelpShortDescriptionString()436 const TCHAR * CShellCommandValue::GetHelpShortDescriptionString()
437 {
438 return VALUE_CMD_SHORT_DESC;
439 }
440