export.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /*
  2. * Copyright 2017 Hugh McMaster
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. */
  18. #include <windows.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <wine/heap.h>
  22. #include "reg.h"
  23. static void write_file(HANDLE hFile, const WCHAR *str)
  24. {
  25. DWORD written;
  26. WriteFile(hFile, str, lstrlenW(str) * sizeof(WCHAR), &written, NULL);
  27. }
  28. static WCHAR *escape_string(WCHAR *str, size_t str_len, size_t *line_len)
  29. {
  30. size_t i, escape_count, pos;
  31. WCHAR *buf;
  32. for (i = 0, escape_count = 0; i < str_len; i++)
  33. {
  34. WCHAR c = str[i];
  35. if (!c) break;
  36. if (c == '\r' || c == '\n' || c == '\\' || c == '"')
  37. escape_count++;
  38. }
  39. buf = heap_xalloc((str_len + escape_count + 1) * sizeof(WCHAR));
  40. for (i = 0, pos = 0; i < str_len; i++, pos++)
  41. {
  42. WCHAR c = str[i];
  43. if (!c) break;
  44. switch (c)
  45. {
  46. case '\r':
  47. buf[pos++] = '\\';
  48. buf[pos] = 'r';
  49. break;
  50. case '\n':
  51. buf[pos++] = '\\';
  52. buf[pos] = 'n';
  53. break;
  54. case '\\':
  55. buf[pos++] = '\\';
  56. buf[pos] = '\\';
  57. break;
  58. case '"':
  59. buf[pos++] = '\\';
  60. buf[pos] = '"';
  61. break;
  62. default:
  63. buf[pos] = c;
  64. }
  65. }
  66. buf[pos] = 0;
  67. *line_len = pos;
  68. return buf;
  69. }
  70. static size_t export_value_name(HANDLE hFile, WCHAR *name, size_t len)
  71. {
  72. static const WCHAR quoted_fmt[] = {'"','%','s','"','=',0};
  73. static const WCHAR default_name[] = {'@','=',0};
  74. size_t line_len;
  75. if (name && *name)
  76. {
  77. WCHAR *str = escape_string(name, len, &line_len);
  78. WCHAR *buf = heap_xalloc((line_len + 4) * sizeof(WCHAR));
  79. line_len = swprintf(buf, line_len + 4, quoted_fmt, str);
  80. write_file(hFile, buf);
  81. heap_free(buf);
  82. heap_free(str);
  83. }
  84. else
  85. {
  86. line_len = lstrlenW(default_name);
  87. write_file(hFile, default_name);
  88. }
  89. return line_len;
  90. }
  91. static void export_string_data(WCHAR **buf, WCHAR *data, size_t size)
  92. {
  93. size_t len = 0, line_len;
  94. WCHAR *str;
  95. static const WCHAR fmt[] = {'"','%','s','"',0};
  96. if (size)
  97. len = size / sizeof(WCHAR) - 1;
  98. str = escape_string(data, len, &line_len);
  99. *buf = heap_xalloc((line_len + 3) * sizeof(WCHAR));
  100. swprintf(*buf, line_len + 3, fmt, str);
  101. heap_free(str);
  102. }
  103. static void export_dword_data(WCHAR **buf, DWORD *data)
  104. {
  105. static const WCHAR fmt[] = {'d','w','o','r','d',':','%','0','8','x',0};
  106. *buf = heap_xalloc(15 * sizeof(WCHAR));
  107. swprintf(*buf, 15, fmt, *data);
  108. }
  109. static size_t export_hex_data_type(HANDLE hFile, DWORD type)
  110. {
  111. static const WCHAR hex[] = {'h','e','x',':',0};
  112. static const WCHAR hexp_fmt[] = {'h','e','x','(','%','x',')',':',0};
  113. size_t line_len;
  114. if (type == REG_BINARY)
  115. {
  116. line_len = lstrlenW(hex);
  117. write_file(hFile, hex);
  118. }
  119. else
  120. {
  121. WCHAR *buf = heap_xalloc(15 * sizeof(WCHAR));
  122. line_len = swprintf(buf, 15, hexp_fmt, type);
  123. write_file(hFile, buf);
  124. heap_free(buf);
  125. }
  126. return line_len;
  127. }
  128. #define MAX_HEX_CHARS 77
  129. static void export_hex_data(HANDLE hFile, WCHAR **buf, DWORD type,
  130. DWORD line_len, void *data, DWORD size)
  131. {
  132. static const WCHAR fmt[] = {'%','0','2','x',0};
  133. static const WCHAR hex_concat[] = {'\\','\r','\n',' ',' ',0};
  134. size_t num_commas, i, pos;
  135. line_len += export_hex_data_type(hFile, type);
  136. if (!size) return;
  137. num_commas = size - 1;
  138. *buf = heap_xalloc(size * 3 * sizeof(WCHAR));
  139. for (i = 0, pos = 0; i < size; i++)
  140. {
  141. pos += swprintf(*buf + pos, 3, fmt, ((BYTE *)data)[i]);
  142. if (i == num_commas) break;
  143. (*buf)[pos++] = ',';
  144. (*buf)[pos] = 0;
  145. line_len += 3;
  146. if (line_len >= MAX_HEX_CHARS)
  147. {
  148. write_file(hFile, *buf);
  149. write_file(hFile, hex_concat);
  150. line_len = 2;
  151. pos = 0;
  152. }
  153. }
  154. }
  155. static void export_newline(HANDLE hFile)
  156. {
  157. static const WCHAR newline[] = {'\r','\n',0};
  158. write_file(hFile, newline);
  159. }
  160. static void export_data(HANDLE hFile, WCHAR *value_name, DWORD value_len,
  161. DWORD type, void *data, size_t size)
  162. {
  163. WCHAR *buf = NULL;
  164. size_t line_len = export_value_name(hFile, value_name, value_len);
  165. switch (type)
  166. {
  167. case REG_SZ:
  168. export_string_data(&buf, data, size);
  169. break;
  170. case REG_DWORD:
  171. if (size)
  172. {
  173. export_dword_data(&buf, data);
  174. break;
  175. }
  176. /* fall through */
  177. case REG_NONE:
  178. case REG_EXPAND_SZ:
  179. case REG_BINARY:
  180. case REG_MULTI_SZ:
  181. default:
  182. export_hex_data(hFile, &buf, type, line_len, data, size);
  183. break;
  184. }
  185. if (size || type == REG_SZ)
  186. {
  187. write_file(hFile, buf);
  188. heap_free(buf);
  189. }
  190. export_newline(hFile);
  191. }
  192. static void export_key_name(HANDLE hFile, WCHAR *name)
  193. {
  194. static const WCHAR fmt[] = {'\r','\n','[','%','s',']','\r','\n',0};
  195. WCHAR *buf;
  196. buf = heap_xalloc((lstrlenW(name) + 7) * sizeof(WCHAR));
  197. swprintf(buf, lstrlenW(name) + 7, fmt, name);
  198. write_file(hFile, buf);
  199. heap_free(buf);
  200. }
  201. static int export_registry_data(HANDLE hFile, HKEY key, WCHAR *path)
  202. {
  203. LONG rc;
  204. DWORD max_value_len = 256, value_len;
  205. DWORD max_data_bytes = 2048, data_size;
  206. DWORD subkey_len;
  207. DWORD i, type, path_len;
  208. WCHAR *value_name, *subkey_name, *subkey_path;
  209. BYTE *data;
  210. HKEY subkey;
  211. export_key_name(hFile, path);
  212. value_name = heap_xalloc(max_value_len * sizeof(WCHAR));
  213. data = heap_xalloc(max_data_bytes);
  214. i = 0;
  215. for (;;)
  216. {
  217. value_len = max_value_len;
  218. data_size = max_data_bytes;
  219. rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
  220. if (rc == ERROR_SUCCESS)
  221. {
  222. export_data(hFile, value_name, value_len, type, data, data_size);
  223. i++;
  224. }
  225. else if (rc == ERROR_MORE_DATA)
  226. {
  227. if (data_size > max_data_bytes)
  228. {
  229. max_data_bytes = data_size;
  230. data = heap_xrealloc(data, max_data_bytes);
  231. }
  232. else
  233. {
  234. max_value_len *= 2;
  235. value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR));
  236. }
  237. }
  238. else break;
  239. }
  240. heap_free(data);
  241. heap_free(value_name);
  242. subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
  243. path_len = lstrlenW(path);
  244. i = 0;
  245. for (;;)
  246. {
  247. subkey_len = MAX_SUBKEY_LEN;
  248. rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
  249. if (rc == ERROR_SUCCESS)
  250. {
  251. subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
  252. if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
  253. {
  254. export_registry_data(hFile, subkey, subkey_path);
  255. RegCloseKey(subkey);
  256. }
  257. heap_free(subkey_path);
  258. i++;
  259. }
  260. else break;
  261. }
  262. heap_free(subkey_name);
  263. return 0;
  264. }
  265. static void export_file_header(HANDLE hFile)
  266. {
  267. static const WCHAR header[] = { 0xfeff,'W','i','n','d','o','w','s',' ',
  268. 'R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ',
  269. 'V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n',0};
  270. write_file(hFile, header);
  271. }
  272. static HANDLE create_file(const WCHAR *filename, DWORD action)
  273. {
  274. return CreateFileW(filename, GENERIC_WRITE, 0, NULL, action, FILE_ATTRIBUTE_NORMAL, NULL);
  275. }
  276. static HANDLE get_file_handle(WCHAR *filename, BOOL overwrite_file)
  277. {
  278. HANDLE hFile = create_file(filename, overwrite_file ? CREATE_ALWAYS : CREATE_NEW);
  279. if (hFile == INVALID_HANDLE_VALUE)
  280. {
  281. DWORD error = GetLastError();
  282. if (error == ERROR_FILE_EXISTS)
  283. {
  284. if (!ask_confirm(STRING_OVERWRITE_FILE, filename))
  285. {
  286. output_message(STRING_CANCELLED);
  287. exit(0);
  288. }
  289. hFile = create_file(filename, CREATE_ALWAYS);
  290. }
  291. else
  292. {
  293. WCHAR *str;
  294. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
  295. FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (WCHAR *)&str, 0, NULL);
  296. output_writeconsole(str, lstrlenW(str));
  297. LocalFree(str);
  298. exit(1);
  299. }
  300. }
  301. return hFile;
  302. }
  303. static BOOL is_overwrite_switch(const WCHAR *s)
  304. {
  305. if (lstrlenW(s) > 2)
  306. return FALSE;
  307. if ((s[0] == '/' || s[0] == '-') && (s[1] == 'y' || s[1] == 'Y'))
  308. return TRUE;
  309. return FALSE;
  310. }
  311. int reg_export(int argc, WCHAR *argv[])
  312. {
  313. HKEY root, hkey;
  314. WCHAR *path, *long_key;
  315. BOOL overwrite_file = FALSE;
  316. HANDLE hFile;
  317. int ret;
  318. if (argc == 3 || argc > 5)
  319. goto error;
  320. if (!parse_registry_key(argv[2], &root, &path, &long_key))
  321. return 1;
  322. if (argc == 5 && !(overwrite_file = is_overwrite_switch(argv[4])))
  323. goto error;
  324. if (RegOpenKeyExW(root, path, 0, KEY_READ, &hkey))
  325. {
  326. output_message(STRING_INVALID_KEY);
  327. return 1;
  328. }
  329. hFile = get_file_handle(argv[3], overwrite_file);
  330. export_file_header(hFile);
  331. ret = export_registry_data(hFile, hkey, long_key);
  332. export_newline(hFile);
  333. CloseHandle(hFile);
  334. RegCloseKey(hkey);
  335. return ret;
  336. error:
  337. output_message(STRING_INVALID_SYNTAX);
  338. output_message(STRING_FUNC_HELP, wcsupr(argv[1]));
  339. return 1;
  340. }