Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenformat_msg.c
Go to the documentation of this file.
00001 /* 00002 * FormatMessage implementation 00003 * 00004 * Copyright 1996 Marcus Meissner 00005 * Copyright 2009 Alexandre Julliard 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 #include <stdarg.h> 00023 #include <stdio.h> 00024 #include <string.h> 00025 00026 #include "ntstatus.h" 00027 #define WIN32_NO_STATUS 00028 #include "windef.h" 00029 #include "winbase.h" 00030 #include "winerror.h" 00031 #include "winternl.h" 00032 #include "winuser.h" 00033 #include "winnls.h" 00034 #include "wine/unicode.h" 00035 #include "wine/debug.h" 00036 00037 extern HMODULE kernel32_handle; 00038 00039 #define HeapAlloc RtlAllocateHeap 00040 #define HeapReAlloc RtlReAllocateHeap 00041 #define HeapFree RtlFreeHeap 00042 WINE_DEFAULT_DEBUG_CHANNEL(resource); 00043 00044 struct format_args 00045 { 00046 ULONG_PTR *args; 00047 __ms_va_list *list; 00048 int last; 00049 }; 00050 00051 /* Messages used by FormatMessage 00052 * 00053 * They can be specified either directly or using a message ID and 00054 * loading them from the resource. 00055 * 00056 * The resourcedata has following format: 00057 * start: 00058 * 0: DWORD nrofentries 00059 * nrofentries * subentry: 00060 * 0: DWORD firstentry 00061 * 4: DWORD lastentry 00062 * 8: DWORD offset from start to the stringentries 00063 * 00064 * (lastentry-firstentry) * stringentry: 00065 * 0: WORD len (0 marks end) [ includes the 4 byte header length ] 00066 * 2: WORD flags 00067 * 4: CHAR[len-4] 00068 * (stringentry i of a subentry refers to the ID 'firstentry+i') 00069 * 00070 * Yes, ANSI strings in win32 resources. Go figure. 00071 */ 00072 00073 static const WCHAR PCNTFMTWSTR[] = { '%','%','%','s',0 }; 00074 static const WCHAR FMTWSTR[] = { '%','s',0 }; 00075 00076 /********************************************************************** 00077 * load_message (internal) 00078 */ 00079 static LPWSTR load_message( HMODULE module, UINT id, WORD lang ) 00080 { 00081 const MESSAGE_RESOURCE_ENTRY *mre; 00082 WCHAR *buffer; 00083 NTSTATUS status; 00084 00085 TRACE("module = %p, id = %08x\n", module, id ); 00086 00087 if (!module) module = GetModuleHandleW( NULL ); 00088 if ((status = RtlFindMessage( module, (ULONG)RT_MESSAGETABLE, lang, id, &mre )) != STATUS_SUCCESS) 00089 { 00090 SetLastError( RtlNtStatusToDosError(status) ); 00091 return NULL; 00092 } 00093 00094 if (mre->Flags & MESSAGE_RESOURCE_UNICODE) 00095 { 00096 int len = (strlenW( (const WCHAR *)mre->Text ) + 1) * sizeof(WCHAR); 00097 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; 00098 memcpy( buffer, mre->Text, len ); 00099 } 00100 else 00101 { 00102 int len = MultiByteToWideChar( CP_ACP, 0, (const char *)mre->Text, -1, NULL, 0 ); 00103 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; 00104 MultiByteToWideChar( CP_ACP, 0, (const char*)mre->Text, -1, buffer, len ); 00105 } 00106 TRACE("returning %s\n", wine_dbgstr_w(buffer)); 00107 return buffer; 00108 } 00109 00110 /********************************************************************** 00111 * get_arg (internal) 00112 */ 00113 static ULONG_PTR get_arg( int nr, DWORD flags, struct format_args *args ) 00114 { 00115 if (nr == -1) nr = args->last + 1; 00116 if (args->list) 00117 { 00118 if (!args->args) args->args = HeapAlloc( GetProcessHeap(), 0, 99 * sizeof(ULONG_PTR) ); 00119 while (nr > args->last) 00120 args->args[args->last++] = va_arg( *args->list, ULONG_PTR ); 00121 } 00122 if (nr > args->last) args->last = nr; 00123 return args->args[nr - 1]; 00124 } 00125 00126 /********************************************************************** 00127 * format_insert (internal) 00128 */ 00129 static LPCWSTR format_insert( BOOL unicode_caller, int insert, LPCWSTR format, 00130 DWORD flags, struct format_args *args, 00131 LPWSTR *result ) 00132 { 00133 static const WCHAR fmt_lu[] = {'%','l','u',0}; 00134 WCHAR *wstring = NULL, *p, fmt[256]; 00135 ULONG_PTR arg; 00136 int size; 00137 00138 if (*format != '!') /* simple string */ 00139 { 00140 arg = get_arg( insert, flags, args ); 00141 if (unicode_caller) 00142 { 00143 WCHAR *str = (WCHAR *)arg; 00144 *result = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) ); 00145 strcpyW( *result, str ); 00146 } 00147 else 00148 { 00149 char *str = (char *)arg; 00150 DWORD length = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); 00151 *result = HeapAlloc( GetProcessHeap(), 0, length * sizeof(WCHAR) ); 00152 MultiByteToWideChar( CP_ACP, 0, str, -1, *result, length ); 00153 } 00154 return format; 00155 } 00156 00157 format++; 00158 p = fmt; 00159 *p++ = '%'; 00160 00161 while (*format == '0' || 00162 *format == '+' || 00163 *format == '-' || 00164 *format == ' ' || 00165 *format == '*' || 00166 *format == '#') 00167 { 00168 if (*format == '*') 00169 { 00170 p += sprintfW( p, fmt_lu, get_arg( insert, flags, args )); 00171 insert = -1; 00172 format++; 00173 } 00174 else *p++ = *format++; 00175 } 00176 while (isdigitW(*format)) *p++ = *format++; 00177 00178 if (*format == '.') 00179 { 00180 *p++ = *format++; 00181 if (*format == '*') 00182 { 00183 p += sprintfW( p, fmt_lu, get_arg( insert, flags, args )); 00184 insert = -1; 00185 format++; 00186 } 00187 else 00188 while (isdigitW(*format)) *p++ = *format++; 00189 } 00190 00191 /* replicate MS bug: drop an argument when using va_list with width/precision */ 00192 if (insert == -1 && args->list) args->last--; 00193 arg = get_arg( insert, flags, args ); 00194 00195 /* check for ascii string format */ 00196 if ((format[0] == 'h' && format[1] == 's') || 00197 (format[0] == 'h' && format[1] == 'S') || 00198 (unicode_caller && format[0] == 'S') || 00199 (!unicode_caller && format[0] == 's')) 00200 { 00201 DWORD len = MultiByteToWideChar( CP_ACP, 0, (char *)arg, -1, NULL, 0 ); 00202 wstring = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 00203 MultiByteToWideChar( CP_ACP, 0, (char *)arg, -1, wstring, len ); 00204 arg = (ULONG_PTR)wstring; 00205 *p++ = 's'; 00206 } 00207 /* check for ascii character format */ 00208 else if ((format[0] == 'h' && format[1] == 'c') || 00209 (format[0] == 'h' && format[1] == 'C') || 00210 (unicode_caller && format[0] == 'C') || 00211 (!unicode_caller && format[0] == 'c')) 00212 { 00213 char ch = arg; 00214 wstring = HeapAlloc( GetProcessHeap(), 0, 2 * sizeof(WCHAR) ); 00215 MultiByteToWideChar( CP_ACP, 0, &ch, 1, wstring, 1 ); 00216 wstring[1] = 0; 00217 arg = (ULONG_PTR)wstring; 00218 *p++ = 's'; 00219 } 00220 /* check for wide string format */ 00221 else if ((format[0] == 'l' && format[1] == 's') || 00222 (format[0] == 'l' && format[1] == 'S') || 00223 (format[0] == 'w' && format[1] == 's') || 00224 (!unicode_caller && format[0] == 'S')) 00225 { 00226 *p++ = 's'; 00227 } 00228 /* check for wide character format */ 00229 else if ((format[0] == 'l' && format[1] == 'c') || 00230 (format[0] == 'l' && format[1] == 'C') || 00231 (format[0] == 'w' && format[1] == 'c') || 00232 (!unicode_caller && format[0] == 'C')) 00233 { 00234 *p++ = 'c'; 00235 } 00236 /* FIXME: handle I64 etc. */ 00237 else while (*format && *format != '!') *p++ = *format++; 00238 00239 *p = 0; 00240 size = 256; 00241 for (;;) 00242 { 00243 WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); 00244 int needed = snprintfW( ret, size, fmt, arg ); 00245 if (needed == -1 || needed >= size) 00246 { 00247 HeapFree( GetProcessHeap(), 0, ret ); 00248 size = max( needed + 1, size * 2 ); 00249 } 00250 else 00251 { 00252 *result = ret; 00253 break; 00254 } 00255 } 00256 00257 while (*format && *format != '!') format++; 00258 if (*format == '!') format++; 00259 00260 HeapFree( GetProcessHeap(), 0, wstring ); 00261 return format; 00262 } 00263 00264 /********************************************************************** 00265 * format_message (internal) 00266 */ 00267 static LPWSTR format_message( BOOL unicode_caller, DWORD dwFlags, LPCWSTR fmtstr, 00268 struct format_args *format_args ) 00269 { 00270 LPWSTR target,t; 00271 DWORD talloced; 00272 LPCWSTR f; 00273 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; 00274 BOOL eos = FALSE; 00275 WCHAR ch; 00276 00277 target = t = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 * sizeof(WCHAR) ); 00278 talloced = 100; 00279 00280 #define ADD_TO_T(c) do {\ 00281 *t++=c;\ 00282 if ((DWORD)(t-target) == talloced) {\ 00283 target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2*sizeof(WCHAR));\ 00284 t = target+talloced;\ 00285 talloced*=2;\ 00286 } \ 00287 } while (0) 00288 00289 f = fmtstr; 00290 while (*f && !eos) { 00291 if (*f=='%') { 00292 int insertnr; 00293 WCHAR *str,*x; 00294 00295 f++; 00296 switch (*f) { 00297 case '1':case '2':case '3':case '4':case '5': 00298 case '6':case '7':case '8':case '9': 00299 if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) 00300 goto ignore_inserts; 00301 else if (((dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) && !format_args->args) || 00302 (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) && !format_args->list)) 00303 { 00304 SetLastError(ERROR_INVALID_PARAMETER); 00305 HeapFree(GetProcessHeap(), 0, target); 00306 return NULL; 00307 } 00308 insertnr = *f-'0'; 00309 switch (f[1]) { 00310 case '0':case '1':case '2':case '3': 00311 case '4':case '5':case '6':case '7': 00312 case '8':case '9': 00313 f++; 00314 insertnr = insertnr*10 + *f-'0'; 00315 f++; 00316 break; 00317 default: 00318 f++; 00319 break; 00320 } 00321 f = format_insert( unicode_caller, insertnr, f, dwFlags, format_args, &str ); 00322 for (x = str; *x; x++) ADD_TO_T(*x); 00323 HeapFree( GetProcessHeap(), 0, str ); 00324 break; 00325 case 'n': 00326 ADD_TO_T('\r'); 00327 ADD_TO_T('\n'); 00328 f++; 00329 break; 00330 case 'r': 00331 ADD_TO_T('\r'); 00332 f++; 00333 break; 00334 case 't': 00335 ADD_TO_T('\t'); 00336 f++; 00337 break; 00338 case '0': 00339 eos = TRUE; 00340 f++; 00341 break; 00342 case '\0': 00343 SetLastError(ERROR_INVALID_PARAMETER); 00344 HeapFree(GetProcessHeap(), 0, target); 00345 return NULL; 00346 ignore_inserts: 00347 default: 00348 if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) 00349 ADD_TO_T('%'); 00350 ADD_TO_T(*f++); 00351 break; 00352 } 00353 } else { 00354 ch = *f; 00355 f++; 00356 if (ch == '\r') { 00357 if (*f == '\n') 00358 f++; 00359 if(width) 00360 ADD_TO_T(' '); 00361 else 00362 { 00363 ADD_TO_T('\r'); 00364 ADD_TO_T('\n'); 00365 } 00366 } else { 00367 if (ch == '\n') 00368 { 00369 if(width) 00370 ADD_TO_T(' '); 00371 else 00372 { 00373 ADD_TO_T('\r'); 00374 ADD_TO_T('\n'); 00375 } 00376 } 00377 else 00378 ADD_TO_T(ch); 00379 } 00380 } 00381 } 00382 *t = '\0'; 00383 00384 return target; 00385 } 00386 #undef ADD_TO_T 00387 00388 /*********************************************************************** 00389 * FormatMessageA (KERNEL32.@) 00390 * FIXME: missing wrap, 00391 */ 00392 DWORD WINAPI FormatMessageA( 00393 DWORD dwFlags, 00394 LPCVOID lpSource, 00395 DWORD dwMessageId, 00396 DWORD dwLanguageId, 00397 LPSTR lpBuffer, 00398 DWORD nSize, 00399 __ms_va_list* args ) 00400 { 00401 struct format_args format_args; 00402 DWORD ret = 0; 00403 LPWSTR target; 00404 DWORD destlength; 00405 LPWSTR from; 00406 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; 00407 00408 TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n", 00409 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); 00410 00411 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) 00412 { 00413 if (!lpBuffer) 00414 { 00415 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 00416 return 0; 00417 } 00418 else 00419 *(LPSTR *)lpBuffer = NULL; 00420 } 00421 00422 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) 00423 { 00424 format_args.args = (ULONG_PTR *)args; 00425 format_args.list = NULL; 00426 format_args.last = 0; 00427 } 00428 else 00429 { 00430 format_args.args = NULL; 00431 format_args.list = args; 00432 format_args.last = 0; 00433 } 00434 00435 if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) 00436 FIXME("line wrapping (%u) not supported.\n", width); 00437 from = NULL; 00438 if (dwFlags & FORMAT_MESSAGE_FROM_STRING) 00439 { 00440 DWORD length = MultiByteToWideChar(CP_ACP, 0, lpSource, -1, NULL, 0); 00441 from = HeapAlloc( GetProcessHeap(), 0, length * sizeof(WCHAR) ); 00442 MultiByteToWideChar(CP_ACP, 0, lpSource, -1, from, length); 00443 } 00444 else if (dwFlags & (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM)) 00445 { 00446 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) 00447 from = load_message( (HMODULE)lpSource, dwMessageId, dwLanguageId ); 00448 if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)) 00449 from = load_message( kernel32_handle, dwMessageId, dwLanguageId ); 00450 if (!from) return 0; 00451 } 00452 else 00453 { 00454 SetLastError(ERROR_INVALID_PARAMETER); 00455 return 0; 00456 } 00457 00458 target = format_message( FALSE, dwFlags, from, &format_args ); 00459 if (!target) 00460 goto failure; 00461 00462 TRACE("-- %s\n", debugstr_w(target)); 00463 00464 /* Only try writing to an output buffer if there are processed characters 00465 * in the temporary output buffer. */ 00466 if (*target) 00467 { 00468 destlength = WideCharToMultiByte(CP_ACP, 0, target, -1, NULL, 0, NULL, NULL); 00469 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) 00470 { 00471 LPSTR buf = LocalAlloc(LMEM_ZEROINIT, max(nSize, destlength)); 00472 WideCharToMultiByte(CP_ACP, 0, target, -1, buf, destlength, NULL, NULL); 00473 *((LPSTR*)lpBuffer) = buf; 00474 } 00475 else 00476 { 00477 if (nSize < destlength) 00478 { 00479 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00480 goto failure; 00481 } 00482 WideCharToMultiByte(CP_ACP, 0, target, -1, lpBuffer, destlength, NULL, NULL); 00483 } 00484 ret = destlength - 1; /* null terminator */ 00485 } 00486 00487 failure: 00488 HeapFree(GetProcessHeap(),0,target); 00489 HeapFree(GetProcessHeap(),0,from); 00490 if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); 00491 TRACE("-- returning %u\n", ret); 00492 return ret; 00493 } 00494 00495 /*********************************************************************** 00496 * FormatMessageW (KERNEL32.@) 00497 */ 00498 DWORD WINAPI FormatMessageW( 00499 DWORD dwFlags, 00500 LPCVOID lpSource, 00501 DWORD dwMessageId, 00502 DWORD dwLanguageId, 00503 LPWSTR lpBuffer, 00504 DWORD nSize, 00505 __ms_va_list* args ) 00506 { 00507 struct format_args format_args; 00508 DWORD ret = 0; 00509 LPWSTR target; 00510 DWORD talloced; 00511 LPWSTR from; 00512 DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; 00513 00514 TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n", 00515 dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); 00516 00517 if (!lpBuffer) 00518 { 00519 SetLastError(ERROR_INVALID_PARAMETER); 00520 return 0; 00521 } 00522 00523 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) 00524 *(LPWSTR *)lpBuffer = NULL; 00525 00526 if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) 00527 { 00528 format_args.args = (ULONG_PTR *)args; 00529 format_args.list = NULL; 00530 format_args.last = 0; 00531 } 00532 else 00533 { 00534 format_args.args = NULL; 00535 format_args.list = args; 00536 format_args.last = 0; 00537 } 00538 00539 if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) 00540 FIXME("line wrapping not supported.\n"); 00541 from = NULL; 00542 if (dwFlags & FORMAT_MESSAGE_FROM_STRING) { 00543 from = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpSource) + 1) * 00544 sizeof(WCHAR) ); 00545 strcpyW( from, lpSource ); 00546 } 00547 else if (dwFlags & (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM)) 00548 { 00549 if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) 00550 from = load_message( (HMODULE)lpSource, dwMessageId, dwLanguageId ); 00551 if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)) 00552 from = load_message( kernel32_handle, dwMessageId, dwLanguageId ); 00553 if (!from) return 0; 00554 } 00555 else 00556 { 00557 SetLastError(ERROR_INVALID_PARAMETER); 00558 return 0; 00559 } 00560 00561 target = format_message( TRUE, dwFlags, from, &format_args ); 00562 if (!target) 00563 goto failure; 00564 00565 talloced = strlenW(target)+1; 00566 TRACE("-- %s\n",debugstr_w(target)); 00567 00568 /* Only allocate a buffer if there are processed characters in the 00569 * temporary output buffer. If a caller supplies the buffer, then 00570 * a null terminator will be written to it. */ 00571 if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) 00572 { 00573 if (*target) 00574 { 00575 /* nSize is the MINIMUM size */ 00576 *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT, max(nSize, talloced)*sizeof(WCHAR)); 00577 strcpyW(*(LPWSTR*)lpBuffer, target); 00578 } 00579 } 00580 else 00581 { 00582 if (nSize < talloced) 00583 { 00584 SetLastError(ERROR_INSUFFICIENT_BUFFER); 00585 goto failure; 00586 } 00587 strcpyW(lpBuffer, target); 00588 } 00589 00590 ret = talloced - 1; /* null terminator */ 00591 failure: 00592 HeapFree(GetProcessHeap(),0,target); 00593 HeapFree(GetProcessHeap(),0,from); 00594 if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); 00595 TRACE("-- returning %u\n", ret); 00596 return ret; 00597 } Generated on Fri May 25 2012 04:22:34 for ReactOS by
1.7.6.1
|