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