OSDN Git Service

Disable annoying warnings Disable 4018 (signed/unsigned) and 4996 (strcpy etc unsafe...
[tortoisegit/TortoiseGitJp.git] / src / crashrpt / WriteRegistry.cpp
1 ///////////////////////////////////////////////////////////////////////////////\r
2 //\r
3 //  Module: WriteRegistry.cpp\r
4 //\r
5 //    Desc: Functions to write a registry hive to a file.\r
6 //\r
7 // Copyright (c) 2003 Grant McDorman\r
8 // This file is licensed using a BSD-type license:\r
9 //  This software is provided 'as-is', without any express or implied\r
10 //  warranty.  In no event will the authors be held liable for any damages\r
11 //  arising from the use of this software.\r
12 //\r
13 //  Permission is granted to anyone to use this software for any purpose,\r
14 //  including commercial applications, and to alter it and redistribute it\r
15 //  freely, subject to the following restrictions:\r
16 //\r
17 //  1. The origin of this software must not be misrepresented; you must not\r
18 //     claim that you wrote the original software. If you use this software\r
19 //     in a product, an acknowledgment in the product documentation would be\r
20 //     appreciated but is not required.\r
21 //  2. Altered source versions must be plainly marked as such, and must not be\r
22 //     misrepresented as being the original software.\r
23 //  3. This notice may not be removed or altered from any source distribution.\r
24 //\r
25 ///////////////////////////////////////////////////////////////////////////////\r
26 #include <StdAfx.h>\r
27 \r
28 #include <windows.h>    // CreateFile, WriteFile, CloseHandle, DeleteFile, Reg* functions\r
29 #include <stdio.h>          // _snprintf\r
30 \r
31 #include "WriteRegistry.h"\r
32 \r
33 static bool WriteRegValue(HANDLE hFile, const char *key_path, const char *name, int name_len, DWORD type, const unsigned char *data, DWORD data_len);\r
34 static bool WriteValuesAndSubkeys(const char *key_path, HKEY parent_key, const char *subkey, HANDLE hFile);\r
35 static void WriteFileString(HANDLE hFile, const char *string);\r
36 \r
37 bool WriteRegistryTreeToFile(const char *key, const char *filename)\r
38 {\r
39         const char *cp = strchr(key, '\\');\r
40         if (cp == NULL) {\r
41                 return false;\r
42         }\r
43         ptrdiff_t len = cp - key;\r
44         HKEY hKey = 0;\r
45 \r
46 #define IS_PATH(id, short_id) if (strncmp(key, #id, len) == 0 || strncmp(key, #short_id, len) == 0) hKey = id\r
47     IS_PATH(HKEY_CLASSES_ROOT, HKCR);\r
48     else IS_PATH(HKEY_CURRENT_USER, HKCU);\r
49     else IS_PATH(HKEY_LOCAL_MACHINE, HKLM);\r
50     else IS_PATH(HKEY_CURRENT_CONFIG, HKCC);\r
51     else IS_PATH(HKEY_USERS, HKU);\r
52     else IS_PATH(HKEY_PERFORMANCE_DATA, HKPD);\r
53     else IS_PATH(HKEY_DYN_DATA, HKDD);\r
54         else {\r
55                 return false;\r
56         }\r
57         return WriteRegistryTreeToFile(hKey, cp + 1, filename);\r
58 }\r
59 \r
60 bool WriteRegistryTreeToFile(HKEY section, const char *subkey, const char *filename)\r
61 {\r
62     bool status = false;\r
63     HANDLE hFile = ::CreateFile(\r
64                                 filename,\r
65                                 GENERIC_READ | GENERIC_WRITE,\r
66                                 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
67                                 NULL,\r
68                                 CREATE_ALWAYS,\r
69                                 FILE_ATTRIBUTE_NORMAL,\r
70                                 0);\r
71     if (INVALID_HANDLE_VALUE != hFile) {\r
72                 char * key_path = "UNKNOWN";\r
73 #define SET_PATH(id) if (id == section) key_path = #id\r
74         SET_PATH(HKEY_CLASSES_ROOT);\r
75         else SET_PATH(HKEY_CURRENT_USER);\r
76         else SET_PATH(HKEY_LOCAL_MACHINE);\r
77         else SET_PATH(HKEY_CURRENT_CONFIG);\r
78         else SET_PATH(HKEY_USERS);\r
79         else SET_PATH(HKEY_PERFORMANCE_DATA);\r
80         else SET_PATH(HKEY_DYN_DATA);\r
81                 WriteFileString(hFile, "REGEDIT4\r\n");\r
82 #undef SET_PATH\r
83         try {\r
84             status = WriteValuesAndSubkeys(key_path, section, subkey, hFile);\r
85         } catch (...) {\r
86             status = false;\r
87         }\r
88         CloseHandle(hFile);\r
89         if (!status) {\r
90             DeleteFile(filename);\r
91         }\r
92         }\r
93     return status;\r
94 }\r
95 \r
96 static bool WriteValuesAndSubkeys(const char *key_path, HKEY parent_key, const char *subkey, HANDLE hFile)\r
97 {\r
98     HKEY key;\r
99 \r
100     if (RegOpenKeyEx(parent_key, subkey, 0, KEY_READ, &key) != ERROR_SUCCESS) {\r
101                 OutputDebugString("RegOpenKeyEx failed, key:\n");\r
102                 OutputDebugString(subkey);\r
103         return false;\r
104     }\r
105     DWORD num_subkeys;\r
106     DWORD max_subkey_len;\r
107     DWORD num_values;\r
108     DWORD max_name_len;\r
109     DWORD max_value_len;\r
110     DWORD max_id_len;\r
111 \r
112     if (RegQueryInfoKey(key,\r
113                                                 NULL, // class\r
114                                                 NULL, // num_class\r
115                                                 NULL, // reserved\r
116                         &num_subkeys, &max_subkey_len,\r
117                                                 NULL, // MaxClassLen\r
118                                                 &num_values, &max_name_len, &max_value_len, NULL, NULL) != ERROR_SUCCESS) {\r
119                 OutputDebugString("RegQueryInfoKey failed, key:\n");\r
120                 OutputDebugString(subkey);\r
121         return false;\r
122     }\r
123 \r
124     max_id_len = (max_name_len > max_subkey_len) ? max_name_len : max_subkey_len;\r
125     char *this_path = reinterpret_cast<char *>(alloca(strlen(key_path) + strlen(subkey) + 2));\r
126     // strcpy/strcat safe because of above alloca\r
127     strcpy(this_path, key_path);\r
128         strcat(this_path, "\\");\r
129     strcat(this_path, subkey);\r
130 \r
131     WriteFileString(hFile, "\r\n[");\r
132     WriteFileString(hFile, this_path);\r
133     WriteFileString(hFile, "]\r\n");\r
134 \r
135     // enumerate values\r
136     char *name = reinterpret_cast<char *>(alloca(max_id_len*2 + 2));\r
137     unsigned char *data = reinterpret_cast<unsigned char *>(alloca(max_value_len*2 + 2));\r
138     DWORD index;\r
139     bool status = true;\r
140 \r
141     for (index = 0; index < num_values && status; index++) {\r
142         DWORD name_len = max_id_len + 1;\r
143         DWORD value_len = max_value_len + 1;\r
144             DWORD type;\r
145         if (RegEnumValue(key, index, name, &name_len, NULL, &type, data, &value_len) == ERROR_SUCCESS) {\r
146             status = WriteRegValue(hFile, this_path, name, name_len, type, data, value_len);\r
147         }\r
148     }\r
149 \r
150     // enumerate subkeys\r
151     for (index = 0; index < num_subkeys && status; index++) {\r
152         DWORD name_len = max_id_len + 1;\r
153         if (RegEnumKeyEx(key, index, name, &name_len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {\r
154             status = WriteValuesAndSubkeys(this_path, key, name, hFile);\r
155         }\r
156     }\r
157 \r
158     RegCloseKey(key);\r
159 \r
160     return status;\r
161 }\r
162 \r
163 static bool WriteRegValue(HANDLE hFile, const char * /*key_path*/, const char *name, int /* name_len */, DWORD type, const unsigned char *data, DWORD data_len)\r
164 {\r
165         WriteFileString(hFile, "\"");\r
166     WriteFileString(hFile, name);\r
167 \r
168     char string_type[64];\r
169 \r
170     switch(type) {\r
171      case REG_DWORD:  // A 32-bit number.\r
172         strncpy(string_type, "\"=dword:", sizeof string_type);\r
173         break;\r
174 \r
175      case REG_SZ: // A null terminated string.\r
176         strncpy(string_type, "\"=\"", sizeof string_type);\r
177         break;\r
178 \r
179      case REG_BINARY: // Binary data in any form.\r
180         strncpy(string_type, "\"=hex:", sizeof string_type);\r
181         break;\r
182 \r
183      case REG_EXPAND_SZ: // A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions. To expand the environment variable references, use the ExpandEnvironmentStrings function.\r
184      case REG_LINK: // A Unicode symbolic link. Used internally; applications should not use this type.\r
185      case REG_MULTI_SZ: // An array of null-terminated strings, terminated by two null characters. \r
186      case REG_NONE: // No defined value type.\r
187      case REG_DWORD_BIG_ENDIAN: // A 64-bit number in big-endian format.\r
188      case REG_RESOURCE_LIST: // A device-driver resource list.\r
189      default:\r
190         _snprintf(string_type, sizeof string_type, "\"=hex(%x):", type);\r
191         break;\r
192     }\r
193 \r
194     WriteFileString(hFile, string_type);\r
195 \r
196     if (type == REG_SZ || type == REG_EXPAND_SZ) {\r
197         // escape special characters; length includes trailing NUL\r
198         int i;\r
199                 // don't crash'n'burn if data_len is 0\r
200         for (i = 0; i < static_cast<int>(data_len) - 1; i++) {\r
201             if (data[i] == '\\' || data[i] == '"') {\r
202                 WriteFileString(hFile, "\\");\r
203             }\r
204             if (isprint(data[i])) {\r
205                                 DWORD written;\r
206                 if (!WriteFile(hFile, &data[i], 1, &written, NULL) || written != 1) {\r
207                     return false;\r
208                 }\r
209             } else {\r
210                 _snprintf(string_type, sizeof string_type, "\\%02x", data[i]);\r
211                 WriteFileString(hFile, string_type);\r
212             }\r
213         }\r
214                 WriteFileString(hFile, "\"");\r
215     } else if (type == REG_DWORD) {\r
216         // write as hex, MSB first\r
217         int i;\r
218         for (i = static_cast<int>(data_len) - 1; i >= 0; i--) {\r
219             _snprintf(string_type, sizeof string_type, "%02x", data[i]);\r
220             WriteFileString(hFile, string_type);\r
221         }\r
222     } else {\r
223         // write as comma-separated hex values\r
224         DWORD i;\r
225         for (i = 0; i < data_len; i++) {\r
226             _snprintf(string_type, sizeof string_type, "%s%02x", i > 0 ? "," : "", data[i]);\r
227             WriteFileString(hFile, string_type);\r
228             if (i > 0 && i % 16 == 0) {\r
229                 WriteFileString(hFile, "\r\n");\r
230             }\r
231         }\r
232     }\r
233     WriteFileString(hFile, "\r\n");\r
234 \r
235         return true;\r
236 }\r
237 \r
238                   \r
239                 \r
240 static void WriteFileString(HANDLE hFile, const char *string)\r
241 {\r
242     DWORD written;\r
243     if (!WriteFile(hFile, string, strlen(string), &written, NULL) || written != strlen(string)) {\r
244                 OutputDebugString("WriteFile failed\n");\r
245         throw false;\r
246     }\r
247 }\r