1 /*
2  * PROJECT:     ReactOS Automatic Testing Utility
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Various helper functions
5  * COPYRIGHT:   Copyright 2008-2015 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 #define DBGPRINT_BUFSIZE   511
11 static const char HexCharacters[] = "0123456789ABCDEF";
12 
13 /**
14  * Escapes a string according to RFC 1738.
15  * Required for passing parameters to the web service.
16  *
17  * @param Input
18  * Constant pointer to a char array, which contains the input buffer to escape.
19  *
20  * @return
21  * The escaped string as std::string.
22  */
23 string
24 EscapeString(const char* Input)
25 {
26     string ReturnedString;
27 
28     do
29     {
30         if(strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~", *Input))
31         {
32             /* It's a character we don't need to escape, just add it to the output string */
33             ReturnedString += *Input;
34         }
35         else
36         {
37             /* We need to escape this character */
38             ReturnedString += '%';
39             ReturnedString += HexCharacters[((UCHAR)*Input >> 4) % 16];
40             ReturnedString += HexCharacters[(UCHAR)*Input % 16];
41         }
42     }
43     while(*++Input);
44 
45     return ReturnedString;
46 }
47 
48 /**
49  * Escapes a string according to RFC 1738.
50  * Required for passing parameters to the web service.
51  *
52  * @param Input
53  * Pointer to a std::string, which contains the input buffer to escape.
54  *
55  * @return
56  * The escaped string as std::string.
57  */
58 string
59 EscapeString(const string& Input)
60 {
61     return EscapeString(Input.c_str());
62 }
63 
64 /**
65  * Determines whether a string contains entirely numeric values.
66  *
67  * @param Input
68  * Constant pointer to a char array containing the input to check.
69  *
70  * @return
71  * true if the string is entirely numeric, false otherwise.
72  */
73 bool
74 IsNumber(const char* Input)
75 {
76     do
77     {
78         if(!isdigit(*Input))
79             return false;
80 
81         ++Input;
82     }
83     while(*Input);
84 
85     return true;
86 }
87 
88 /**
89  * Outputs a string through the standard output and the debug output.
90  * The string may have LF or CRLF line endings.
91  *
92  * @param String
93  * The std::string to output
94  */
95 string
96 StringOut(const string& String, bool forcePrint)
97 {
98     char DbgString[DBGPRINT_BUFSIZE + 1];
99     size_t i, start = 0, last_newline = 0, size = 0, curr_pos = 0;
100     string NewString;
101 
102     /* Unify the line endings (the piped output of the tests may use CRLF) */
103     for(i = 0; i < String.size(); i++)
104     {
105         /* If this is a CRLF line-ending, only copy a \n to the new string and skip the next character */
106         if(String[i] == '\r' && String[i + 1] == '\n')
107         {
108             NewString += '\n';
109             ++i;
110         }
111         else
112         {
113             /* Otherwise copy the string */
114             NewString += String[i];
115         }
116 
117         curr_pos = NewString.size();
118 
119         /* Try to print whole lines but obey the 512 bytes chunk size limit*/
120         if(NewString[curr_pos - 1] == '\n' || (curr_pos - start) == DBGPRINT_BUFSIZE)
121         {
122             if((curr_pos - start) >= DBGPRINT_BUFSIZE)
123             {
124                 /* No newlines so far, or the string just fits */
125                 if(last_newline <= start || ((curr_pos - start == DBGPRINT_BUFSIZE) && NewString[curr_pos - 1] == '\n'))
126                 {
127                     size = curr_pos - start;
128                     memcpy(DbgString, NewString.c_str() + start, size);
129                     start = curr_pos;
130                 }
131                 else
132                 {
133                     size = last_newline - start;
134                     memcpy(DbgString, NewString.c_str() + start, size);
135                     start = last_newline;
136                 }
137 
138                 DbgString[size] = 0;
139                 DbgPrint("%s", DbgString);
140             }
141 
142             last_newline = curr_pos;
143         }
144     }
145 
146     size = curr_pos - start;
147 
148     /* Only print if forced to or if the rest is a whole line */
149     if(forcePrint == true || NewString[curr_pos - 1] == '\n')
150     {
151         /* Output the whole string */
152         if(Configuration.DoPrint())
153             cout << NewString << flush;
154 
155         memcpy(DbgString, NewString.c_str() + start, size);
156         DbgString[size] = 0;
157         DbgPrint("%s", DbgString);
158 
159         NewString.clear();
160         return NewString;
161     }
162 
163     /* Output full lines only */
164     if(Configuration.DoPrint())
165         cout << NewString.substr(0, start) << flush;
166 
167     /* Return the remaining chunk */
168     return NewString.substr(start, size);
169 }
170 
171 /**
172  * Gets a value from a specified INI file and returns it converted to ASCII.
173  *
174  * @param AppName
175  * Constant pointer to a WCHAR array with the INI section to look in (lpAppName parameter passed to GetPrivateProfileStringW)
176  *
177  * @param KeyName
178  * Constant pointer to a WCHAR array containing the key to look for in the specified section (lpKeyName parameter passed to GetPrivateProfileStringW)
179  *
180  * @param FileName
181  * Constant pointer to a WCHAR array containing the path to the INI file
182  *
183  * @return
184  * Returns the data of the value as std::string or an empty string if no data could be retrieved.
185  */
186 string
187 GetINIValue(PCWCH AppName, PCWCH KeyName, PCWCH FileName)
188 {
189     DWORD Length;
190     PCHAR AsciiBuffer;
191     string ReturnedString;
192     WCHAR Buffer[2048];
193 
194     /* Load the value into a temporary Unicode buffer */
195     Length = GetPrivateProfileStringW(AppName, KeyName, NULL, Buffer, sizeof(Buffer) / sizeof(WCHAR), FileName);
196 
197     if(Length)
198     {
199         /* Convert the string to ASCII charset */
200         AsciiBuffer = new char[Length + 1];
201         WideCharToMultiByte(CP_ACP, 0, Buffer, Length + 1, AsciiBuffer, Length + 1, NULL, NULL);
202 
203         ReturnedString = AsciiBuffer;
204         delete[] AsciiBuffer;
205     }
206 
207     return ReturnedString;
208 }
209 
210 /**
211  * Converts an ASCII string to a Unicode one.
212  *
213  * @param AsciiString
214  * Constant pointer to a char array containing the ASCII string
215  *
216  * @return
217  * The Unicode string as std::wstring
218  */
219 wstring
220 AsciiToUnicode(const char* AsciiString)
221 {
222     DWORD Length;
223     PWSTR UnicodeString;
224     wstring ReturnString;
225 
226     Length = MultiByteToWideChar(CP_ACP, 0, AsciiString, -1, NULL, 0);
227 
228     UnicodeString = new WCHAR[Length];
229     MultiByteToWideChar(CP_ACP, 0, AsciiString, -1, UnicodeString, Length);
230     ReturnString = UnicodeString;
231     delete UnicodeString;
232 
233     return ReturnString;
234 }
235 
236 /**
237  * Converts an ASCII string to a Unicode one.
238  *
239  * @param AsciiString
240  * Pointer to a std::string containing the ASCII string
241  *
242  * @return
243  * The Unicode string as std::wstring
244  */
245 wstring
246 AsciiToUnicode(const string& AsciiString)
247 {
248     return AsciiToUnicode(AsciiString.c_str());
249 }
250 
251 /**
252  * Converts a Unicode string to an ASCII one.
253  *
254  * @param UnicodeString
255  * Constant pointer to a WCHAR array containing the Unicode string
256  *
257  * @return
258  * The ASCII string as std::string
259  */
260 string
261 UnicodeToAscii(PCWSTR UnicodeString)
262 {
263     DWORD Length;
264     PCHAR AsciiString;
265     string ReturnString;
266 
267     Length = WideCharToMultiByte(CP_ACP, 0, UnicodeString, -1, NULL, 0, NULL, NULL);
268 
269     AsciiString = new char[Length];
270     WideCharToMultiByte(CP_ACP, 0, UnicodeString, -1, AsciiString, Length, NULL, NULL);
271     ReturnString = AsciiString;
272     delete AsciiString;
273 
274     return ReturnString;
275 }
276 
277 /**
278  * Converts a Unicode string to an ASCII one.
279  *
280  * @param UnicodeString
281  * Pointer to a std::wstring containing the Unicode string
282  *
283  * @return
284  * The ASCII string as std::string
285  */
286 string
287 UnicodeToAscii(const wstring& UnicodeString)
288 {
289     return UnicodeToAscii(UnicodeString.c_str());
290 }
291