branch update for HEAD-2003091401
[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 = FindResourceW
39  (
40   (HMODULE)hInstance,
41   MAKEINTRESOURCEW((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
91 /*
92  * @implemented
93  */
94 int STDCALL LoadStringA
95 (
96  HINSTANCE hInstance,
97  UINT uID,
98  LPSTR lpBuffer,
99  int nBufferMax
100 )
101 {
102  UNICODE_STRING wstrResStr;
103  ANSI_STRING strBuf;
104  NTSTATUS nErrCode;
105
106  /* parameter validation */
107  if
108  (
109   (nBufferMax < 1) ||
110   (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
111  )
112  {
113   SetLastError(ERROR_INVALID_PARAMETER);
114   return 0;
115  }
116
117  /* get the UNICODE_STRING descriptor of the in-memory image of the string */
118  if(!_InternalLoadString(hInstance, uID, &wstrResStr))
119   /* failure */
120   return 0;
121
122  /*
123   convert the string. The Unicode string may be in UTF-16 (multi-byte), so we
124   don't alter wstrResStr.Length, and let RtlUnicodeStringToAnsiString truncate
125   it, if necessary
126  */
127  strBuf.Length = 0;
128  strBuf.MaximumLength = nBufferMax * sizeof(CHAR);
129  strBuf.Buffer = lpBuffer;
130
131  nErrCode = RtlUnicodeStringToAnsiString(&strBuf, &wstrResStr, FALSE);
132  
133  if(!NT_SUCCESS(nErrCode))
134  {
135   /* failure */
136   RtlNtStatusToDosError(nErrCode);
137   return 0;
138  }
139
140  /* the ANSI string may not be null-terminated */
141  if(strBuf.Length >= strBuf.MaximumLength)
142  {
143   /* length greater than the buffer? whatever */
144   int nStringLen = strBuf.MaximumLength / sizeof(CHAR) - 1;
145
146   /* zero the last character in the buffer */
147   strBuf.Buffer[nStringLen] = 0;
148
149   /* success */
150   return nStringLen;
151  }
152  else
153  {
154   /* zero the last character in the string */
155   strBuf.Buffer[strBuf.Length / sizeof(CHAR)] = 0;
156
157   /* success */
158   return strBuf.Length / sizeof(CHAR);
159  }
160 }
161
162
163 /*
164  * @implemented
165  */
166 int STDCALL LoadStringW
167 (
168  HINSTANCE hInstance,
169  UINT uID,
170  LPWSTR lpBuffer,
171  int nBufferMax
172 )
173 {
174  UNICODE_STRING wstrResStr;
175  int nStringLen;
176
177  /* parameter validation */
178  if
179  (
180   (nBufferMax < 1) ||
181   (IsBadWritePtr(lpBuffer, nBufferMax * sizeof(lpBuffer[0])))
182  )
183  {
184   SetLastError(ERROR_INVALID_PARAMETER);
185   return 0;
186  }
187
188  /* get the UNICODE_STRING descriptor of the in-memory image of the string */
189  if(!_InternalLoadString(hInstance, uID, &wstrResStr))
190   /* failure */
191   return 0;
192
193  /* get the length in characters */
194  nStringLen = wstrResStr.Length / sizeof(WCHAR);
195
196  /* the buffer must be enough to contain the string and the null terminator */
197  if(nBufferMax < (nStringLen + 1))
198   /* otherwise, the string is truncated */
199   nStringLen = nBufferMax - 1;
200
201  /* copy the string */
202  memcpy(lpBuffer, wstrResStr.Buffer, nStringLen * sizeof(WCHAR));
203  
204  /* null-terminate it */
205  lpBuffer[nStringLen] = 0;
206  
207  /* success */
208  return nStringLen;
209 }
210
211 /* EOF */