richedit: EN_UPDATE notification is sent on WM_PAINT.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 typedef enum {
42     SLDF_HAS_ID_LIST = 0x00000001,
43     SLDF_HAS_LINK_INFO = 0x00000002,
44     SLDF_HAS_NAME = 0x00000004,
45     SLDF_HAS_RELPATH = 0x00000008,
46     SLDF_HAS_WORKINGDIR = 0x00000010,
47     SLDF_HAS_ARGS = 0x00000020,
48     SLDF_HAS_ICONLOCATION = 0x00000040,
49     SLDF_UNICODE = 0x00000080,
50     SLDF_FORCE_NO_LINKINFO = 0x00000100,
51     SLDF_HAS_EXP_SZ = 0x00000200,
52     SLDF_RUN_IN_SEPARATE = 0x00000400,
53     SLDF_HAS_LOGO3ID = 0x00000800,
54     SLDF_HAS_DARWINID = 0x00001000,
55     SLDF_RUNAS_USER = 0x00002000,
56     SLDF_HAS_EXP_ICON_SZ = 0x00004000,
57     SLDF_NO_PIDL_ALIAS = 0x00008000,
58     SLDF_FORCE_UNCNAME = 0x00010000,
59     SLDF_RUN_WITH_SHIMLAYER = 0x00020000,
60     SLDF_FORCE_NO_LINKTRACK = 0x00040000,
61     SLDF_ENABLE_TARGET_METADATA = 0x00080000,
62     SLDF_DISABLE_KNOWNFOLDER_RELATIVE_TRACKING = 0x00200000,
63     SLDF_RESERVED = 0x80000000,
64 } SHELL_LINK_DATA_FLAGS;
65
66 #define EXP_SZ_LINK_SIG         0xa0000001
67 #define EXP_SPECIAL_FOLDER_SIG  0xa0000005
68 #define EXP_DARWIN_ID_SIG       0xa0000006
69 #define EXP_SZ_ICON_SIG         0xa0000007
70
71 typedef struct tagDATABLOCKHEADER
72 {
73     DWORD cbSize;
74     DWORD dwSignature;
75 } DATABLOCK_HEADER;
76
77 typedef struct _LINK_HEADER
78 {
79     DWORD    dwSize;        /* 0x00 size of the header - 0x4c */
80     GUID     MagicGuid;     /* 0x04 is CLSID_ShellLink */
81     DWORD    dwFlags;       /* 0x14 describes elements following */
82     DWORD    dwFileAttr;    /* 0x18 attributes of the target file */
83     FILETIME Time1;         /* 0x1c */
84     FILETIME Time2;         /* 0x24 */
85     FILETIME Time3;         /* 0x2c */
86     DWORD    dwFileLength;  /* 0x34 File length */
87     DWORD    nIcon;         /* 0x38 icon number */
88     DWORD   fStartup;       /* 0x3c startup type */
89     DWORD   wHotKey;        /* 0x40 hotkey */
90     DWORD   Unknown5;       /* 0x44 */
91     DWORD   Unknown6;       /* 0x48 */
92 } LINK_HEADER, * PLINK_HEADER;
93
94 typedef struct tagLINK_SZ_BLOCK
95 {
96     DWORD size;
97     DWORD magic;
98     CHAR  bufA[MAX_PATH];
99     WCHAR bufW[MAX_PATH];
100 } LINK_SZ_BLOCK;
101
102 typedef struct _LOCATION_INFO
103 {
104     DWORD  dwTotalSize;
105     DWORD  dwHeaderSize;
106     DWORD  dwFlags;
107     DWORD  dwVolTableOfs;
108     DWORD  dwLocalPathOfs;
109     DWORD  dwNetworkVolTableOfs;
110     DWORD  dwFinalPathOfs;
111 } LOCATION_INFO;
112
113 typedef struct _LOCAL_VOLUME_INFO
114 {
115     DWORD dwSize;
116     DWORD dwType;
117     DWORD dwVolSerial;
118     DWORD dwVolLabelOfs;
119 } LOCAL_VOLUME_INFO;
120
121 typedef struct _NETWORK_VOLUME_INFO
122 {
123     DWORD dwSize;
124     DWORD dwUnkown1;
125     DWORD dwShareNameOfs;
126     DWORD dwReserved;
127     DWORD dwUnknown2;
128 } NETWORK_VOLUME_INFO;
129
130 typedef struct
131 {
132     DWORD cbSize;
133     DWORD dwSignature;
134     DWORD idSpecialFolder;
135     DWORD cbOffset;
136 } EXP_SPECIAL_FOLDER;
137
138 typedef struct lnk_string_tag
139 {
140     unsigned short size;
141     union {
142         unsigned short w[1];
143         unsigned char a[1];
144     } str;
145 } lnk_string;
146
147 #include "poppack.h"
148
149 static unsigned offset;
150
151 static const void* fetch_block(void)
152 {
153     const unsigned*     u;
154     const void*         ret;
155
156     if (!(u = PRD(offset, sizeof(*u)))) return 0;
157     if ((ret = PRD(offset, *u)))   offset += *u;
158     return ret;
159 }
160
161 static const lnk_string* fetch_string(int unicode)
162 {
163     const unsigned short*       s;
164     unsigned short              len;
165     const void*                 ret;
166
167     if (!(s = PRD(offset, sizeof(*s)))) return 0;
168     len = *s * (unicode ? sizeof(WCHAR) : sizeof(char));
169     if ((ret = PRD(offset, sizeof(*s) + len)))  offset += sizeof(*s) + len;
170     return ret;
171 }
172
173
174 static int dump_pidl(void)
175 {
176     const lnk_string *pidl;
177     int i, n = 0, sz = 0;
178
179     pidl = fetch_string(FALSE);
180     if (!pidl)
181         return -1;
182
183     printf("PIDL\n");
184     printf("----\n\n");
185
186     while(sz<pidl->size)
187     {
188         const lnk_string *segment = (const lnk_string*) &pidl->str.a[sz];
189
190         if(!segment->size)
191             break;
192         sz+=segment->size;
193         if(sz>pidl->size)
194         {
195             printf("bad pidl\n");
196             break;
197         }
198         n++;
199         printf("segment %d (%2d bytes) : ",n,segment->size);
200         for(i=0; i<segment->size; i++)
201             printf("%02x ",segment->str.a[i]);
202         printf("\n");
203     }
204     printf("\n");
205
206     return 0;
207 }
208
209 static int dump_string(const char *what, int unicode)
210 {
211     const lnk_string *data;
212     unsigned sz;
213
214     data = fetch_string(unicode);
215     if (!data)
216         return -1;
217     printf("%s : ", what);
218     sz = data->size;
219     if (unicode)
220         while (sz) printf("%c", data->str.w[data->size - sz--]);
221     else
222         while (sz) printf("%c", data->str.a[data->size - sz--]);
223     printf("\n");
224
225     return 0;
226 }
227
228 static int dump_location(void)
229 {
230     const LOCATION_INFO *loc;
231     const char *p;
232
233     loc = fetch_block();
234     if (!loc)
235         return -1;
236     p = (const char*)loc;
237
238     printf("Location\n");
239     printf("--------\n\n");
240     printf("Total size    = %d\n", loc->dwTotalSize);
241     printf("Header size   = %d\n", loc->dwHeaderSize);
242     printf("Flags         = %08x\n", loc->dwFlags);
243
244     /* dump information about the local volume the link points to */
245     printf("Local volume ofs    = %08x ", loc->dwVolTableOfs);
246     if (loc->dwVolTableOfs &&
247         loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO) < loc->dwTotalSize)
248     {
249         const LOCAL_VOLUME_INFO *vol = (const LOCAL_VOLUME_INFO *)&p[loc->dwVolTableOfs];
250
251         printf("size %d  type %d  serial %08x  label %d ",
252                vol->dwSize, vol->dwType, vol->dwVolSerial, vol->dwVolLabelOfs);
253         if(vol->dwVolLabelOfs)
254             printf("(\"%s\")", &p[loc->dwVolTableOfs + vol->dwVolLabelOfs]);
255     }
256     printf("\n");
257
258     /* dump information about the network volume the link points to */
259     printf("Network volume ofs    = %08x ", loc->dwNetworkVolTableOfs);
260     if (loc->dwNetworkVolTableOfs &&
261         loc->dwNetworkVolTableOfs + sizeof(NETWORK_VOLUME_INFO) < loc->dwTotalSize)
262     {
263         const NETWORK_VOLUME_INFO *vol = (const NETWORK_VOLUME_INFO *)&p[loc->dwNetworkVolTableOfs];
264
265         printf("size %d name %d ", vol->dwSize, vol->dwShareNameOfs);
266         if(vol->dwShareNameOfs)
267             printf("(\"%s\")", &p[loc->dwNetworkVolTableOfs + vol->dwShareNameOfs]);
268     }
269     printf("\n");
270
271     /* dump out the path the link points to */
272     printf("LocalPath ofs = %08x ", loc->dwLocalPathOfs);
273     if( loc->dwLocalPathOfs && (loc->dwLocalPathOfs < loc->dwTotalSize) )
274         printf("(\"%s\")", &p[loc->dwLocalPathOfs]);
275     printf("\n");
276
277     printf("Net Path ofs  = %08x\n", loc->dwNetworkVolTableOfs);
278     printf("Final Path    = %08x ", loc->dwFinalPathOfs);
279     if( loc->dwFinalPathOfs && (loc->dwFinalPathOfs < loc->dwTotalSize) )
280         printf("(\"%s\")", &p[loc->dwFinalPathOfs]);
281     printf("\n");
282     printf("\n");
283
284     return 0;
285 }
286
287 static const unsigned char table_dec85[0x80] = {
288 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
289 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
290 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
291 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
292 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
293 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
294 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
295 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
296 };
297
298 static int base85_to_guid( const char *str, LPGUID guid )
299 {
300     DWORD i, val = 0, base = 1, *p;
301     unsigned char ch;
302
303     p = (DWORD*) guid;
304     for( i=0; i<20; i++ )
305     {
306         if( (i%5) == 0 )
307         {
308             val = 0;
309             base = 1;
310         }
311         ch = str[i];
312         if( ch >= 0x80 )
313             return 0;
314         val += table_dec85[ch] * base;
315         if( table_dec85[ch] == 0xff )
316             return 0;
317         if( (i%5) == 4 )
318             p[i/5] = val;
319         base *= 85;
320     }
321     return 1;
322 }
323
324 static int dump_special_folder_block(const DATABLOCK_HEADER* bhdr)
325 {
326     const EXP_SPECIAL_FOLDER *sfb = (const EXP_SPECIAL_FOLDER*)bhdr;
327     printf("Special folder block\n");
328     printf("--------------------\n\n");
329     printf("folder  = 0x%04x\n", sfb->idSpecialFolder);
330     printf("offset  = %d\n", sfb->cbOffset);
331     printf("\n");
332     return 0;
333 }
334
335 static int dump_sz_block(const DATABLOCK_HEADER* bhdr, const char* label)
336 {
337     const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
338     printf("String block\n");
339     printf("-----------\n\n");
340     printf("magic   = %x\n", szp->magic);
341     printf("%s    = %s\n", label, szp->bufA);
342     printf("\n");
343     return 0;
344 }
345
346 static int dump_darwin_id(const DATABLOCK_HEADER* bhdr)
347 {
348     const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
349     char comp_str[40];
350     const char *feat, *comp, *prod_str, *feat_str;
351     GUID guid;
352
353     printf("Advertise Info\n");
354     printf("--------------\n\n");
355     printf("msi string = %s\n", szp->bufA);
356
357     if (base85_to_guid(szp->bufA, &guid))
358         prod_str = get_guid_str(&guid);
359     else
360         prod_str = "?";
361
362     comp = &szp->bufA[20];
363     feat = strchr(comp, '>');
364     if (!feat)
365         feat = strchr(comp, '<');
366     if (feat)
367     {
368         memcpy(comp_str, comp, feat - comp);
369         comp_str[feat-comp] = 0;
370     }
371     else
372     {
373         strcpy(comp_str, "?");
374     }
375
376     if (feat && feat[0] == '>' && base85_to_guid( &feat[1], &guid ))
377         feat_str = get_guid_str( &guid );
378     else
379         feat_str = "";
380
381     printf("  product:   %s\n", prod_str);
382     printf("  component: %s\n", comp_str );
383     printf("  feature:   %s\n", feat_str);
384     printf("\n");
385
386     return 0;
387 }
388
389 static int dump_raw_block(const DATABLOCK_HEADER* bhdr)
390 {
391     int data_size;
392
393     printf("Raw Block\n");
394     printf("---------\n\n");
395     printf("size    = %d\n", bhdr->cbSize);
396     printf("magic   = %x\n", bhdr->dwSignature);
397
398     data_size=bhdr->cbSize-sizeof(*bhdr);
399     if (data_size > 0)
400     {
401         int i;
402         const unsigned char *data;
403
404         printf("data    = ");
405         data=(const unsigned char*)bhdr+sizeof(*bhdr);
406         while (data_size > 0)
407         {
408             for (i=0; i < 16; i++)
409             {
410                 if (i < data_size)
411                     printf("%02x ", data[i]);
412                 else
413                     printf("   ");
414             }
415             for (i=0; i < data_size && i < 16; i++)
416                 printf("%c", (data[i] >= 32 && data[i] < 128 ? data[i] : '.'));
417             printf("\n");
418             data_size-=16;
419             if (data_size <= 0)
420                 break;
421             data+=16;
422             printf("          ");
423         }
424     }
425     printf("\n");
426
427     return 1;
428 }
429
430 static const GUID CLSID_ShellLink = {0x00021401L, 0, 0, {0xC0,0,0,0,0,0,0,0x46}};
431
432 enum FileSig get_kind_lnk(void)
433 {
434     const LINK_HEADER*        hdr;
435
436     hdr = PRD(0, sizeof(*hdr));
437     if (hdr && hdr->dwSize == sizeof(LINK_HEADER) &&
438         !memcmp(&hdr->MagicGuid, &CLSID_ShellLink, sizeof(GUID)))
439         return SIG_LNK;
440     return SIG_UNKNOWN;
441 }
442
443 void lnk_dump(void)
444 {
445     const LINK_HEADER*        hdr;
446     const DATABLOCK_HEADER*   bhdr;
447     DWORD dwFlags;
448
449     offset = 0;
450     hdr = fetch_block();
451     if (!hdr)
452         return;
453
454     printf("Header\n");
455     printf("------\n\n");
456     printf("Size:    %04x\n", hdr->dwSize);
457     printf("GUID:    %s\n", get_guid_str(&hdr->MagicGuid));
458
459     printf("FileAttr: %08x\n", hdr->dwFileAttr);
460     printf("FileLength: %08x\n", hdr->dwFileLength);
461     printf("nIcon: %d\n", hdr->nIcon);
462     printf("Startup: %d\n", hdr->fStartup);
463     printf("HotKey: %08x\n", hdr->wHotKey);
464     printf("Unknown5: %08x\n", hdr->Unknown5);
465     printf("Unknown6: %08x\n", hdr->Unknown6);
466
467     /* dump out all the flags */
468     printf("Flags:   %04x ( ", hdr->dwFlags);
469     dwFlags=hdr->dwFlags;
470 #define FLAG(x) do \
471                 { \
472                     if (dwFlags & SLDF_##x) \
473                     { \
474                         printf("%s ", #x); \
475                         dwFlags&=~SLDF_##x; \
476                     } \
477                 } while (0)
478     FLAG(HAS_ID_LIST);
479     FLAG(HAS_LINK_INFO);
480     FLAG(HAS_NAME);
481     FLAG(HAS_RELPATH);
482     FLAG(HAS_WORKINGDIR);
483     FLAG(HAS_ARGS);
484     FLAG(HAS_ICONLOCATION);
485     FLAG(UNICODE);
486     FLAG(FORCE_NO_LINKINFO);
487     FLAG(HAS_EXP_SZ);
488     FLAG(RUN_IN_SEPARATE);
489     FLAG(HAS_LOGO3ID);
490     FLAG(HAS_DARWINID);
491     FLAG(RUNAS_USER);
492     FLAG(HAS_EXP_ICON_SZ);
493     FLAG(NO_PIDL_ALIAS);
494     FLAG(FORCE_UNCNAME);
495     FLAG(RUN_WITH_SHIMLAYER);
496     FLAG(FORCE_NO_LINKTRACK);
497     FLAG(ENABLE_TARGET_METADATA);
498     FLAG(DISABLE_KNOWNFOLDER_RELATIVE_TRACKING);
499     FLAG(RESERVED);
500 #undef FLAG
501     if (dwFlags)
502         printf("+%04x", dwFlags);
503     printf(")\n");
504
505     printf("Length:  %04x\n", hdr->dwFileLength);
506     printf("\n");
507
508     if (hdr->dwFlags & SLDF_HAS_ID_LIST)
509         dump_pidl();
510     if (hdr->dwFlags & SLDF_HAS_LINK_INFO)
511         dump_location();
512     if (hdr->dwFlags & SLDF_HAS_NAME)
513         dump_string("Description", hdr->dwFlags & SLDF_UNICODE);
514     if (hdr->dwFlags & SLDF_HAS_RELPATH)
515         dump_string("Relative path", hdr->dwFlags & SLDF_UNICODE);
516     if (hdr->dwFlags & SLDF_HAS_WORKINGDIR)
517         dump_string("Working directory", hdr->dwFlags & SLDF_UNICODE);
518     if (hdr->dwFlags & SLDF_HAS_ARGS)
519         dump_string("Arguments", hdr->dwFlags & SLDF_UNICODE);
520     if (hdr->dwFlags & SLDF_HAS_ICONLOCATION)
521         dump_string("Icon path", hdr->dwFlags & SLDF_UNICODE);
522
523     bhdr=fetch_block();
524     while (bhdr)
525     {
526         if (!bhdr->cbSize)
527             break;
528         switch (bhdr->dwSignature)
529         {
530         case EXP_SZ_LINK_SIG:
531             dump_sz_block(bhdr, "exp.link");
532             break;
533         case EXP_SPECIAL_FOLDER_SIG:
534             dump_special_folder_block(bhdr);
535             break;
536         case EXP_SZ_ICON_SIG:
537             dump_sz_block(bhdr, "icon");
538             break;
539         case EXP_DARWIN_ID_SIG:
540             dump_darwin_id(bhdr);
541             break;
542         default:
543             dump_raw_block(bhdr);
544         }
545         bhdr=fetch_block();
546     }
547 }