crypt32: Add additional path for Solaris 11 Express.
[wine] / programs / dxdiag / output.c
1 /*
2  * DxDiag file information output
3  *
4  * Copyright 2011 Andrew Nguyen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22 #include <initguid.h>
23 #include <windows.h>
24 #include <msxml2.h>
25 #include <assert.h>
26 #include <stdio.h>
27
28 #include "wine/debug.h"
29 #include "wine/unicode.h"
30
31 #include "dxdiag_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);
34
35 static char output_buffer[1024];
36 static const char crlf[2] = "\r\n";
37
38 static const WCHAR DxDiag[] = {'D','x','D','i','a','g',0};
39
40 static const WCHAR SystemInformation[] = {'S','y','s','t','e','m','I','n','f','o','r','m','a','t','i','o','n',0};
41 static const WCHAR Time[] = {'T','i','m','e',0};
42 static const WCHAR MachineName[] = {'M','a','c','h','i','n','e','N','a','m','e',0};
43 static const WCHAR OperatingSystem[] = {'O','p','e','r','a','t','i','n','g','S','y','s','t','e','m',0};
44 static const WCHAR Language[] = {'L','a','n','g','u','a','g','e',0};
45 static const WCHAR SystemManufacturer[] = {'S','y','s','t','e','m','M','a','n','u','f','a','c','t','u','r','e','r',0};
46 static const WCHAR SystemModel[] = {'S','y','s','t','e','m','M','o','d','e','l',0};
47 static const WCHAR BIOS[] = {'B','I','O','S',0};
48 static const WCHAR Processor[] = {'P','r','o','c','e','s','s','o','r',0};
49 static const WCHAR Memory[] = {'M','e','m','o','r','y',0};
50 static const WCHAR PageFile[] = {'P','a','g','e','F','i','l','e',0};
51 static const WCHAR WindowsDir[] = {'W','i','n','d','o','w','s','D','i','r',0};
52 static const WCHAR DirectXVersion[] = {'D','i','r','e','c','t','X','V','e','r','s','i','o','n',0};
53 static const WCHAR DXSetupParameters[] = {'D','X','S','e','t','u','p','P','a','r','a','m','e','t','e','r','s',0};
54 static const WCHAR DxDiagVersion[] = {'D','x','D','i','a','g','V','e','r','s','i','o','n',0};
55 static const WCHAR DxDiagUnicode[] = {'D','x','D','i','a','g','U','n','i','c','o','d','e',0};
56 static const WCHAR DxDiag64Bit[] = {'D','x','D','i','a','g','6','4','B','i','t',0};
57
58 struct text_information_field
59 {
60     const char *field_name;
61     const WCHAR *value;
62 };
63
64 struct xml_information_field
65 {
66     const WCHAR *tag_name;
67     const WCHAR *value;
68 };
69
70 static BOOL output_text_header(HANDLE hFile, const char *caption)
71 {
72     DWORD len = strlen(caption);
73     DWORD total_len = 3 * (len + sizeof(crlf));
74     char *ptr = output_buffer;
75
76     assert(total_len <= sizeof(output_buffer));
77
78     memset(ptr, '-', len);
79     ptr += len;
80
81     memcpy(ptr, crlf, sizeof(crlf));
82     ptr += sizeof(crlf);
83
84     memcpy(ptr, caption, len);
85     ptr += len;
86
87     memcpy(ptr, crlf, sizeof(crlf));
88     ptr += sizeof(crlf);
89
90     memset(ptr, '-', len);
91     ptr += len;
92
93     memcpy(ptr, crlf, sizeof(crlf));
94     ptr += sizeof(crlf);
95
96     return WriteFile(hFile, output_buffer, total_len, NULL, NULL);
97 }
98
99 static BOOL output_text_field(HANDLE hFile, const char *field_name, DWORD field_width, const WCHAR *value)
100 {
101     DWORD value_lenW = strlenW(value);
102     DWORD value_lenA = WideCharToMultiByte(CP_ACP, 0, value, value_lenW, NULL, 0, NULL, NULL);
103     DWORD total_len = field_width + sizeof(": ") - 1 + value_lenA + sizeof(crlf);
104     char sprintf_fmt[1 + 10 + 3 + 1];
105     char *ptr = output_buffer;
106
107     assert(total_len <= sizeof(output_buffer));
108
109     sprintf(sprintf_fmt, "%%%us: ", field_width);
110     ptr += sprintf(ptr, sprintf_fmt, field_name);
111
112     ptr += WideCharToMultiByte(CP_ACP, 0, value, value_lenW, ptr, value_lenA, NULL, NULL);
113
114     memcpy(ptr, crlf, sizeof(crlf));
115     ptr += sizeof(crlf);
116
117     return WriteFile(hFile, output_buffer, total_len, NULL, NULL);
118 }
119
120 static BOOL output_crlf(HANDLE hFile)
121 {
122     return WriteFile(hFile, crlf, sizeof(crlf), NULL, NULL);
123 }
124
125 static inline void fill_system_text_output_table(struct dxdiag_information *dxdiag_info, struct text_information_field *fields)
126 {
127     fields[0].field_name = "Time of this report";
128     fields[0].value = dxdiag_info->system_info.szTimeEnglish;
129     fields[1].field_name = "Machine name";
130     fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
131     fields[2].field_name = "Operating System";
132     fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
133     fields[3].field_name = "Language";
134     fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
135     fields[4].field_name = "System Manufacturer";
136     fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
137     fields[5].field_name = "System Model";
138     fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
139     fields[6].field_name = "BIOS";
140     fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
141     fields[7].field_name = "Processor";
142     fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
143     fields[8].field_name = "Memory";
144     fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
145     fields[9].field_name = "Page File";
146     fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
147     fields[10].field_name = "Windows Dir";
148     fields[10].value = dxdiag_info->system_info.szWindowsDir;
149     fields[11].field_name = "DirectX Version";
150     fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
151     fields[12].field_name = "DX Setup Parameters";
152     fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
153     fields[13].field_name = "DxDiag Version";
154     fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
155 }
156
157 static BOOL output_text_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
158 {
159     struct information_block
160     {
161         const char *caption;
162         const size_t field_width;
163         struct text_information_field fields[50];
164     } output_table[] =
165     {
166         {"System Information", 19},
167     };
168
169     HANDLE hFile;
170     size_t i;
171
172     fill_system_text_output_table(dxdiag_info, output_table[0].fields);
173
174     hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
175                         NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
176     if (hFile == INVALID_HANDLE_VALUE)
177     {
178         WINE_ERR("File creation failed, last error %u\n", GetLastError());
179         return FALSE;
180     }
181
182     for (i = 0; i < sizeof(output_table)/sizeof(output_table[0]); i++)
183     {
184         const struct text_information_field *fields = output_table[i].fields;
185         unsigned int j;
186
187         output_text_header(hFile, output_table[i].caption);
188         for (j = 0; fields[j].field_name; j++)
189             output_text_field(hFile, fields[j].field_name, output_table[i].field_width, fields[j].value);
190         output_crlf(hFile);
191     }
192
193     CloseHandle(hFile);
194     return FALSE;
195 }
196
197 static IXMLDOMElement *xml_create_element(IXMLDOMDocument *xmldoc, const WCHAR *name)
198 {
199     BSTR bstr = SysAllocString(name);
200     IXMLDOMElement *ret;
201     HRESULT hr;
202
203     if (!bstr)
204         return NULL;
205
206     hr = IXMLDOMDocument_createElement(xmldoc, bstr, &ret);
207     SysFreeString(bstr);
208
209     return SUCCEEDED(hr) ? ret : NULL;
210 }
211
212 static HRESULT xml_put_element_text(IXMLDOMElement *element, const WCHAR *text)
213 {
214     BSTR bstr = SysAllocString(text);
215     HRESULT hr;
216
217     if (!bstr)
218         return E_OUTOFMEMORY;
219
220     hr = IXMLDOMElement_put_text(element, bstr);
221     SysFreeString(bstr);
222
223     return hr;
224 }
225
226 static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename)
227 {
228     BSTR bstr = SysAllocString(filename);
229     VARIANT destVar;
230     HRESULT hr;
231
232     if (!bstr)
233         return E_OUTOFMEMORY;
234
235     V_VT(&destVar) = VT_BSTR;
236     V_BSTR(&destVar) = bstr;
237
238     hr = IXMLDOMDocument_save(xmldoc, destVar);
239     VariantClear(&destVar);
240
241     return hr;
242 }
243
244 static inline void fill_system_xml_output_table(struct dxdiag_information *dxdiag_info, struct xml_information_field *fields)
245 {
246     static const WCHAR zeroW[] = {'0',0};
247     static const WCHAR oneW[] = {'1',0};
248
249     fields[0].tag_name = Time;
250     fields[0].value = dxdiag_info->system_info.szTimeEnglish;
251     fields[1].tag_name = MachineName;
252     fields[1].value = dxdiag_info->system_info.szMachineNameEnglish;
253     fields[2].tag_name = OperatingSystem;
254     fields[2].value = dxdiag_info->system_info.szOSExLongEnglish;
255     fields[3].tag_name = Language;
256     fields[3].value = dxdiag_info->system_info.szLanguagesEnglish;
257     fields[4].tag_name = SystemManufacturer;
258     fields[4].value = dxdiag_info->system_info.szSystemManufacturerEnglish;
259     fields[5].tag_name = SystemModel;
260     fields[5].value = dxdiag_info->system_info.szSystemModelEnglish;
261     fields[6].tag_name = BIOS;
262     fields[6].value = dxdiag_info->system_info.szBIOSEnglish;
263     fields[7].tag_name = Processor;
264     fields[7].value = dxdiag_info->system_info.szProcessorEnglish;
265     fields[8].tag_name = Memory;
266     fields[8].value = dxdiag_info->system_info.szPhysicalMemoryEnglish;
267     fields[9].tag_name = PageFile;
268     fields[9].value = dxdiag_info->system_info.szPageFileEnglish;
269     fields[10].tag_name = WindowsDir;
270     fields[10].value = dxdiag_info->system_info.szWindowsDir;
271     fields[11].tag_name = DirectXVersion;
272     fields[11].value = dxdiag_info->system_info.szDirectXVersionLongEnglish;
273     fields[12].tag_name = DXSetupParameters;
274     fields[12].value = dxdiag_info->system_info.szSetupParamEnglish;
275     fields[13].tag_name = DxDiagVersion;
276     fields[13].value = dxdiag_info->system_info.szDxDiagVersion;
277     fields[14].tag_name = DxDiagUnicode;
278     fields[14].value = oneW;
279     fields[15].tag_name = DxDiag64Bit;
280     fields[15].value = dxdiag_info->system_info.win64 ? oneW : zeroW;
281 }
282
283 static BOOL output_xml_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename)
284 {
285     struct information_block
286     {
287         const WCHAR *tag_name;
288         struct xml_information_field fields[50];
289     } output_table[] =
290     {
291         {SystemInformation},
292     };
293
294     IXMLDOMDocument *xmldoc = NULL;
295     IXMLDOMElement *dxdiag_element = NULL;
296     HRESULT hr;
297     size_t i;
298
299     fill_system_xml_output_table(dxdiag_info, output_table[0].fields);
300
301     hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
302                           &IID_IXMLDOMDocument, (void **)&xmldoc);
303     if (FAILED(hr))
304     {
305         WINE_ERR("IXMLDOMDocument instance creation failed with 0x%08x\n", hr);
306         goto error;
307     }
308
309     if (!(dxdiag_element = xml_create_element(xmldoc, DxDiag)))
310         goto error;
311
312     hr = IXMLDOMDocument_appendChild(xmldoc, (IXMLDOMNode *)dxdiag_element, NULL);
313     if (FAILED(hr))
314         goto error;
315
316     for (i = 0; i < sizeof(output_table)/sizeof(output_table[0]); i++)
317     {
318         IXMLDOMElement *info_element = xml_create_element(xmldoc, output_table[i].tag_name);
319         const struct xml_information_field *fields = output_table[i].fields;
320         unsigned int j = 0;
321
322         if (!info_element)
323             goto error;
324
325         hr = IXMLDOMElement_appendChild(dxdiag_element, (IXMLDOMNode *)info_element, NULL);
326         if (FAILED(hr))
327         {
328             IXMLDOMElement_Release(info_element);
329             goto error;
330         }
331
332         for (j = 0; fields[j].tag_name; j++)
333         {
334             IXMLDOMElement *field_element = xml_create_element(xmldoc, fields[j].tag_name);
335
336             if (!field_element)
337             {
338                 IXMLDOMElement_Release(info_element);
339                 goto error;
340             }
341
342             hr = xml_put_element_text(field_element, fields[j].value);
343             if (FAILED(hr))
344             {
345                 IXMLDOMElement_Release(field_element);
346                 IXMLDOMElement_Release(info_element);
347                 goto error;
348             }
349
350             hr = IXMLDOMElement_appendChild(info_element, (IXMLDOMNode *)field_element, NULL);
351             if (FAILED(hr))
352             {
353                 IXMLDOMElement_Release(field_element);
354                 IXMLDOMElement_Release(info_element);
355                 goto error;
356             }
357
358             IXMLDOMElement_Release(field_element);
359         }
360
361         IXMLDOMElement_Release(info_element);
362     }
363
364     hr = save_xml_document(xmldoc, filename);
365     if (FAILED(hr))
366         goto error;
367
368     IXMLDOMElement_Release(dxdiag_element);
369     IXMLDOMDocument_Release(xmldoc);
370     return TRUE;
371 error:
372     if (dxdiag_element) IXMLDOMElement_Release(dxdiag_element);
373     if (xmldoc) IXMLDOMDocument_Release(xmldoc);
374     return FALSE;
375 }
376
377 static struct output_backend
378 {
379     const WCHAR filename_ext[5];
380     BOOL (*output_handler)(struct dxdiag_information *, const WCHAR *filename);
381 } output_backends[] =
382 {
383     /* OUTPUT_TEXT */
384     {
385         {'.','t','x','t',0},
386         output_text_information,
387     },
388     /* OUTPUT_XML */
389     {
390         {'.','x','m','l',0},
391         output_xml_information,
392     },
393 };
394
395 const WCHAR *get_output_extension(enum output_type type)
396 {
397     assert(type > OUTPUT_NONE && type <= sizeof(output_backends)/sizeof(output_backends[0]));
398
399     return output_backends[type - 1].filename_ext;
400 }
401
402 BOOL output_dxdiag_information(struct dxdiag_information *dxdiag_info, const WCHAR *filename, enum output_type type)
403 {
404     assert(type > OUTPUT_NONE && type <= sizeof(output_backends)/sizeof(output_backends[0]));
405
406     return output_backends[type - 1].output_handler(dxdiag_info, filename);
407 }