ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

format_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.