Add dumping of lnk files.
[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 <stdio.h>
22 #include <malloc.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <stdarg.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31
32 #include "pshpack1.h"
33
34 #define SCF_PIDL 1
35 #define SCF_LOCATION 2
36 #define SCF_DESCRIPTION 4
37 #define SCF_RELATIVE 8
38 #define SCF_WORKDIR 0x10
39 #define SCF_ARGS 0x20
40 #define SCF_CUSTOMICON 0x40
41 #define SCF_UNICODE 0x80
42 #define SCF_PRODUCT 0x800
43 #define SCF_COMPONENT 0x1000
44
45 typedef struct _LINK_HEADER
46 {
47     DWORD    dwSize;        /* 0x00 size of the header - 0x4c */
48     GUID     MagicGuid;     /* 0x04 is CLSID_ShellLink */
49     DWORD    dwFlags;       /* 0x14 describes elements following */
50     DWORD    dwFileAttr;    /* 0x18 attributes of the target file */
51     FILETIME Time1;         /* 0x1c */
52     FILETIME Time2;         /* 0x24 */
53     FILETIME Time3;         /* 0x2c */
54     DWORD    dwFileLength;  /* 0x34 File length */
55     DWORD    nIcon;         /* 0x38 icon number */
56     DWORD   fStartup;       /* 0x3c startup type */
57     DWORD   wHotKey;        /* 0x40 hotkey */
58     DWORD   Unknown5;       /* 0x44 */
59     DWORD   Unknown6;       /* 0x48 */
60 } LINK_HEADER, * PLINK_HEADER;
61
62 typedef struct tagLINK_ADVERTISEINFO
63 {
64     DWORD size;
65     DWORD magic;
66     CHAR  bufA[MAX_PATH];
67     WCHAR bufW[MAX_PATH];
68 } LINK_ADVERTISEINFO;
69
70 typedef struct _LOCATION_INFO
71 {
72     DWORD  dwTotalSize;
73     DWORD  dwHeaderSize;
74     DWORD  dwFlags;
75     DWORD  dwVolTableOfs;
76     DWORD  dwLocalPathOfs;
77     DWORD  dwNetworkVolTableOfs;
78     DWORD  dwFinalPathOfs;
79 } LOCATION_INFO;
80
81 typedef struct lnk_string_tag {
82     unsigned short size;
83     union {
84         unsigned short w[1];
85         unsigned char a[1];
86     } str;
87 } lnk_string;
88
89 #include "poppack.h"
90
91 static void guid_to_string(LPGUID guid, char *str)
92 {
93     sprintf(str, "{%08lx-%04x-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}",
94             guid->Data1, guid->Data2, guid->Data3,
95             guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
96             guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
97 }
98
99 /* the size is a short integer */
100 static void* load_pidl(int fd)
101 {
102     int r;
103     unsigned char *data;
104     unsigned short size = 0;
105
106     r = read( fd, &size, sizeof size );
107     if (r != sizeof size)
108         return NULL;
109     if (size<sizeof size)
110         return NULL;
111
112     data = malloc(size + sizeof size);
113     memcpy(data, &size, sizeof size);
114     r = read( fd, data + sizeof size, size );
115     if (r != size)
116     {
117         free(data);
118         return NULL;
119     }
120     return (void*)data;
121 }
122
123 /* size is an integer */
124 static void* load_long_section(int fd)
125 {
126     int r, size = 0;
127     unsigned char *data;
128
129     r = read( fd, &size, sizeof size );
130     if (r != sizeof size)
131         return NULL;
132     if (size<sizeof size)
133         return NULL;
134
135     data = malloc(size);
136     memcpy(data, &size, sizeof size);
137     r = read( fd, data + sizeof size, size - sizeof size);
138     if (r != (size - sizeof size))
139     {
140         free(data);
141         return NULL;
142     }
143     return (void*)data;
144 }
145
146 /* the size is a character count in a short integer */
147 static lnk_string* load_string(int fd, int unicode)
148 {
149     int r;
150     lnk_string *data;
151     unsigned short size = 0, bytesize;
152
153     r = read( fd, &size, sizeof size );
154     if (r != sizeof size)
155         return NULL;
156     if (size < sizeof size)
157         return NULL;
158
159     bytesize = size;
160     if (unicode)
161         bytesize *= sizeof(WCHAR);
162     data = malloc(sizeof *data + bytesize);
163     data->size = size;
164     if (unicode)
165         data->str.w[size] = 0;
166     else
167         data->str.a[size] = 0;
168     r = read(fd, &data->str, bytesize);
169     if (r != bytesize)
170     {
171         free(data);
172         return NULL;
173     }
174     return data;
175 }
176
177
178 static int dump_pidl(int fd)
179 {
180     void *pidl;
181
182     pidl = load_pidl(fd);
183     if (!pidl)
184         return -1;
185
186     printf("PIDL\n");
187     printf("----\n\n");
188
189     free(pidl);
190
191     return 0;
192 }
193
194 static void print_unicode_string(unsigned short *str)
195 {
196     while(*str)
197     {
198         printf("%c", *str);
199         str++;
200     }
201     printf("\n");
202 }
203
204 static int dump_string(int fd, char *what, int unicode)
205 {
206     lnk_string *data;
207
208     data = load_string(fd, unicode);
209     if (!data)
210         return -1;
211     printf("%s : ", what);
212     if (unicode)
213         print_unicode_string(data->str.w);
214     else
215         printf("%s",data->str.a);
216     printf("\n");
217     free(data);
218     return 0;
219 }
220
221 static int dump_location(int fd)
222 {
223     LOCATION_INFO *loc;
224
225     loc = load_long_section(fd);
226     if (!loc)
227         return -1;
228
229     printf("Location\n");
230     printf("--------\n\n");
231     printf("Total size    = %ld\n", loc->dwTotalSize);
232     printf("Header size   = %ld\n", loc->dwHeaderSize);
233     printf("Flags         = %08lx\n", loc->dwFlags);
234     printf("Volume ofs    = %08lx\n", loc->dwVolTableOfs);
235     printf("LocalPath ofs = %08lx\n", loc->dwLocalPathOfs);
236     printf("Net Path ofs  = %08lx\n", loc->dwNetworkVolTableOfs);
237     printf("Final Path    = %08lx\n", loc->dwFinalPathOfs);
238     printf("\n");
239
240     free(loc);
241
242     return 0;
243 }
244
245 static int dump_advertise_info(int fd, char *type)
246 {
247     LINK_ADVERTISEINFO *avt;
248
249     avt = load_long_section(fd);
250     if (!avt)
251         return -1;
252
253     printf("Advertise Info\n");
254     printf("--------------\n\n");
255     printf("magic   = %lx\n", avt->magic);
256     printf("%s = %s\n", type, avt->bufA);
257     printf("\n");
258
259     return 0;
260 }
261
262 static int dump_lnk_fd(int fd)
263 {
264     LINK_HEADER *hdr;
265     char guid[40];
266
267     hdr = load_long_section( fd );
268     if (!hdr)
269         return -1;
270
271     guid_to_string(&hdr->MagicGuid, guid);
272
273     printf("Header\n");
274     printf("------\n\n");
275     printf("Size:    %04lx\n", hdr->dwSize);
276     printf("GUID:    %s\n", guid);
277     printf("Flags:   %04lx\n", hdr->dwFlags);
278     printf("Length:  %04lx\n", hdr->dwFileLength);
279     printf("\n");
280
281     if (hdr->dwFlags & SCF_PIDL)
282         dump_pidl(fd);
283     if (hdr->dwFlags & SCF_LOCATION)
284         dump_location(fd);
285     if (hdr->dwFlags & SCF_DESCRIPTION)
286         dump_string(fd, "Description", hdr->dwFlags & SCF_UNICODE);
287     if (hdr->dwFlags & SCF_RELATIVE)
288         dump_string(fd, "Relative path", hdr->dwFlags & SCF_UNICODE);
289     if (hdr->dwFlags & SCF_WORKDIR)
290         dump_string(fd, "Working directory", hdr->dwFlags & SCF_UNICODE);
291     if (hdr->dwFlags & SCF_ARGS)
292         dump_string(fd, "Arguments", hdr->dwFlags & SCF_UNICODE);
293     if (hdr->dwFlags & SCF_CUSTOMICON)
294         dump_string(fd, "Icon path", hdr->dwFlags & SCF_UNICODE);
295     if (hdr->dwFlags & SCF_PRODUCT)
296         dump_advertise_info(fd, "product");
297     if (hdr->dwFlags & SCF_COMPONENT)
298         dump_advertise_info(fd, "component");
299
300     return 0;
301 }
302
303 int dump_lnk(const char *emf)
304 {
305     int fd;
306
307     fd = open(emf,O_RDONLY);
308     if (fd<0)
309         return -1;
310     dump_lnk_fd(fd);
311     close(fd);
312     return 0;
313 }