update for HEAD-2003021201
[reactos.git] / lib / user32 / misc / resources.c
1 #include <string.h>
2 #include <windows.h>
3 #include <ddk/ntddk.h>
4 #include <kernel32/error.h>
5
6 BOOL STDCALL _InternalLoadString
7 (
8  HINSTANCE hInstance,
9  UINT uID,
10  PUNICODE_STRING pwstrDest
11 )
12 {
13  HRSRC hrsStringTable;
14  PWCHAR pStringTable;
15  unsigned i;
16  unsigned l = uID % 16; /* (1) */
17
18  /* parameter validation */
19  if(IsBadWritePtr(pwstrDest, sizeof(UNICODE_STRING)))
20  {
21   SetLastError(ERROR_INVALID_PARAMETER);
22   return FALSE;
23  }
24
25  /*
26   find the string table. String tables are created by grouping, 16 by 16, string
27   resources whose identifiers, divided by 16, have the same integer quotient.
28   Holes in the numbering are filled with zero-length strings. String table ids
29   (actual resource ids) start from 1. See (1) and (2)
30  */
31  /* TODO: some sort of cache, here, would be great */
32  hrsStringTable = FindResource
33  (
34   (HMODULE)hInstance,
35   MAKEINTRESOURCE((uID / 16) + 1), /* (2) */
36   RT_STRING
37  );
38
39  /* failure */
40  if(hrsStringTable == NULL) return FALSE;
41
42  /* load the string table into memory */
43  pStringTable = LoadResource((HMODULE)hInstance, hrsStringTable);
44
45  /* failure */
46  if(pStringTable == NULL) return FALSE;
47
48  /*
49   string tables are packed Unicode Pascal strings. The first WCHAR contains the
50   length, in characters, of the current string. Zero-length strings, if any, are
51   placeholders for unused slots, and should therefore be considered non-present.
52   See also (3). Here, we walk all the strings before that of interest
53  */
54  for(i = 0; i < l; ++ i)
55  {
56   /* skip the length and the current string */
57   pStringTable += 1 + (*pStringTable);
58  }
59
60  /* we've reached the string of interest */
61  if((*pStringTable) == 0)
62  {
63   /* the string is empty (unallocated) */
64   SetLastError(ERROR_RESOURCE_NAME_NOT_FOUND);
65   return FALSE; /* 3 */
66  }
67
68  /* string length */
69  pwstrDest->Length = pwstrDest->MaximumLength = (*pStringTable);
70
71  /* string */
72  pwstrDest->Buffer = pStringTable + 1;
73
74  /* success */
75  return TRUE;
76 }
77
78 int STDCALL LoadStringA
79 (
80  HINSTANCE hInstance,
81  UINT uID,
82  LPSTR lpBuffer,
83  int nBufferMax
84 )
85 {
86  UNICODE_STRING wstrResStr;
87  ANSI_STRING strBuf;
88  NTSTATUS nErrCode;
89
90  /* parameter validation */
91  if
92  (
93   (nBufferMax < 1) ||
94   (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
95  )
96  {
97   SetLastError(ERROR_INVALID_PARAMETER);
98   return 0;
99  }
100
101  /* get the UNICODE_STRING descriptor of the in-memory image of the string */
102  if(!_InternalLoadString(hInstance, uID, &wstrResStr))
103   /* failure */
104   return 0;
105
106  /*
107   convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
108   don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
109   it, if necessary
110  */
111  strBuf.Length = 0;
112  strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
113  strBuf.Buffer = lpBuffer;
114
115  nErrCode = RtlUnicodeStringToAnsiString(&strBuf, &wstrResStr, FALSE);
116  
117  if(!NT_SUCCESS(nErrCode))
118  {
119   /* failure */
120   SetLastErrorByStatus(nErrCode);
121   return 0;
122  }
123
124  /* the ANSI string may not be null-terminated */
125  if(strBuf.Length >= strBuf.MaximumLength)
126  {
127   /* length greater than the buffer? whatever */
128   int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
129
130   /* zero the last character in the buffer */
131   strBuf.Buffer[nStringLen] = 0;
132
133   /* success */
134   return nStringLen;
135  }
136  else
137  {
138   /* zero the last character in the string */
139   strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
140
141   /* success */
142   return strBuf.Length / sizeof(CHAR);
143  }
144 }
145
146 int STDCALL LoadStringW
147 (
148  HINSTANCE hInstance,
149  UINT uID,
150  LPWSTR lpBuffer,
151  int nBufferMax
152 )
153 {
154  UNICODE_STRING wstrResStr;
155  int nStringLen;
156
157  /* parameter validation */
158  if
159  (
160   (nBufferMax < 1) ||
161   (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
162  )
163  {
164   SetLastError(ERROR_INVALID_PARAMETER);
165   return 0;
166  }
167
168  /* get the UNICODE_STRING descriptor of the in-memory image of the string */
169  if(!_InternalLoadString(hInstance, uID, &wstrResStr))
170   /* failure */
171   return 0;
172
173  /* get the length in characters */
174  nStringLen = wstrResStr.Length / sizeof(WCHAR);
175
176  /* the buffer must be enough to contain the string and the null terminator */
177  if(nBufferMax < (nStringLen + 1))
178   /* otherwise, the string is truncated */
179   nStringLen = nBufferMax - 1;
180
181  /* copy the string */
182  memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
183  
184  /* null-terminate it */
185  lpBuffer[nStringLen] = 0;
186  
187  /* success */
188  return nStringLen;
189 }
190
191 /* EOF */