Fix declarations.
[wine] / tools / winedump / lnk.c
1 /*
2  *  Dump a shortcut (lnk) file
3  *
4  *  Copyright 2005 Mike McCormack
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include "winedump.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33 #include <fcntl.h>
34 #include <stdarg.h>
35
36 #include "windef.h"
37 #include "winbase.h"
38
39 #include "pshpack1.h"
40
41 #define SCF_PIDL 1
42 #define SCF_LOCATION 2
43 #define SCF_DESCRIPTION 4
44 #define SCF_RELATIVE 8
45 #define SCF_WORKDIR 0x10
46 #define SCF_ARGS 0x20
47 #define SCF_CUSTOMICON 0x40
48 #define SCF_UNICODE 0x80
49 #define SCF_PRODUCT 0x800
50 #define SCF_COMPONENT 0x1000
51
52 typedef struct _LINK_HEADER
53 {
54     DWORD    dwSize;        /* 0x00 size of the header - 0x4c */
55     GUID     MagicGuid;     /* 0x04 is CLSID_ShellLink */
56     DWORD    dwFlags;       /* 0x14 describes elements following */
57     DWORD    dwFileAttr;    /* 0x18 attributes of the target file */
58     FILETIME Time1;         /* 0x1c */
59     FILETIME Time2;         /* 0x24 */
60     FILETIME Time3;         /* 0x2c */
61     DWORD    dwFileLength;  /* 0x34 File length */
62     DWORD    nIcon;         /* 0x38 icon number */
63     DWORD   fStartup;       /* 0x3c startup type */
64     DWORD   wHotKey;        /* 0x40 hotkey */
65     DWORD   Unknown5;       /* 0x44 */
66     DWORD   Unknown6;       /* 0x48 */
67 } LINK_HEADER, * PLINK_HEADER;
68
69 typedef struct tagLINK_ADVERTISEINFO
70 {
71     DWORD size;
72     DWORD magic;
73     CHAR  bufA[MAX_PATH];
74     WCHAR bufW[MAX_PATH];
75 } LINK_ADVERTISEINFO;
76
77 typedef struct _LOCATION_INFO
78 {
79     DWORD  dwTotalSize;
80     DWORD  dwHeaderSize;
81     DWORD  dwFlags;
82     DWORD  dwVolTableOfs;
83     DWORD  dwLocalPathOfs;
84     DWORD  dwNetworkVolTableOfs;
85     DWORD  dwFinalPathOfs;
86 } LOCATION_INFO;
87
88 typedef struct _LOCAL_VOLUME_INFO
89 {
90     DWORD dwSize;
91     DWORD dwType;
92     DWORD dwVolSerial;
93     DWORD dwVolLabelOfs;
94 } LOCAL_VOLUME_INFO;
95
96 typedef struct lnk_string_tag {
97     unsigned short size;
98     union {
99         unsigned short w[1];
100         unsigned char a[1];
101     } str;
102 } lnk_string;
103
104 #include "poppack.h"
105
106 static void guid_to_string(LPGUID guid, char *str)
107 {
108     sprintf(str, "{%08lx-%04x-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}",
109             guid->Data1, guid->Data2, guid->Data3,
110             guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
111             guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
112 }
113
114 /* the size is a short integer */
115 static void* load_pidl(int fd)
116 {
117     int r;
118     unsigned char *data;
119     unsigned short size = 0;
120
121     r = read( fd, &size, sizeof size );
122     if (r != sizeof size)
123         return NULL;
124     if (size<sizeof size)
125         return NULL;
126
127     data = malloc(size + sizeof size);
128     memcpy(data, &size, sizeof size);
129     r = read( fd, data + sizeof size, size );
130     if (r != size)
131     {
132         free(data);
133         return NULL;
134     }
135     return (void*)data;
136 }
137
138 /* size is an integer */
139 static void* load_long_section(int fd)
140 {
141     int r, size = 0;
142     unsigned char *data;
143
144     r = read( fd, &size, sizeof size );
145     if (r != sizeof size)
146         return NULL;
147     if (size<sizeof size)
148         return NULL;
149
150     data = malloc(size);
151     memcpy(data, &size, sizeof size);
152     r = read( fd, data + sizeof size, size - sizeof size);
153     if (r != (size - sizeof size))
154     {
155         free(data);
156         return NULL;
157     }
158     return (void*)data;
159 }
160
161 /* the size is a character count in a short integer */
162 static lnk_string* load_string(int fd, int unicode)
163 {
164     int r;
165     lnk_string *data;
166     unsigned short size = 0, bytesize;
167
168     r = read( fd, &size, sizeof size );
169     if (r != sizeof size)
170         return NULL;
171     if (size < sizeof size)
172         return NULL;
173
174     bytesize = size;
175     if (unicode)
176         bytesize *= sizeof(WCHAR);
177     data = malloc(sizeof *data + bytesize);
178     data->size = size;
179     if (unicode)
180         data->str.w[size] = 0;
181     else
182         data->str.a[size] = 0;
183     r = read(fd, &data->str, bytesize);
184     if (r != bytesize)
185     {
186         free(data);
187         return NULL;
188     }
189     return data;
190 }
191
192
193 static int dump_pidl(int fd)
194 {
195     lnk_string *pidl;
196     int i, n = 0, sz = 0;
197
198     pidl = load_pidl(fd);
199     if (!pidl)
200         return -1;
201
202     printf("PIDL\n");
203     printf("----\n\n");
204
205     while(sz<pidl->size)
206     {
207         lnk_string *segment = (lnk_string*) &pidl->str.a[sz];
208
209         if(!segment->size)
210             break;
211         sz+=segment->size;
212         if(sz>pidl->size)
213         {
214             printf("bad pidl\n");
215             break;
216         }
217         n++;
218         printf("segment %d (%2d bytes) : ",n,segment->size);
219         for(i=0; i<segment->size; i++)
220             printf("%02x ",segment->str.a[i]);
221         printf("\n");
222     }
223     printf("\n");
224
225     free(pidl);
226
227     return 0;
228 }
229
230 static void print_unicode_string(const unsigned short *str)
231 {
232     while(*str)
233     {
234         printf("%c", *str);
235         str++;
236     }
237     printf("\n");
238 }
239
240 static int dump_string(int fd, const char *what, int unicode)
241 {
242     lnk_string *data;
243
244     data = load_string(fd, unicode);
245     if (!data)
246         return -1;
247     printf("%s : ", what);
248     if (unicode)
249         print_unicode_string(data->str.w);
250     else
251         printf("%s",data->str.a);
252     printf("\n");
253     free(data);
254     return 0;
255 }
256
257 static int dump_location(int fd)
258 {
259     LOCATION_INFO *loc;
260     char *p;
261
262     loc = load_long_section(fd);
263     if (!loc)
264         return -1;
265     p = (char*)loc;
266
267     printf("Location\n");
268     printf("--------\n\n");
269     printf("Total size    = %ld\n", loc->dwTotalSize);
270     printf("Header size   = %ld\n", loc->dwHeaderSize);
271     printf("Flags         = %08lx\n", loc->dwFlags);
272
273     /* dump out information about the volume the link points to */
274     printf("Volume ofs    = %08lx ", loc->dwVolTableOfs);
275     if (loc->dwVolTableOfs && (loc->dwVolTableOfs<loc->dwTotalSize))
276     {
277         LOCAL_VOLUME_INFO *vol = (LOCAL_VOLUME_INFO *) &p[loc->dwVolTableOfs];
278
279         printf("size %ld  type %ld  serial %08lx  label %ld ",
280                vol->dwSize, vol->dwType, vol->dwVolSerial, vol->dwVolLabelOfs);
281         if(vol->dwVolLabelOfs)
282             printf("(\"%s\")", &p[loc->dwVolTableOfs + vol->dwVolLabelOfs]);
283     }
284     printf("\n");
285
286     /* dump out the path the link points to */
287     printf("LocalPath ofs = %08lx ", loc->dwLocalPathOfs);
288     if( loc->dwLocalPathOfs && (loc->dwLocalPathOfs < loc->dwTotalSize) )
289         printf("(\"%s\")", &p[loc->dwLocalPathOfs]);
290     printf("\n");
291
292     printf("Net Path ofs  = %08lx\n", loc->dwNetworkVolTableOfs);
293     printf("Final Path    = %08lx ", loc->dwFinalPathOfs);
294     if( loc->dwFinalPathOfs && (loc->dwFinalPathOfs < loc->dwTotalSize) )
295         printf("(\"%s\")", &p[loc->dwFinalPathOfs]);
296     printf("\n");
297     printf("\n");
298
299     free(loc);
300
301     return 0;
302 }
303
304 static const unsigned char table_dec85[0x80] = {
305 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
306 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
307 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
308 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
309 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
310 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
311 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
312 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
313 };
314
315 static int base85_to_guid( const unsigned char *str, LPGUID guid )
316 {
317     DWORD i, val = 0, base = 1, *p;
318
319     p = (DWORD*) guid;
320     for( i=0; i<20; i++ )
321     {
322         if( (i%5) == 0 )
323         {
324             val = 0;
325             base = 1;
326         }
327         val += table_dec85[str[i]] * base;
328         if( str[i] >= 0x80 )
329             return 0;
330         if( table_dec85[str[i]] == 0xff )
331             return 0;
332         if( (i%5) == 4 )
333             p[i/5] = val;
334         base *= 85;
335     }
336     return 1;
337 }
338
339 static int dump_advertise_info(int fd, const char *type)
340 {
341     LINK_ADVERTISEINFO *avt;
342
343     avt = load_long_section(fd);
344     if (!avt)
345         return -1;
346
347     printf("Advertise Info\n");
348     printf("--------------\n\n");
349     printf("magic   = %lx\n", avt->magic);
350     printf("%s = %s\n", type, avt->bufA);
351     if (avt->magic == 0xa0000006)
352     {
353         char prod_str[40], comp_str[40], feat_str[40];
354         char *feat, *comp;
355         GUID guid;
356
357         if (base85_to_guid(avt->bufA, &guid))
358             guid_to_string( &guid, prod_str );
359         else
360             strcpy( prod_str, "?" );
361
362         comp = &avt->bufA[20];
363         feat = strchr(comp,'>');
364         if (feat)
365             memcpy( comp_str, comp, feat - comp );
366         else
367             strcpy( prod_str, "?" );
368
369         if (feat && base85_to_guid( &feat[1], &guid ))
370             guid_to_string( &guid, feat_str );
371         else
372             strcpy( prod_str, "?" );
373
374         printf("  product:   %s\n", prod_str);
375         printf("  component: %s\n", comp_str );
376         printf("  feature:   %s\n", feat_str);
377     }
378     printf("\n");
379
380     return 0;
381 }
382
383 static int dump_lnk_fd(int fd)
384 {
385     LINK_HEADER *hdr;
386     char guid[40];
387
388     hdr = load_long_section( fd );
389     if (!hdr)
390         return -1;
391
392     guid_to_string(&hdr->MagicGuid, guid);
393
394     printf("Header\n");
395     printf("------\n\n");
396     printf("Size:    %04lx\n", hdr->dwSize);
397     printf("GUID:    %s\n", guid);
398
399     /* dump out all the flags */
400     printf("Flags:   %04lx ( ", hdr->dwFlags);
401 #define FLAG(x) if(hdr->dwFlags & SCF_##x) printf("%s ",#x);
402     FLAG(PIDL)
403     FLAG(LOCATION)
404     FLAG(DESCRIPTION)
405     FLAG(RELATIVE)
406     FLAG(WORKDIR)
407     FLAG(ARGS)
408     FLAG(CUSTOMICON)
409     FLAG(UNICODE)
410     FLAG(PRODUCT)
411     FLAG(COMPONENT)
412 #undef FLAG
413     printf(")\n");
414
415     printf("Length:  %04lx\n", hdr->dwFileLength);
416     printf("\n");
417
418     if (hdr->dwFlags & SCF_PIDL)
419         dump_pidl(fd);
420     if (hdr->dwFlags & SCF_LOCATION)
421         dump_location(fd);
422     if (hdr->dwFlags & SCF_DESCRIPTION)
423         dump_string(fd, "Description", hdr->dwFlags & SCF_UNICODE);
424     if (hdr->dwFlags & SCF_RELATIVE)
425         dump_string(fd, "Relative path", hdr->dwFlags & SCF_UNICODE);
426     if (hdr->dwFlags & SCF_WORKDIR)
427         dump_string(fd, "Working directory", hdr->dwFlags & SCF_UNICODE);
428     if (hdr->dwFlags & SCF_ARGS)
429         dump_string(fd, "Arguments", hdr->dwFlags & SCF_UNICODE);
430     if (hdr->dwFlags & SCF_CUSTOMICON)
431         dump_string(fd, "Icon path", hdr->dwFlags & SCF_UNICODE);
432     if (hdr->dwFlags & SCF_PRODUCT)
433         dump_advertise_info(fd, "product");
434     if (hdr->dwFlags & SCF_COMPONENT)
435         dump_advertise_info(fd, "msi string");
436
437     return 0;
438 }
439
440 int dump_lnk(const char *emf)
441 {
442     int fd;
443
444     fd = open(emf,O_RDONLY);
445     if (fd<0)
446         return -1;
447     dump_lnk_fd(fd);
448     close(fd);
449     return 0;
450 }