update for HEAD-2003021201
[reactos.git] / lib / user32 / misc / resources.c
index 47e5e54..0e35d36 100644 (file)
 #include <ddk/ntddk.h>
 #include <kernel32/error.h>
 
-int
-STDCALL
-LoadStringA( HINSTANCE hInstance,
           UINT uID,
-            LPSTR lpBuffer,
-            int nBufferMax)
+BOOL STDCALL _InternalLoadString
+(
+ HINSTANCE hInstance,
+ UINT uID,
+ PUNICODE_STRING pwstrDest
+)
 {
-  HRSRC rsc;
-  PBYTE ptr;
-  int len;
-  int count, dest = uID % 16;
-  PWSTR pwstr;
-  UNICODE_STRING UString;
-  ANSI_STRING AString;
-  NTSTATUS Status;
-  
-  rsc = FindResource( (HMODULE)hInstance,
-                     MAKEINTRESOURCE( (uID / 16) + 1 ),
-                     RT_STRING );
-  if( rsc == NULL )
-    return 0;
-  // get pointer to string table
-  ptr = (PBYTE)LoadResource( (HMODULE)hInstance, rsc );
-  if( ptr == NULL )
-    return 0;
-  for( count = 0; count <= dest; count++ )
-    {
-      // walk each of the 16 string slots in the string table
-      len = (*(USHORT *)ptr) * 2;  // length is in unicode chars, convert to bytes
-      ptr += 2;    // first 2 bytes are length, string follows
-      pwstr = (PWSTR)ptr;
-      ptr += len;
-    }
-  if( !len )
-    return 0;   // zero means no string is there
-  // convert unitocde to ansi, and copy string to caller buffer
-  UString.Length = UString.MaximumLength = len;
-  UString.Buffer = pwstr;
-  memset( &AString, 0, sizeof AString );
-  Status = RtlUnicodeStringToAnsiString( &AString, &UString, TRUE );
-  if( !NT_SUCCESS( Status ) )
-    {
-      SetLastErrorByStatus( Status );
-      return 0;
-    }
-  nBufferMax--;  // save room for the null
-  if( nBufferMax > AString.Length )
-    nBufferMax = AString.Length;
-  memcpy( lpBuffer, AString.Buffer, nBufferMax );
-  lpBuffer[nBufferMax] = 0;
-  RtlFreeAnsiString( &AString );
-  return nBufferMax;
+ HRSRC hrsStringTable;
+ PWCHAR pStringTable;
+ unsigned i;
+ unsigned l = uID % 16; /* (1) */
+
+ /* parameter validation */
+ if(IsBadWritePtr(pwstrDest, sizeof(UNICODE_STRING)))
+ {
+  SetLastError(ERROR_INVALID_PARAMETER);
+  return FALSE;
+ }
+
+ /*
+  find the string table. String tables are created by grouping, 16 by 16, string
+  resources whose identifiers, divided by 16, have the same integer quotient.
+  Holes in the numbering are filled with zero-length strings. String table ids
+  (actual resource ids) start from 1. See (1) and (2)
+ */
+ /* TODO: some sort of cache, here, would be great */
+ hrsStringTable = FindResource
+ (
+  (HMODULE)hInstance,
+  MAKEINTRESOURCE((uID / 16) + 1), /* (2) */
+  RT_STRING
+ );
+
+ /* failure */
+ if(hrsStringTable == NULL) return FALSE;
+
+ /* load the string table into memory */
+ pStringTable = LoadResource((HMODULE)hInstance, hrsStringTable);
+
+ /* failure */
+ if(pStringTable == NULL) return FALSE;
+
+ /*
+  string tables are packed Unicode Pascal strings. The first WCHAR contains the
+  length, in characters, of the current string. Zero-length strings, if any, are
+  placeholders for unused slots, and should therefore be considered non-present.
+  See also (3). Here, we walk all the strings before that of interest
+ */
+ for(i = 0; i < l; ++ i)
+ {
+  /* skip the length and the current string */
+  pStringTable += 1 + (*pStringTable);
+ }
+
+ /* we've reached the string of interest */
+ if((*pStringTable) == 0)
+ {
+  /* the string is empty (unallocated) */
+  SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
+  return FALSE; /* 3 */
+ }
+
+ /* string length */
+ pwstrDest->Length = pwstrDest->MaximumLength = (*pStringTable);
+
+ /* string */
+ pwstrDest->Buffer = pStringTable + 1;
+
+ /* success */
+ return TRUE;
+}
+
+int STDCALL LoadStringA
+(
+ HINSTANCE hInstance,
+ UINT uID,
+ LPSTR lpBuffer,
+ int nBufferMax
+)
+{
+ UNICODE_STRING wstrResStr;
+ ANSI_STRING strBuf;
+ NTSTATUS nErrCode;
+
+ /* parameter validation */
+ if
+ (
+  (nBufferMax < 1) ||
+  (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
+ )
+ {
+  SetLastError(ERROR_INVALID_PARAMETER);
+  return 0;
+ }
+
+ /* get the UNICODE_STRING descriptor of the in-memory image of the string */
+ if(!_InternalLoadString(hInstance, uID, &wstrResStr))
+  /* failure */
+  return 0;
+
+ /*
+  convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
+  don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
+  it, if necessary
+ */
+ strBuf.Length = 0;
+ strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
+ strBuf.Buffer = lpBuffer;
+
+ nErrCode = RtlUnicodeStringToAnsiString(&strBuf, &wstrResStr, FALSE);
+ if(!NT_SUCCESS(nErrCode))
+ {
+  /* failure */
+  SetLastErrorByStatus(nErrCode);
+  return 0;
+ }
+
+ /* the ANSI string may not be null-terminated */
+ if(strBuf.Length >= strBuf.MaximumLength)
+ {
+  /* length greater than the buffer? whatever */
+  int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
+
+  /* zero the last character in the buffer */
+  strBuf.Buffer[nStringLen] = 0;
+
+  /* success */
+  return nStringLen;
+ }
+ else
+ {
+  /* zero the last character in the string */
+  strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
+
+  /* success */
+  return strBuf.Length / sizeof(CHAR);
+ }
 }
+
+int STDCALL LoadStringW
+(
+ HINSTANCE hInstance,
+ UINT uID,
+ LPWSTR lpBuffer,
+ int nBufferMax
+)
+{
+ UNICODE_STRING wstrResStr;
+ int nStringLen;
+
+ /* parameter validation */
+ if
+ (
+  (nBufferMax < 1) ||
+  (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
+ )
+ {
+  SetLastError(ERROR_INVALID_PARAMETER);
+  return 0;
+ }
+
+ /* get the UNICODE_STRING descriptor of the in-memory image of the string */
+ if(!_InternalLoadString(hInstance, uID, &wstrResStr))
+  /* failure */
+  return 0;
+
+ /* get the length in characters */
+ nStringLen = wstrResStr.Length / sizeof(WCHAR);
+
+ /* the buffer must be enough to contain the string and the null terminator */
+ if(nBufferMax < (nStringLen + 1))
+  /* otherwise, the string is truncated */
+  nStringLen = nBufferMax - 1;
+
+ /* copy the string */
+ memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
+ /* null-terminate it */
+ lpBuffer[nStringLen] = 0;
  
+ /* success */
+ return nStringLen;
+}
+
+/* EOF */