Added some more tests.
[wine] / dlls / user / resource.c
1 /*
2  * USER resource functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winerror.h"
25 #include "winnls.h"
26 #include "wine/winbase16.h"
27 #include "wine/winuser16.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(resource);
31 WINE_DECLARE_DEBUG_CHANNEL(accel);
32
33 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
34 typedef struct
35 {
36     BYTE   fVirt;
37     BYTE   pad0;
38     WORD   key;
39     WORD   cmd;
40     WORD   pad1;
41 } PE_ACCEL, *LPPE_ACCEL;
42
43 /**********************************************************************
44  *                      LoadAccelerators        [USER.177]
45  */
46 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, LPCSTR lpTableName)
47 {
48     HRSRC16     hRsrc;
49
50     TRACE_(accel)("%04x %s\n", instance, debugres_a(lpTableName) );
51
52     if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATORA ))) {
53       WARN_(accel)("couldn't find accelerator table resource\n");
54       return 0;
55     }
56
57     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
58     return LoadResource16(instance,hRsrc);
59 }
60
61 /**********************************************************************
62  *                      LoadAcceleratorsW       (USER32.@)
63  * The image layout seems to look like this (not 100% sure):
64  * 00:  BYTE    type            type of accelerator
65  * 01:  BYTE    pad             (to WORD boundary)
66  * 02:  WORD    event
67  * 04:  WORD    IDval           
68  * 06:  WORD    pad             (to DWORD boundary)
69  */
70 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE instance,LPCWSTR lpTableName)
71 {
72     HRSRC hRsrc;
73     HACCEL hMem,hRetval=0;
74     DWORD size;
75
76     if (HIWORD(lpTableName))
77         TRACE_(accel)("%p '%s'\n",
78                       (LPVOID)instance, (char *)( lpTableName ) );
79     else
80         TRACE_(accel)("%p 0x%04x\n",
81                        (LPVOID)instance, LOWORD(lpTableName) );
82
83     if (!(hRsrc = FindResourceW( instance, lpTableName, RT_ACCELERATORW )))
84     {
85       WARN_(accel)("couldn't find accelerator table resource\n");
86     } else {
87       hMem = LoadResource( instance, hRsrc );
88       size = SizeofResource( instance, hRsrc );
89       if(size>=sizeof(PE_ACCEL))
90       {
91         LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem;
92         LPACCEL16 accel16;
93         int i,nrofaccells = size/sizeof(PE_ACCEL);
94
95         hRetval = GlobalAlloc16(0,sizeof(ACCEL16)*nrofaccells);
96         accel16 = (LPACCEL16)GlobalLock16(hRetval);
97         for (i=0;i<nrofaccells;i++) {
98                 accel16[i].fVirt = accel_table[i].fVirt;
99                 accel16[i].key = accel_table[i].key;
100                 accel16[i].cmd = accel_table[i].cmd;
101         }
102         accel16[i-1].fVirt |= 0x80;
103       }
104     }
105     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
106     return hRetval;
107 }
108
109 /***********************************************************************
110  *              LoadAcceleratorsA   (USER32.@)
111  */
112 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE instance,LPCSTR lpTableName)
113 {
114     INT len;
115     LPWSTR uni;
116     HACCEL result = 0;
117
118     if (!HIWORD(lpTableName)) return LoadAcceleratorsW( instance, (LPCWSTR)lpTableName );
119
120     len = MultiByteToWideChar( CP_ACP, 0, lpTableName, -1, NULL, 0 );
121     if ((uni = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
122     {
123         MultiByteToWideChar( CP_ACP, 0, lpTableName, -1, uni, len );
124         result = LoadAcceleratorsW(instance,uni);
125         HeapFree( GetProcessHeap(), 0, uni);
126     }
127     return result;
128 }
129
130 /**********************************************************************
131  *             CopyAcceleratorTableA   (USER32.@)
132  */
133 INT WINAPI CopyAcceleratorTableA(HACCEL src, LPACCEL dst, INT entries)
134 {
135   return CopyAcceleratorTableW(src, dst, entries);
136 }
137
138 /**********************************************************************
139  *             CopyAcceleratorTableW   (USER32.@)
140  *
141  * By mortene@pvv.org 980321
142  */
143 INT WINAPI CopyAcceleratorTableW(HACCEL src, LPACCEL dst,
144                                      INT entries)
145 {
146   int i,xsize;
147   LPACCEL16 accel = (LPACCEL16)GlobalLock16(src);
148   BOOL done = FALSE;
149
150   /* Do parameter checking to avoid the explosions and the screaming
151      as far as possible. */
152   if((dst && (entries < 1)) || (src == (HACCEL)NULL) || !accel) {
153     WARN_(accel)("Application sent invalid parameters (%p %p %d).\n",
154          (LPVOID)src, (LPVOID)dst, entries);
155     return 0;
156   }
157   xsize = GlobalSize16(src)/sizeof(ACCEL16);
158   if (xsize>entries) entries=xsize;
159
160   i=0;
161   while(!done) {
162     /* Spit out some debugging information. */
163     TRACE_(accel)("accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
164           i, accel[i].fVirt, accel[i].key, accel[i].cmd);
165
166     /* Copy data to the destination structure array (if dst == NULL,
167        we're just supposed to count the number of entries). */
168     if(dst) {
169       dst[i].fVirt = accel[i].fVirt;
170       dst[i].key = accel[i].key;
171       dst[i].cmd = accel[i].cmd;
172
173       /* Check if we've reached the end of the application supplied
174          accelerator table. */
175       if(i+1 == entries) {
176         /* Turn off the high order bit, just in case. */
177         dst[i].fVirt &= 0x7f;
178         done = TRUE;
179       }
180     }
181
182     /* The highest order bit seems to mark the end of the accelerator
183        resource table, but not always. Use GlobalSize() check too. */
184     if((accel[i].fVirt & 0x80) != 0) done = TRUE;
185
186     i++;
187   }
188
189   return i;
190 }
191
192 /*********************************************************************
193  *                    CreateAcceleratorTableA   (USER32.@)
194  *
195  * By mortene@pvv.org 980321
196  */
197 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccel, INT cEntries)
198 {
199   HACCEL        hAccel;
200   LPACCEL16     accel;
201   int           i;
202
203   /* Do parameter checking just in case someone's trying to be
204      funny. */
205   if(cEntries < 1) {
206     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
207          lpaccel, cEntries);
208     SetLastError(ERROR_INVALID_PARAMETER);
209     return (HACCEL)NULL;
210   }
211   FIXME_(accel)("should check that the accelerator descriptions are valid,"
212         " return NULL and SetLastError() if not.\n");
213
214
215   /* Allocate memory and copy the table. */
216   hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
217
218   TRACE_(accel)("handle %x\n", hAccel);
219   if(!hAccel) {
220     ERR_(accel)("Out of memory.\n");
221     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
222     return (HACCEL)NULL;
223   }
224   accel = GlobalLock16(hAccel);
225   for (i=0;i<cEntries;i++) {
226         accel[i].fVirt = lpaccel[i].fVirt;
227         accel[i].key = lpaccel[i].key;
228         accel[i].cmd = lpaccel[i].cmd;
229   }
230   /* Set the end-of-table terminator. */
231   accel[cEntries-1].fVirt |= 0x80;
232
233   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
234   return hAccel;
235 }
236
237 /*********************************************************************
238  *                    CreateAcceleratorTableW   (USER32.@)
239  *
240  * 
241  */
242 HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccel, INT cEntries)
243 {
244   HACCEL        hAccel;
245   LPACCEL16     accel;
246   int           i;
247   char          ckey;  
248
249   /* Do parameter checking just in case someone's trying to be
250      funny. */
251   if(cEntries < 1) {
252     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
253          lpaccel, cEntries);
254     SetLastError(ERROR_INVALID_PARAMETER);
255     return (HACCEL)NULL;
256   }
257   FIXME_(accel)("should check that the accelerator descriptions are valid,"
258         " return NULL and SetLastError() if not.\n");
259
260
261   /* Allocate memory and copy the table. */
262   hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
263
264   TRACE_(accel)("handle %x\n", hAccel);
265   if(!hAccel) {
266     ERR_(accel)("Out of memory.\n");
267     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
268     return (HACCEL)NULL;
269   }
270   accel = GlobalLock16(hAccel);
271
272
273   for (i=0;i<cEntries;i++) {
274        accel[i].fVirt = lpaccel[i].fVirt;
275        if( !(accel[i].fVirt & FVIRTKEY) ) {
276           ckey = (char) lpaccel[i].key;
277          if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, &ckey, 1, &accel[i].key, 1))
278             WARN_(accel)("Error converting ASCII accelerator table to Unicode");
279        }
280        else 
281          accel[i].key = lpaccel[i].key; 
282        accel[i].cmd = lpaccel[i].cmd;
283   }
284
285   /* Set the end-of-table terminator. */
286   accel[cEntries-1].fVirt |= 0x80;
287
288   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
289   return hAccel;
290 }
291
292 /******************************************************************************
293  * DestroyAcceleratorTable [USER32.@]
294  * Destroys an accelerator table
295  *
296  * NOTES
297  *    By mortene@pvv.org 980321
298  *
299  * PARAMS
300  *    handle [I] Handle to accelerator table
301  *
302  * RETURNS STD
303  */
304 BOOL WINAPI DestroyAcceleratorTable( HACCEL handle )
305 {
306     return !GlobalFree16(handle); 
307 }
308   
309 /**********************************************************************
310  *     LoadString   (USER.176)
311  */
312 INT16 WINAPI LoadString16( HINSTANCE16 instance, UINT16 resource_id,
313                            LPSTR buffer, INT16 buflen )
314 {
315     HGLOBAL16 hmem;
316     HRSRC16 hrsrc;
317     unsigned char *p;
318     int string_num;
319     int i;
320
321     TRACE("inst=%04x id=%04x buff=%08x len=%d\n",
322           instance, resource_id, (int) buffer, buflen);
323
324     hrsrc = FindResource16( instance, (LPCSTR)((resource_id>>4)+1), RT_STRINGA );
325     if (!hrsrc) return 0;
326     hmem = LoadResource16( instance, hrsrc );
327     if (!hmem) return 0;
328     
329     p = LockResource16(hmem);
330     string_num = resource_id & 0x000f;
331     for (i = 0; i < string_num; i++)
332         p += *p + 1;
333     
334     TRACE("strlen = %d\n", (int)*p );
335     
336     if (buffer == NULL) return *p;
337     i = min(buflen - 1, *p);
338     if (i > 0) {
339         memcpy(buffer, p + 1, i);
340         buffer[i] = '\0';
341     } else {
342         if (buflen > 1) {
343             buffer[0] = '\0';
344             return 0;
345         }
346         WARN("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
347     }
348     FreeResource16( hmem );
349
350     TRACE("'%s' loaded !\n", buffer);
351     return i;
352 }
353
354 /**********************************************************************
355  *      LoadStringW             (USER32.@)
356  */
357 INT WINAPI LoadStringW( HINSTANCE instance, UINT resource_id,
358                             LPWSTR buffer, INT buflen )
359 {
360     HGLOBAL hmem;
361     HRSRC hrsrc;
362     WCHAR *p;
363     int string_num;
364     int i;
365
366     if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */
367         resource_id = (UINT)(-((INT)resource_id));
368     TRACE("instance = %04x, id = %04x, buffer = %08x, length = %d\n",
369           instance, (int)resource_id, (int) buffer, buflen);
370
371     /* Use bits 4 - 19 (incremented by 1) as resourceid, mask out 
372      * 20 - 31. */
373     hrsrc = FindResourceW( instance, (LPCWSTR)(((resource_id>>4)&0xffff)+1),
374                              RT_STRINGW );
375     if (!hrsrc) return 0;
376     hmem = LoadResource( instance, hrsrc );
377     if (!hmem) return 0;
378     
379     p = LockResource(hmem);
380     string_num = resource_id & 0x000f;
381     for (i = 0; i < string_num; i++)
382         p += *p + 1;
383     
384     TRACE("strlen = %d\n", (int)*p );
385     
386     if (buffer == NULL) return *p;
387     i = min(buflen - 1, *p);
388     if (i > 0) {
389         memcpy(buffer, p + 1, i * sizeof (WCHAR));
390         buffer[i] = (WCHAR) 0;
391     } else {
392         if (buflen > 1) {
393             buffer[0] = (WCHAR) 0;
394             return 0;
395         }
396 #if 0
397         WARN("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
398 #endif
399     }
400
401     TRACE("%s loaded !\n", debugstr_w(buffer));
402     return i;
403 }
404
405 /**********************************************************************
406  *      LoadStringA     (USER32.@)
407  */
408 INT WINAPI LoadStringA( HINSTANCE instance, UINT resource_id,
409                             LPSTR buffer, INT buflen )
410 {
411     INT    retval;
412     LPWSTR wbuf;
413
414     TRACE("instance = %04x, id = %04x, buffer = %08x, length = %d\n",
415           instance, (int)resource_id, (int) buffer, buflen);
416
417     if(buffer == NULL) /* asked size of string */
418         return LoadStringW(instance, resource_id, NULL, 0);
419     
420     wbuf = HeapAlloc(GetProcessHeap(), 0, buflen * sizeof(WCHAR));
421     if(!wbuf)
422         return 0;
423
424     retval = LoadStringW(instance, resource_id, wbuf, buflen);
425     if(retval != 0)
426     {
427         retval = WideCharToMultiByte(CP_ACP, 0, wbuf, retval, buffer, buflen - 1, NULL, NULL);
428         buffer[retval] = 0;
429         TRACE("%s loaded !\n", debugstr_a(buffer));
430     }
431     else buffer[0] = 0;    /* no check of buflen here */
432     HeapFree( GetProcessHeap(), 0, wbuf );
433
434     return retval;
435 }