Author: gschneider Date: Thu Dec 3 19:57:57 2009 New Revision: 44386
URL: http://svn.reactos.org/svn/reactos?rev=44386&view=rev Log: [kernel32] - Update FormatMessageA/W to current Wine sources, rename the file to better reflect the content - Fixes the failing kernel32 format_msg tests
Added: trunk/reactos/dll/win32/kernel32/misc/format_msg.c (with props) Removed: trunk/reactos/dll/win32/kernel32/misc/errormsg.c Modified: trunk/reactos/dll/win32/kernel32/kernel32.rbuild
Modified: trunk/reactos/dll/win32/kernel32/kernel32.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/kernel32... ============================================================================== --- trunk/reactos/dll/win32/kernel32/kernel32.rbuild [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/kernel32.rbuild [iso-8859-1] Thu Dec 3 19:57:57 2009 @@ -77,8 +77,8 @@ <file>dllmain.c</file> <file>env.c</file> <file>error.c</file> - <file>errormsg.c</file> <file>fold.c</file> + <file>format_msg.c</file> <file>handle.c</file> <file>lang.c</file> <file>ldr.c</file>
Removed: trunk/reactos/dll/win32/kernel32/misc/errormsg.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/misc/err... ============================================================================== --- trunk/reactos/dll/win32/kernel32/misc/errormsg.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/misc/errormsg.c (removed) @@ -1,668 +1,0 @@ -/* $Id$ - * - * reactos/lib/kernel32/misc/errormsg.c - * Wine calls this file now as kernel/format_msg.c - * - */ -/* - * FormatMessage implementation - * - * Copyright 1996 Marcus Meissner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <k32.h> - -#define NDEBUG - -#include <debug.h> -#include "wine/unicode.h" - -#define TRACE DPRINT -#define FIXME DPRINT - -static const WCHAR PCNTFMTWSTR[] = { '%','%','%','s',0 }; -static const WCHAR FMTWSTR[] = { '%','s',0 }; -static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0}; - -/* strdup macros */ -/* DO NOT USE IT!! it will go away soon */ - -__inline static LPSTR HEAP_strdupWtoA( HANDLE heap, DWORD flags, LPCWSTR str ) -{ - LPSTR ret; - INT len; - - if (!str) return NULL; - len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); - ret = RtlAllocateHeap(RtlGetProcessHeap(), flags, len ); - if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); - return ret; -} - -/* Messages...used by FormatMessage32* (KERNEL32.something) - * - * They can be specified either directly or using a message ID and - * loading them from the resource. - * - * The resourcedata has following format: - * start: - * 0: DWORD nrofentries - * nrofentries * subentry: - * 0: DWORD firstentry - * 4: DWORD lastentry - * 8: DWORD offset from start to the stringentries - * - * (lastentry-firstentry) * stringentry: - * 0: WORD len (0 marks end) [ includes the 4 byte header length ] - * 2: WORD flags - * 4: CHAR[len-4] - * (stringentry i of a subentry refers to the ID 'firstentry+i') - * - * Yes, ANSI strings in win32 resources. Go figure. - */ - -/********************************************************************** - * load_messageW (internal) - */ -static LPWSTR load_messageW( HMODULE module, UINT id, WORD lang ) -{ - PRTL_MESSAGE_RESOURCE_ENTRY mre; - WCHAR *buffer; - NTSTATUS Status; - - TRACE("module = %p, id = %08x\n", module, id ); - - if (!module) module = GetModuleHandleW( NULL ); - Status = RtlFindMessage( module, (ULONG) RT_MESSAGETABLE, lang, id, &mre ); - if (!NT_SUCCESS(Status)) - { - SetLastError( RtlNtStatusToDosError(Status) ); - return NULL; - } - - if (mre->Flags & MESSAGE_RESOURCE_UNICODE) - { - int len = (strlenW( (const WCHAR *)mre->Text ) + 1) * sizeof(WCHAR); - if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; - memcpy( buffer, mre->Text, len ); - } - else - { - int len = MultiByteToWideChar( CP_ACP, 0, (const char *)mre->Text, -1, NULL, 0 ); - if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; - MultiByteToWideChar( CP_ACP, 0, (const char*)mre->Text, -1, buffer, len ); - } - //TRACE("returning %s\n", wine_dbgstr_w(buffer)); - return buffer; -} - - -/********************************************************************** - * load_messageA (internal) - */ - -static LPSTR load_messageA( HMODULE module, UINT id, WORD lang ) -{ - PRTL_MESSAGE_RESOURCE_ENTRY mre; - char *buffer; - NTSTATUS Status; - - TRACE("module = %p, id = %08x\n", module, id ); - - if (!module) module = GetModuleHandleW( NULL ); - Status = RtlFindMessage( module, (ULONG) RT_MESSAGETABLE, lang, id, &mre ); - if (!NT_SUCCESS(Status)) - { - SetLastError( RtlNtStatusToDosError(Status) ); - return NULL; - } - - if (mre->Flags & MESSAGE_RESOURCE_UNICODE) - { - int len = WideCharToMultiByte( CP_ACP, 0, (const WCHAR *)mre->Text, -1, NULL, 0, NULL, NULL ); - if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; - WideCharToMultiByte( CP_ACP, 0, (const WCHAR *)mre->Text, -1, buffer, len, NULL, NULL ); - } - else - { - int len = strlen((const char*)mre->Text) + 1; - if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; - memcpy( buffer, mre->Text, len ); - } - //TRACE("returning %s\n", wine_dbgstr_a(buffer)); - return buffer; -} - - -/*********************************************************************** - * FormatMessageA (KERNEL32.@) - * FIXME: missing wrap, - * - * @implemented - */ -DWORD WINAPI FormatMessageA( - DWORD dwFlags, - LPCVOID lpSource, - DWORD dwMessageId, - DWORD dwLanguageId, - LPSTR lpBuffer, - DWORD nSize, - va_list* _args ) -{ - LPDWORD args=(LPDWORD)_args; - HMODULE kernel32_handle = GetModuleHandleW(kernel32W); - -#if defined(__i386__) || defined(__sparc__) -/* This implementation is completely dependent on the format of the va_list on x86 CPUs */ - LPSTR target,t; - DWORD talloced; - LPSTR from,f; - DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; - BOOL eos = FALSE; - CHAR ch; - - TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", - dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); - if ((dwFlags & FORMAT_MESSAGE_FROM_STRING) - &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) - || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0; - - if (!lpBuffer) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) - FIXME("line wrapping (%lu) not supported.\n", width); - from = NULL; - if (dwFlags & FORMAT_MESSAGE_FROM_STRING) - { - from = HeapAlloc( GetProcessHeap(), 0, strlen((LPCSTR)lpSource)+1 ); - if (from == NULL) - { - return 0; - } - strcpy( from, (LPCSTR)lpSource ); - } - else { - from = NULL; - if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) - from = load_messageA( (HMODULE)lpSource, dwMessageId, (WORD)dwLanguageId ); - if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)) - from = load_messageA( kernel32_handle, dwMessageId, (WORD)dwLanguageId ); - - if (!from) - { - return 0; - } - } - target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100); - if(target == NULL) - { - HeapFree(GetProcessHeap(),0,from); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - t = target; - talloced= 100; - -#define ADD_TO_T(c) do { \ - *t++=c;\ - if (t-target == talloced) {\ - target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\ - t = target+talloced;\ - talloced*=2;\ - }\ -} while (0) - - if (from) { - f=from; - if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) { - while (*f && !eos) - ADD_TO_T(*f++); - } - else { - while (*f && !eos) { - if (*f=='%') { - int insertnr; - char *fmtstr,*x,*lastf; - DWORD *argliststart; - - fmtstr = NULL; - lastf = f; - f++; - if (!*f) { - ADD_TO_T('%'); - continue; - } - switch (*f) { - case '1':case '2':case '3':case '4':case '5': - case '6':case '7':case '8':case '9': - insertnr=*f-'0'; - switch (f[1]) { - case '0':case '1':case '2':case '3': - case '4':case '5':case '6':case '7': - case '8':case '9': - f++; - insertnr=insertnr*10+*f-'0'; - f++; - break; - default: - f++; - break; - } - if (*f=='!') { - f++; - if (NULL!=(x=strchr(f,'!'))) { - *x='\0'; - fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2); - if(fmtstr == NULL) - { - HeapFree(GetProcessHeap(),0,from); - HeapFree(GetProcessHeap(),0,target); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - sprintf(fmtstr,"%%%s",f); - f=x+1; - } else { - fmtstr=HeapAlloc(GetProcessHeap(),0,strlen(f)+2); - if(fmtstr == NULL) - { - HeapFree(GetProcessHeap(),0,from); - HeapFree(GetProcessHeap(),0,target); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - sprintf(fmtstr,"%%%s",f); - f+=strlen(f); /*at \0*/ - } - } else { - if(!args) break; - fmtstr = HeapAlloc(GetProcessHeap(),0,3); - if(fmtstr == NULL) - { - HeapFree(GetProcessHeap(),0,from); - HeapFree(GetProcessHeap(),0,target); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - strcpy( fmtstr, "%s" ); - } - if (args) { - int sz; - LPSTR b; - - if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) - argliststart=args+insertnr-1; - else - argliststart=(*(DWORD**)args)+insertnr-1; - - b = NULL; - sz = 0; - do { - if (b) { - HeapFree(GetProcessHeap(), 0, b); - } - sz += 256; - b = HeapAlloc(GetProcessHeap(), 0, sz); - /* CMF - This makes a BIG assumption about va_list */ - } while (0 > _vsnprintf(b, sz, fmtstr, (va_list) argliststart)); - x=b; - while(*x) - ADD_TO_T(*x++); - - HeapFree(GetProcessHeap(),0,b); - } else { - /* NULL args - copy formatstr - * (probably wrong) - */ - while ((lastf<f)&&(*lastf)) { - ADD_TO_T(*lastf++); - } - } - HeapFree(GetProcessHeap(),0,fmtstr); - break; - case 'n': - ADD_TO_T('\r'); - ADD_TO_T('\n'); - f++; - break; - case '0': - eos = TRUE; - f++; - break; - default: - ADD_TO_T(*f++); - break; - } - } else { - ch = *f; - f++; - if (ch == '\r') { - if (*f == '\n') - f++; - if(width) - ADD_TO_T(' '); - else - { - ADD_TO_T('\r'); - ADD_TO_T('\n'); - } - } else { - if (ch == '\n') - { - if(width) - ADD_TO_T(' '); - else - { - ADD_TO_T('\r'); - ADD_TO_T('\n'); - } - } - else - ADD_TO_T(ch); - } - } - } - } - *t='\0'; - } - talloced = strlen(target)+1; - if (nSize && talloced<nSize) { - target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize); - } - //TRACE("-- %s\n",debugstr_a(target)); - if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { - *((LPVOID*)lpBuffer) = (LPVOID)LocalAlloc(LMEM_ZEROINIT,max(nSize, talloced)); - memcpy(*(LPSTR*)lpBuffer,target,talloced); - } else { - lstrcpynA(lpBuffer,target,nSize); - } - HeapFree(GetProcessHeap(),0,target); - HeapFree(GetProcessHeap(),0,from); - TRACE("-- returning %d\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer):strlen(lpBuffer)); - return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? - strlen(*(LPSTR*)lpBuffer): - strlen(lpBuffer); -#else - return 0; -#endif /* __i386__ */ -} -#undef ADD_TO_T - -/*********************************************************************** - * FormatMessageW (KERNEL32.@) - * - * @implemented - */ -DWORD WINAPI FormatMessageW( - DWORD dwFlags, - LPCVOID lpSource, - DWORD dwMessageId, - DWORD dwLanguageId, - LPWSTR lpBuffer, - DWORD nSize, - va_list* _args ) -{ - HMODULE kernel32_handle = GetModuleHandleW(kernel32W); - LPDWORD args=(LPDWORD)_args; -#if defined(__i386__) || defined(__sparc__) -/* This implementation is completely dependent on the format of the va_list on x86 CPUs */ - LPWSTR target,t; - DWORD talloced,len; - LPWSTR from,f; - DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; - BOOL eos = FALSE; - WCHAR ch; - - TRACE("(0x%lx,%p,%ld,0x%lx,%p,%ld,%p)\n", - dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); - if ((dwFlags & FORMAT_MESSAGE_FROM_STRING) - &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) - || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0; - - if (!lpBuffer) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) - FIXME("line wrapping not supported.\n"); - from = NULL; - if (dwFlags & FORMAT_MESSAGE_FROM_STRING) { - from = HeapAlloc( GetProcessHeap(), 0, (strlenW((LPCWSTR)lpSource) + 1) * - sizeof(WCHAR) ); - if(from == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - strcpyW( from, (LPCWSTR)lpSource ); - } - else { - from = NULL; - if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) - from = load_messageW( (HMODULE)lpSource, dwMessageId, (WORD)dwLanguageId ); - if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)) - from = load_messageW( kernel32_handle, dwMessageId,(WORD)dwLanguageId ); - - if (!from) - { - return 0; - } - } - - target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 * sizeof(WCHAR) ); - if(target == NULL) - { - HeapFree(GetProcessHeap(),0,from); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - t = target; - talloced= 100; - -#define ADD_TO_T(c) do {\ - *t++=c;\ - if (t-target == talloced) {\ - target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2*sizeof(WCHAR));\ - t = target+talloced;\ - talloced*=2;\ - } \ -} while (0) - - if (from) { - f=from; - if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) { - while (*f && !eos) - ADD_TO_T(*f++); - } - else { - while (*f && !eos) { - if (*f=='%') { - int insertnr; - WCHAR *fmtstr,*sprintfbuf,*x,*lastf; - DWORD *argliststart; - - fmtstr = NULL; - lastf = f; - f++; - if (!*f) { - ADD_TO_T('%'); - continue; - } - - switch (*f) { - case '1':case '2':case '3':case '4':case '5': - case '6':case '7':case '8':case '9': - insertnr=*f-'0'; - switch (f[1]) { - case '0':case '1':case '2':case '3': - case '4':case '5':case '6':case '7': - case '8':case '9': - f++; - insertnr=insertnr*10+*f-'0'; - f++; - break; - default: - f++; - break; - } - if (*f=='!') { - f++; - if (NULL!=(x=strchrW(f,'!'))) { - *x='\0'; - fmtstr=HeapAlloc( GetProcessHeap(), 0,(strlenW(f)+2)*sizeof(WCHAR)); - if(fmtstr == NULL) - { - HeapFree(GetProcessHeap(),0,from); - HeapFree(GetProcessHeap(),0,target); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - sprintfW(fmtstr,PCNTFMTWSTR,f); - f=x+1; - } else { - fmtstr=HeapAlloc(GetProcessHeap(),0,(strlenW(f)+2)*sizeof(WCHAR)); - if(fmtstr == NULL) - { - HeapFree(GetProcessHeap(),0,from); - HeapFree(GetProcessHeap(),0,target); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - sprintfW(fmtstr,PCNTFMTWSTR,f); - f+=strlenW(f); /*at \0*/ - } - } else { - if(!args) break; - fmtstr = HeapAlloc( GetProcessHeap(),0,3*sizeof(WCHAR)); - if(fmtstr == NULL) - { - HeapFree(GetProcessHeap(),0,from); - HeapFree(GetProcessHeap(),0,target); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - strcpyW( fmtstr, FMTWSTR ); - } - - if (args) { - if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) - argliststart=args+insertnr-1; - else - argliststart=(*(DWORD**)args)+insertnr-1; - - len = 0; - sprintfbuf = NULL; - do { - if (sprintfbuf) { - HeapFree(GetProcessHeap(),0,sprintfbuf); - } - len += 256; - sprintfbuf=HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); - /* CMF - This makes a BIG assumption about va_list */ - } while (0 > _vsnwprintf(sprintfbuf, len, fmtstr, (va_list) argliststart)); - x=sprintfbuf; - while (*x) { - ADD_TO_T(*x++); - } - HeapFree(GetProcessHeap(),0,sprintfbuf); - - } else { - /* NULL args - copy formatstr - * (probably wrong) - */ - while ((lastf<f)&&(*lastf)) { - ADD_TO_T(*lastf++); - } - } - - HeapFree(GetProcessHeap(),0,fmtstr); - break; - case 'n': - ADD_TO_T('\r'); - ADD_TO_T('\n'); - f++; - break; - case '0': - eos = TRUE; - f++; - break; - default: - ADD_TO_T(*f++); - break; - } - } else { - ch = *f; - f++; - if (ch == '\r') { - if (*f == '\n') - f++; - if(width) - ADD_TO_T(' '); - else - { - ADD_TO_T('\r'); - ADD_TO_T('\n'); - } - } else { - if (ch == '\n') - { - if(width) - ADD_TO_T(' '); - else - { - ADD_TO_T('\r'); - ADD_TO_T('\n'); - } - } - else - ADD_TO_T(ch); - } - } - } - } - *t='\0'; - } - talloced = strlenW(target)+1; - if (nSize && talloced<nSize) - target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize*sizeof(WCHAR)); - if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { - /* nSize is the MINIMUM size */ - DWORD len = strlenW(target) + 1; - *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,len*sizeof(WCHAR)); - strcpyW(*(LPWSTR*)lpBuffer, target); - } - else lstrcpynW(lpBuffer, target, nSize); - - HeapFree(GetProcessHeap(),0,target); - HeapFree(GetProcessHeap(),0,from); - //TRACE("ret=%s\n", wine_dbgstr_w((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? - // *(LPWSTR*)lpBuffer : lpBuffer)); - return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? - strlenW(*(LPWSTR*)lpBuffer): - strlenW(lpBuffer); -#else - return 0; -#endif /* __i386__ */ -} -#undef ADD_TO_T -
Added: trunk/reactos/dll/win32/kernel32/misc/format_msg.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/misc/for... ============================================================================== --- trunk/reactos/dll/win32/kernel32/misc/format_msg.c (added) +++ trunk/reactos/dll/win32/kernel32/misc/format_msg.c [iso-8859-1] Thu Dec 3 19:57:57 2009 @@ -1,0 +1,757 @@ +/* + * FormatMessage implementation + * + * Copyright 1996 Marcus Meissner + * Copyright 2009 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <k32.h> + +#define NDEBUG + +#include <debug.h> +#include "wine/unicode.h" + +struct format_args +{ + ULONG_PTR *args; + __ms_va_list *list; + int last; +}; + +static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0}; + +/* Messages used by FormatMessage + * + * They can be specified either directly or using a message ID and + * loading them from the resource. + * + * The resourcedata has following format: + * start: + * 0: DWORD nrofentries + * nrofentries * subentry: + * 0: DWORD firstentry + * 4: DWORD lastentry + * 8: DWORD offset from start to the stringentries + * + * (lastentry-firstentry) * stringentry: + * 0: WORD len (0 marks end) [ includes the 4 byte header length ] + * 2: WORD flags + * 4: CHAR[len-4] + * (stringentry i of a subentry refers to the ID 'firstentry+i') + * + * Yes, ANSI strings in win32 resources. Go figure. + */ + +static const WCHAR PCNTFMTWSTR[] = { '%','%','%','s',0 }; +static const WCHAR FMTWSTR[] = { '%','s',0 }; + +/********************************************************************** + * load_messageW (internal) + */ +static LPWSTR load_messageW( HMODULE module, UINT id, WORD lang ) +{ + PRTL_MESSAGE_RESOURCE_ENTRY mre; + WCHAR *buffer; + NTSTATUS status; + + DPRINT("module = %p, id = %08x\n", module, id ); + + if (!module) module = GetModuleHandleW( NULL ); + if ((status = RtlFindMessage( module, (ULONG)RT_MESSAGETABLE, lang, id, &mre )) != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + return NULL; + } + + if (mre->Flags & MESSAGE_RESOURCE_UNICODE) + { + int len = (strlenW( (const WCHAR *)mre->Text ) + 1) * sizeof(WCHAR); + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; + memcpy( buffer, mre->Text, len ); + } + else + { + int len = MultiByteToWideChar( CP_ACP, 0, (const char *)mre->Text, -1, NULL, 0 ); + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL; + MultiByteToWideChar( CP_ACP, 0, (const char*)mre->Text, -1, buffer, len ); + } + DPRINT("returning %S\n", buffer); + return buffer; +} + + +/********************************************************************** + * load_messageA (internal) + */ +static LPSTR load_messageA( HMODULE module, UINT id, WORD lang ) +{ + PRTL_MESSAGE_RESOURCE_ENTRY mre; + char *buffer; + NTSTATUS status; + + DPRINT("module = %p, id = %08x\n", module, id ); + + if (!module) module = GetModuleHandleW( NULL ); + if ((status = RtlFindMessage( module, (ULONG)RT_MESSAGETABLE, lang, id, &mre )) != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + return NULL; + } + + if (mre->Flags & MESSAGE_RESOURCE_UNICODE) + { + int len = WideCharToMultiByte( CP_ACP, 0, (const WCHAR *)mre->Text, -1, NULL, 0, NULL, NULL ); + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; + WideCharToMultiByte( CP_ACP, 0, (const WCHAR *)mre->Text, -1, buffer, len, NULL, NULL ); + } + else + { + int len = strlen((const char*)mre->Text) + 1; + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; + memcpy( buffer, mre->Text, len ); + } + DPRINT("returning %s\n", buffer); + return buffer; +} + + +/********************************************************************** + * get_arg (internal) + */ +static ULONG_PTR get_arg( int nr, DWORD flags, struct format_args *args ) +{ + if (nr == -1) nr = args->last + 1; + if (args->list) + { + if (!args->args) args->args = HeapAlloc( GetProcessHeap(), 0, 99 * sizeof(ULONG_PTR) ); + while (nr > args->last) + args->args[args->last++] = va_arg( *args->list, ULONG_PTR ); + } + if (nr > args->last) args->last = nr; + return args->args[nr - 1]; +} + + +/********************************************************************** + * format_insertA (internal) + */ +static LPCSTR format_insertA( int insert, LPCSTR format, DWORD flags, + struct format_args *args, LPSTR *result ) +{ + char *astring = NULL, *p, fmt[256]; + ULONG_PTR arg; + int size; + + if (*format != '!') /* simple string */ + { + char *str = (char *)get_arg( insert, flags, args ); + *result = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 ); + strcpy( *result, str ); + return format; + } + + format++; + p = fmt; + *p++ = '%'; + + while (*format == '0' || + *format == '+' || + *format == '-' || + *format == ' ' || + *format == '*' || + *format == '#') + { + if (*format == '*') + { + p += sprintf( p, "%lu", get_arg( insert, flags, args )); + insert = -1; + format++; + } + else *p++ = *format++; + } + while (isdigit(*format)) *p++ = *format++; + + if (*format == '.') + { + *p++ = *format++; + if (*format == '*') + { + p += sprintf( p, "%lu", get_arg( insert, flags, args )); + insert = -1; + format++; + } + else + while (isdigit(*format)) *p++ = *format++; + } + + /* replicate MS bug: drop an argument when using va_list with width/precision */ + if (insert == -1 && args->list) args->last--; + arg = get_arg( insert, flags, args ); + + /* check for wide string format */ + if ((format[0] == 'l' && format[1] == 's') || + (format[0] == 'l' && format[1] == 'S') || + (format[0] == 'w' && format[1] == 's') || + (format[0] == 'S')) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)arg, -1, /*FIXME*/ + NULL, 0, NULL, NULL ); + astring = HeapAlloc( GetProcessHeap(), 0, len ); + WideCharToMultiByte( CP_ACP, 0, (WCHAR *)arg, -1, astring, len, NULL, NULL ); + arg = (ULONG_PTR)astring; + *p++ = 's'; + } + /* check for wide character format */ + else if ((format[0] == 'l' && format[1] == 'c') || + (format[0] == 'l' && format[1] == 'C') || + (format[0] == 'w' && format[1] == 'c') || + (format[0] == 'C')) + { + WCHAR ch = arg; + DWORD len = WideCharToMultiByte( CP_ACP, 0, &ch, 1, NULL, 0, NULL, NULL ); + astring = HeapAlloc( GetProcessHeap(), 0, len + 1 ); + WideCharToMultiByte( CP_ACP, 0, &ch, 1, astring, len, NULL, NULL ); + astring[len] = 0; + arg = (ULONG_PTR)astring; + *p++ = 's'; + } + /* check for ascii string format */ + else if ((format[0] == 'h' && format[1] == 's') || + (format[0] == 'h' && format[1] == 'S')) + { + *p++ = 's'; + } + /* check for ascii character format */ + else if ((format[0] == 'h' && format[1] == 'c') || + (format[0] == 'h' && format[1] == 'C')) + { + *p++ = 'c'; + } + /* FIXME: handle I64 etc. */ + else while (*format && *format != '!') *p++ = *format++; + + *p = 0; + size = 256; + for (;;) + { + char *ret = HeapAlloc( GetProcessHeap(), 0, size ); + int needed = snprintf( ret, size, fmt, arg ); + if (needed == -1 || needed >= size) + { + HeapFree( GetProcessHeap(), 0, ret ); + size = max( needed + 1, size * 2 ); + } + else + { + *result = ret; + break; + } + } + + while (*format && *format != '!') format++; + if (*format == '!') format++; + + HeapFree( GetProcessHeap(), 0, astring ); + return format; +} + + +/********************************************************************** + * format_insertW (internal) + */ +static LPCWSTR format_insertW( int insert, LPCWSTR format, DWORD flags, + struct format_args *args, LPWSTR *result ) +{ + static const WCHAR fmt_lu[] = {'%','l','u',0}; + WCHAR *wstring = NULL, *p, fmt[256]; + ULONG_PTR arg; + int size; + + if (*format != '!') /* simple string */ + { + WCHAR *str = (WCHAR *)get_arg( insert, flags, args ); + *result = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) ); + strcpyW( *result, str ); + return format; + } + + format++; + p = fmt; + *p++ = '%'; + + while (*format == '0' || + *format == '+' || + *format == '-' || + *format == ' ' || + *format == '*' || + *format == '#') + { + if (*format == '*') + { + p += sprintfW( p, fmt_lu, get_arg( insert, flags, args )); + insert = -1; + format++; + } + else *p++ = *format++; + } + while (isdigitW(*format)) *p++ = *format++; + + if (*format == '.') + { + *p++ = *format++; + if (*format == '*') + { + p += sprintfW( p, fmt_lu, get_arg( insert, flags, args )); + insert = -1; + format++; + } + else + while (isdigitW(*format)) *p++ = *format++; + } + + /* replicate MS bug: drop an argument when using va_list with width/precision */ + if (insert == -1 && args->list) args->last--; + arg = get_arg( insert, flags, args ); + + /* check for ascii string format */ + if ((format[0] == 'h' && format[1] == 's') || + (format[0] == 'h' && format[1] == 'S') || + (format[0] == 'S')) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, (char *)arg, -1, /*FIXME*/ NULL, 0 ); + wstring = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, (char *)arg, -1, wstring, len ); + arg = (ULONG_PTR)wstring; + *p++ = 's'; + } + /* check for ascii character format */ + else if ((format[0] == 'h' && format[1] == 'c') || + (format[0] == 'h' && format[1] == 'C') || + (format[0] == 'C')) + { + char ch = arg; + wstring = HeapAlloc( GetProcessHeap(), 0, 2 * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, &ch, 1, wstring, 1 ); + wstring[1] = 0; + arg = (ULONG_PTR)wstring; + *p++ = 's'; + } + /* check for wide string format */ + else if ((format[0] == 'l' && format[1] == 's') || + (format[0] == 'l' && format[1] == 'S') || + (format[0] == 'w' && format[1] == 's')) + { + *p++ = 's'; + } + /* check for wide character format */ + else if ((format[0] == 'l' && format[1] == 'c') || + (format[0] == 'l' && format[1] == 'C') || + (format[0] == 'w' && format[1] == 'c')) + { + *p++ = 'c'; + } + /* FIXME: handle I64 etc. */ + else while (*format && *format != '!') *p++ = *format++; + + *p = 0; + size = 256; + for (;;) + { + WCHAR *ret = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); + int needed = snprintfW( ret, size, fmt, arg ); + if (needed == -1 || needed >= size) + { + HeapFree( GetProcessHeap(), 0, ret ); + size = max( needed + 1, size * 2 ); + } + else + { + *result = ret; + break; + } + } + + while (*format && *format != '!') format++; + if (*format == '!') format++; + + HeapFree( GetProcessHeap(), 0, wstring ); + return format; +} + + +/*********************************************************************** + * FormatMessageA (KERNEL32.@) + * FIXME: missing wrap, + */ +DWORD WINAPI FormatMessageA( + DWORD dwFlags, + LPCVOID lpSource, + DWORD dwMessageId, + DWORD dwLanguageId, + LPSTR lpBuffer, + DWORD nSize, + __ms_va_list* args ) +{ + struct format_args format_args; + DWORD ret = 0; + LPSTR target,t; + DWORD talloced; + LPSTR from; + LPCSTR f; + DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; + BOOL eos = FALSE; + CHAR ch; + HMODULE kernel32_handle = GetModuleHandleW(kernel32W); + + DPRINT("(0x%x,%p,%d,0x%x,%p,%d,%p)\n", + dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); + if ((dwFlags & FORMAT_MESSAGE_FROM_STRING) + &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) + || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0; + + if (!lpBuffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + + if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) + { + format_args.args = (ULONG_PTR *)args; + format_args.list = NULL; + format_args.last = 0; + } + else + { + format_args.args = NULL; + format_args.list = args; + format_args.last = 0; + } + + if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) + DPRINT1("FIXME: line wrapping (%u) not supported.\n", width); + from = NULL; + if (dwFlags & FORMAT_MESSAGE_FROM_STRING) + { + from = HeapAlloc( GetProcessHeap(), 0, strlen(lpSource) + 1 ); + strcpy( from, lpSource ); + } + else { + from = NULL; + if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) + from = load_messageA( (HMODULE)lpSource, dwMessageId, dwLanguageId ); + if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)) + from = load_messageA( kernel32_handle, dwMessageId, dwLanguageId ); + if (!from) return 0; + } + target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100); + t = target; + talloced= 100; + +#define ADD_TO_T(c) do { \ + *t++=c;\ + if ((DWORD)(t-target) == talloced) {\ + target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2);\ + t = target+talloced;\ + talloced*=2;\ + }\ +} while (0) + + if (from) { + f=from; + if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) { + while (*f && !eos) + ADD_TO_T(*f++); + } + else { + while (*f && !eos) { + if (*f=='%') { + int insertnr; + char *str,*x; + + f++; + if (!*f) { + ADD_TO_T('%'); + continue; + } + switch (*f) { + case '1':case '2':case '3':case '4':case '5': + case '6':case '7':case '8':case '9': + insertnr=*f-'0'; + switch (f[1]) { + case '0':case '1':case '2':case '3': + case '4':case '5':case '6':case '7': + case '8':case '9': + f++; + insertnr=insertnr*10+*f-'0'; + f++; + break; + default: + f++; + break; + } + f = format_insertA( insertnr, f, dwFlags, &format_args, &str ); + for (x = str; *x; x++) ADD_TO_T(*x); + HeapFree( GetProcessHeap(), 0, str ); + break; + case 'n': + ADD_TO_T('\r'); + ADD_TO_T('\n'); + f++; + break; + case '0': + eos = TRUE; + f++; + break; + default: + ADD_TO_T(*f++); + break; + } + } else { + ch = *f; + f++; + if (ch == '\r') { + if (*f == '\n') + f++; + if(width) + ADD_TO_T(' '); + else + { + ADD_TO_T('\r'); + ADD_TO_T('\n'); + } + } else { + if (ch == '\n') + { + if(width) + ADD_TO_T(' '); + else + { + ADD_TO_T('\r'); + ADD_TO_T('\n'); + } + } + else + ADD_TO_T(ch); + } + } + } + } + *t='\0'; + } + talloced = strlen(target)+1; + if (nSize && talloced<nSize) { + target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize); + } + DPRINT("-- %S\n", target); + if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { + *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,max(nSize, talloced)); + memcpy(*(LPSTR*)lpBuffer,target,talloced); + } else { + lstrcpynA(lpBuffer,target,nSize); + } + HeapFree(GetProcessHeap(),0,target); + HeapFree(GetProcessHeap(),0,from); + if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); + ret = (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer) : strlen(lpBuffer); + DPRINT("-- returning %d\n", ret); + return ret; +} +#undef ADD_TO_T + + +/*********************************************************************** + * FormatMessageW (KERNEL32.@) + */ +DWORD WINAPI FormatMessageW( + DWORD dwFlags, + LPCVOID lpSource, + DWORD dwMessageId, + DWORD dwLanguageId, + LPWSTR lpBuffer, + DWORD nSize, + __ms_va_list* args ) +{ + struct format_args format_args; + LPWSTR target,t; + DWORD talloced; + LPWSTR from; + LPCWSTR f; + DWORD width = dwFlags & FORMAT_MESSAGE_MAX_WIDTH_MASK; + BOOL eos = FALSE; + WCHAR ch; + HMODULE kernel32_handle = GetModuleHandleW(kernel32W); + + DPRINT("(0x%x,%p,%d,0x%x,%p,%d,%p)\n", + dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args); + if ((dwFlags & FORMAT_MESSAGE_FROM_STRING) + &&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM) + || (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0; + + if (!lpBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY) + { + format_args.args = (ULONG_PTR *)args; + format_args.list = NULL; + format_args.last = 0; + } + else + { + format_args.args = NULL; + format_args.list = args; + format_args.last = 0; + } + + if (width && width != FORMAT_MESSAGE_MAX_WIDTH_MASK) + DPRINT1("FIXME: line wrapping not supported.\n"); + from = NULL; + if (dwFlags & FORMAT_MESSAGE_FROM_STRING) { + from = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpSource) + 1) * + sizeof(WCHAR) ); + strcpyW( from, lpSource ); + } + else { + from = NULL; + if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE) + from = load_messageW( (HMODULE)lpSource, dwMessageId, dwLanguageId ); + if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)) + from = load_messageW( kernel32_handle, dwMessageId, dwLanguageId ); + if (!from) return 0; + } + target = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 100 * sizeof(WCHAR) ); + t = target; + talloced= 100; + +#define ADD_TO_T(c) do {\ + *t++=c;\ + if ((DWORD)(t-target) == talloced) {\ + target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,talloced*2*sizeof(WCHAR));\ + t = target+talloced;\ + talloced*=2;\ + } \ +} while (0) + + if (from) { + f=from; + if (dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS) { + while (*f && !eos) + ADD_TO_T(*f++); + } + else { + while (*f && !eos) { + if (*f=='%') { + int insertnr; + WCHAR *str,*x; + + f++; + if (!*f) { + ADD_TO_T('%'); + continue; + } + + switch (*f) { + case '1':case '2':case '3':case '4':case '5': + case '6':case '7':case '8':case '9': + insertnr=*f-'0'; + switch (f[1]) { + case '0':case '1':case '2':case '3': + case '4':case '5':case '6':case '7': + case '8':case '9': + f++; + insertnr=insertnr*10+*f-'0'; + f++; + break; + default: + f++; + break; + } + f = format_insertW( insertnr, f, dwFlags, &format_args, &str ); + for (x = str; *x; x++) ADD_TO_T(*x); + HeapFree( GetProcessHeap(), 0, str ); + break; + case 'n': + ADD_TO_T('\r'); + ADD_TO_T('\n'); + f++; + break; + case '0': + eos = TRUE; + f++; + break; + default: + ADD_TO_T(*f++); + break; + } + } else { + ch = *f; + f++; + if (ch == '\r') { + if (*f == '\n') + f++; + if(width) + ADD_TO_T(' '); + else + { + ADD_TO_T('\r'); + ADD_TO_T('\n'); + } + } else { + if (ch == '\n') + { + if(width) + ADD_TO_T(' '); + else + { + ADD_TO_T('\r'); + ADD_TO_T('\n'); + } + } + else + ADD_TO_T(ch); + } + } + } + } + *t='\0'; + } + talloced = strlenW(target)+1; + if (nSize && talloced<nSize) + target = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,target,nSize*sizeof(WCHAR)); + if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { + /* nSize is the MINIMUM size */ + DWORD len = strlenW(target) + 1; + *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,len*sizeof(WCHAR)); + strcpyW(*(LPWSTR*)lpBuffer, target); + } + else lstrcpynW(lpBuffer, target, nSize); + + HeapFree(GetProcessHeap(),0,target); + HeapFree(GetProcessHeap(),0,from); + if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); + DPRINT("ret=%S\n", (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? + *(LPWSTR*)lpBuffer : lpBuffer); + return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? + strlenW(*(LPWSTR*)lpBuffer): + strlenW(lpBuffer); +} +#undef ADD_TO_T
Propchange: trunk/reactos/dll/win32/kernel32/misc/format_msg.c ------------------------------------------------------------------------------ svn:eol-style = native