msvcp: Fixed complex division.
[wine.git] / tools / winedump / lnk.c
blob1a8917337dd2ae2c2bb021f6d0d742c5405021f3
1 /*
2 * Dump a shortcut (lnk) file
4 * Copyright 2005 Mike McCormack
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
23 #include "winedump.h"
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>
36 #include "windef.h"
37 #include "winbase.h"
39 #include "pshpack1.h"
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;
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 #define EXP_PROPERTYSTORAGE_SIG 0xa0000009
72 typedef struct tagDATABLOCKHEADER
74 DWORD cbSize;
75 DWORD dwSignature;
76 } DATABLOCK_HEADER;
78 typedef struct _LINK_HEADER
80 DWORD dwSize; /* 0x00 size of the header - 0x4c */
81 GUID MagicGuid; /* 0x04 is CLSID_ShellLink */
82 DWORD dwFlags; /* 0x14 describes elements following */
83 DWORD dwFileAttr; /* 0x18 attributes of the target file */
84 FILETIME Time1; /* 0x1c */
85 FILETIME Time2; /* 0x24 */
86 FILETIME Time3; /* 0x2c */
87 DWORD dwFileLength; /* 0x34 File length */
88 DWORD nIcon; /* 0x38 icon number */
89 DWORD fStartup; /* 0x3c startup type */
90 DWORD wHotKey; /* 0x40 hotkey */
91 DWORD Unknown5; /* 0x44 */
92 DWORD Unknown6; /* 0x48 */
93 } LINK_HEADER, * PLINK_HEADER;
95 typedef struct tagLINK_SZ_BLOCK
97 DWORD size;
98 DWORD magic;
99 CHAR bufA[MAX_PATH];
100 WCHAR bufW[MAX_PATH];
101 } LINK_SZ_BLOCK;
103 typedef struct tagLINK_PROPERTYSTORAGE_GUID
105 DWORD size;
106 DWORD magic;
107 GUID fmtid;
108 } LINK_PROPERTYSTORAGE_GUID;
110 typedef struct tagLINK_PROPERTYSTORAGE_VALUE
112 DWORD size;
113 DWORD pid;
114 BYTE unknown8;
115 DWORD vt;
116 DWORD unknown25;
117 } LINK_PROPERTYSTORAGE_VALUE;
119 typedef struct _LOCATION_INFO
121 DWORD dwTotalSize;
122 DWORD dwHeaderSize;
123 DWORD dwFlags;
124 DWORD dwVolTableOfs;
125 DWORD dwLocalPathOfs;
126 DWORD dwNetworkVolTableOfs;
127 DWORD dwFinalPathOfs;
128 } LOCATION_INFO;
130 typedef struct _LOCAL_VOLUME_INFO
132 DWORD dwSize;
133 DWORD dwType;
134 DWORD dwVolSerial;
135 DWORD dwVolLabelOfs;
136 } LOCAL_VOLUME_INFO;
138 typedef struct _NETWORK_VOLUME_INFO
140 DWORD dwSize;
141 DWORD dwUnknown1;
142 DWORD dwShareNameOfs;
143 DWORD dwReserved;
144 DWORD dwUnknown2;
145 } NETWORK_VOLUME_INFO;
147 typedef struct
149 DWORD cbSize;
150 DWORD dwSignature;
151 DWORD idSpecialFolder;
152 DWORD cbOffset;
153 } EXP_SPECIAL_FOLDER;
155 typedef struct lnk_string_tag
157 unsigned short size;
158 union {
159 unsigned short w[1];
160 unsigned char a[1];
161 } str;
162 } lnk_string;
164 #include "poppack.h"
166 static unsigned offset;
168 static const void* fetch_block(void)
170 const unsigned* u;
171 const void* ret;
173 if (!(u = PRD(offset, sizeof(*u)))) return 0;
174 if ((ret = PRD(offset, *u))) offset += *u;
175 return ret;
178 static const lnk_string* fetch_string(int unicode)
180 const unsigned short* s;
181 unsigned short len;
182 const void* ret;
184 if (!(s = PRD(offset, sizeof(*s)))) return 0;
185 len = *s * (unicode ? sizeof(WCHAR) : sizeof(char));
186 if ((ret = PRD(offset, sizeof(*s) + len))) offset += sizeof(*s) + len;
187 return ret;
191 static int dump_pidl(void)
193 const lnk_string *pidl;
194 int i, n = 0, sz = 0;
196 pidl = fetch_string(FALSE);
197 if (!pidl)
198 return -1;
200 printf("PIDL\n");
201 printf("----\n\n");
203 while(sz<pidl->size)
205 const lnk_string *segment = (const lnk_string*) &pidl->str.a[sz];
207 if(!segment->size)
208 break;
209 sz+=segment->size;
210 if(sz>pidl->size)
212 printf("bad pidl\n");
213 break;
215 n++;
216 printf("segment %d (%2d bytes) : ",n,segment->size);
217 for(i=0; i<segment->size; i++)
218 printf("%02x ",segment->str.a[i]);
219 printf("\n");
221 printf("\n");
223 return 0;
226 static int dump_string(const char *what, int unicode)
228 const lnk_string *data;
229 unsigned sz;
231 data = fetch_string(unicode);
232 if (!data)
233 return -1;
234 printf("%s : ", what);
235 sz = data->size;
236 if (unicode)
237 while (sz) printf("%c", data->str.w[data->size - sz--]);
238 else
239 while (sz) printf("%c", data->str.a[data->size - sz--]);
240 printf("\n");
242 return 0;
245 static int dump_location(void)
247 const LOCATION_INFO *loc;
248 const char *p;
250 loc = fetch_block();
251 if (!loc)
252 return -1;
253 p = (const char*)loc;
255 printf("Location\n");
256 printf("--------\n\n");
257 printf("Total size = %d\n", loc->dwTotalSize);
258 printf("Header size = %d\n", loc->dwHeaderSize);
259 printf("Flags = %08x\n", loc->dwFlags);
261 /* dump information about the local volume the link points to */
262 printf("Local volume ofs = %08x ", loc->dwVolTableOfs);
263 if (loc->dwVolTableOfs &&
264 loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO) < loc->dwTotalSize)
266 const LOCAL_VOLUME_INFO *vol = (const LOCAL_VOLUME_INFO *)&p[loc->dwVolTableOfs];
268 printf("size %d type %d serial %08x label %d ",
269 vol->dwSize, vol->dwType, vol->dwVolSerial, vol->dwVolLabelOfs);
270 if(vol->dwVolLabelOfs)
271 printf("(\"%s\")", &p[loc->dwVolTableOfs + vol->dwVolLabelOfs]);
273 printf("\n");
275 /* dump information about the network volume the link points to */
276 printf("Network volume ofs = %08x ", loc->dwNetworkVolTableOfs);
277 if (loc->dwNetworkVolTableOfs &&
278 loc->dwNetworkVolTableOfs + sizeof(NETWORK_VOLUME_INFO) < loc->dwTotalSize)
280 const NETWORK_VOLUME_INFO *vol = (const NETWORK_VOLUME_INFO *)&p[loc->dwNetworkVolTableOfs];
282 printf("size %d name %d ", vol->dwSize, vol->dwShareNameOfs);
283 if(vol->dwShareNameOfs)
284 printf("(\"%s\")", &p[loc->dwNetworkVolTableOfs + vol->dwShareNameOfs]);
286 printf("\n");
288 /* dump out the path the link points to */
289 printf("LocalPath ofs = %08x ", loc->dwLocalPathOfs);
290 if( loc->dwLocalPathOfs && (loc->dwLocalPathOfs < loc->dwTotalSize) )
291 printf("(\"%s\")", &p[loc->dwLocalPathOfs]);
292 printf("\n");
294 printf("Net Path ofs = %08x\n", loc->dwNetworkVolTableOfs);
295 printf("Final Path = %08x ", loc->dwFinalPathOfs);
296 if( loc->dwFinalPathOfs && (loc->dwFinalPathOfs < loc->dwTotalSize) )
297 printf("(\"%s\")", &p[loc->dwFinalPathOfs]);
298 printf("\n");
299 printf("\n");
301 return 0;
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,
315 static int base85_to_guid( const char *str, LPGUID guid )
317 DWORD i, val = 0, base = 1, *p;
318 unsigned char ch;
320 p = (DWORD*) guid;
321 for( i=0; i<20; i++ )
323 if( (i%5) == 0 )
325 val = 0;
326 base = 1;
328 ch = str[i];
329 if( ch >= 0x80 )
330 return 0;
331 val += table_dec85[ch] * base;
332 if( table_dec85[ch] == 0xff )
333 return 0;
334 if( (i%5) == 4 )
335 p[i/5] = val;
336 base *= 85;
338 return 1;
341 static int dump_special_folder_block(const DATABLOCK_HEADER* bhdr)
343 const EXP_SPECIAL_FOLDER *sfb = (const EXP_SPECIAL_FOLDER*)bhdr;
344 printf("Special folder block\n");
345 printf("--------------------\n\n");
346 printf("folder = 0x%04x\n", sfb->idSpecialFolder);
347 printf("offset = %d\n", sfb->cbOffset);
348 printf("\n");
349 return 0;
352 static int dump_sz_block(const DATABLOCK_HEADER* bhdr, const char* label)
354 const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
355 printf("String block\n");
356 printf("-----------\n\n");
357 printf("magic = %x\n", szp->magic);
358 printf("%s = %s\n", label, szp->bufA);
359 printf("\n");
360 return 0;
363 static int dump_darwin_id(const DATABLOCK_HEADER* bhdr)
365 const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
366 char comp_str[40];
367 const char *feat, *comp, *prod_str, *feat_str;
368 GUID guid;
370 printf("Advertise Info\n");
371 printf("--------------\n\n");
372 printf("msi string = %s\n", szp->bufA);
374 if (base85_to_guid(szp->bufA, &guid))
375 prod_str = get_guid_str(&guid);
376 else
377 prod_str = "?";
379 comp = &szp->bufA[20];
380 feat = strchr(comp, '>');
381 if (!feat)
382 feat = strchr(comp, '<');
383 if (feat)
385 memcpy(comp_str, comp, feat - comp);
386 comp_str[feat-comp] = 0;
388 else
390 strcpy(comp_str, "?");
393 if (feat && feat[0] == '>' && base85_to_guid( &feat[1], &guid ))
394 feat_str = get_guid_str( &guid );
395 else
396 feat_str = "";
398 printf(" product: %s\n", prod_str);
399 printf(" component: %s\n", comp_str );
400 printf(" feature: %s\n", feat_str);
401 printf("\n");
403 return 0;
406 static void dump_property_storage_value(const LINK_PROPERTYSTORAGE_VALUE *lnk_value_hdr,
407 DWORD data_size)
409 int got_terminator = 0, i, value_size;
410 const unsigned char *value;
412 while (data_size >= sizeof(DWORD))
414 if (!lnk_value_hdr->size)
416 got_terminator = 1;
417 break;
420 if (lnk_value_hdr->size > data_size || lnk_value_hdr->size < sizeof(*lnk_value_hdr))
422 printf(" size: %d (invald)\n", lnk_value_hdr->size);
423 return;
426 printf(" pid: %d\n", lnk_value_hdr->pid);
427 printf(" unknown8: %d\n", lnk_value_hdr->unknown8);
428 printf(" vartype: %d\n", lnk_value_hdr->vt);
429 printf(" unknown25: %d\n", lnk_value_hdr->unknown25);
431 value_size = lnk_value_hdr->size - sizeof(*lnk_value_hdr);
432 value = (const unsigned char*)(lnk_value_hdr+1);
434 printf(" value (%2d bytes) : ",value_size);
435 for(i=0; i<value_size; i++)
436 printf("%02x ",value[i]);
437 printf("\n\n");
439 data_size -= lnk_value_hdr->size;
440 lnk_value_hdr = (void*)((char*)lnk_value_hdr + lnk_value_hdr->size);
443 if (!got_terminator)
444 printf(" missing terminator!\n");
447 static int dump_property_storage(const DATABLOCK_HEADER* bhdr)
449 int data_size;
450 const LINK_PROPERTYSTORAGE_GUID *lnk_guid_hdr;
451 int got_terminator = 0;
453 printf("Property Storage\n");
454 printf("--------------\n\n");
456 data_size=bhdr->cbSize-sizeof(*bhdr);
458 lnk_guid_hdr=(void*)((const char*)bhdr+sizeof(*bhdr));
460 while (data_size >= sizeof(DWORD))
462 if (!lnk_guid_hdr->size)
464 got_terminator = 1;
465 break;
468 if (lnk_guid_hdr->size > data_size || lnk_guid_hdr->size < sizeof(*lnk_guid_hdr))
470 printf("size: %d (invald)\n", lnk_guid_hdr->size);
471 return 1;
474 if (lnk_guid_hdr->magic != 0x53505331)
475 printf("magic: %x\n", lnk_guid_hdr->magic);
477 printf("fmtid: %s\n", get_guid_str(&lnk_guid_hdr->fmtid));
479 dump_property_storage_value((void*)(lnk_guid_hdr + 1), lnk_guid_hdr->size - sizeof(*lnk_guid_hdr));
481 data_size -= lnk_guid_hdr->size;
483 lnk_guid_hdr = (void*)((char*)lnk_guid_hdr + lnk_guid_hdr->size);
486 if (!got_terminator)
487 printf("missing terminator!\n");
489 printf("\n");
491 return 0;
494 static int dump_raw_block(const DATABLOCK_HEADER* bhdr)
496 int data_size;
498 printf("Raw Block\n");
499 printf("---------\n\n");
500 printf("size = %d\n", bhdr->cbSize);
501 printf("magic = %x\n", bhdr->dwSignature);
503 data_size=bhdr->cbSize-sizeof(*bhdr);
504 if (data_size > 0)
506 int i;
507 const unsigned char *data;
509 printf("data = ");
510 data=(const unsigned char*)bhdr+sizeof(*bhdr);
511 while (data_size > 0)
513 for (i=0; i < 16; i++)
515 if (i < data_size)
516 printf("%02x ", data[i]);
517 else
518 printf(" ");
520 for (i=0; i < data_size && i < 16; i++)
521 printf("%c", (data[i] >= 32 && data[i] < 128 ? data[i] : '.'));
522 printf("\n");
523 data_size-=16;
524 if (data_size <= 0)
525 break;
526 data+=16;
527 printf(" ");
530 printf("\n");
532 return 1;
535 static const GUID CLSID_ShellLink = {0x00021401L, 0, 0, {0xC0,0,0,0,0,0,0,0x46}};
537 enum FileSig get_kind_lnk(void)
539 const LINK_HEADER* hdr;
541 hdr = PRD(0, sizeof(*hdr));
542 if (hdr && hdr->dwSize == sizeof(LINK_HEADER) &&
543 !memcmp(&hdr->MagicGuid, &CLSID_ShellLink, sizeof(GUID)))
544 return SIG_LNK;
545 return SIG_UNKNOWN;
548 void lnk_dump(void)
550 const LINK_HEADER* hdr;
551 const DATABLOCK_HEADER* bhdr;
552 DWORD dwFlags;
554 offset = 0;
555 hdr = fetch_block();
556 if (!hdr)
557 return;
559 printf("Header\n");
560 printf("------\n\n");
561 printf("Size: %04x\n", hdr->dwSize);
562 printf("GUID: %s\n", get_guid_str(&hdr->MagicGuid));
564 printf("FileAttr: %08x\n", hdr->dwFileAttr);
565 printf("FileLength: %08x\n", hdr->dwFileLength);
566 printf("nIcon: %d\n", hdr->nIcon);
567 printf("Startup: %d\n", hdr->fStartup);
568 printf("HotKey: %08x\n", hdr->wHotKey);
569 printf("Unknown5: %08x\n", hdr->Unknown5);
570 printf("Unknown6: %08x\n", hdr->Unknown6);
572 /* dump out all the flags */
573 printf("Flags: %04x ( ", hdr->dwFlags);
574 dwFlags=hdr->dwFlags;
575 #define FLAG(x) do \
577 if (dwFlags & SLDF_##x) \
579 printf("%s ", #x); \
580 dwFlags&=~SLDF_##x; \
582 } while (0)
583 FLAG(HAS_ID_LIST);
584 FLAG(HAS_LINK_INFO);
585 FLAG(HAS_NAME);
586 FLAG(HAS_RELPATH);
587 FLAG(HAS_WORKINGDIR);
588 FLAG(HAS_ARGS);
589 FLAG(HAS_ICONLOCATION);
590 FLAG(UNICODE);
591 FLAG(FORCE_NO_LINKINFO);
592 FLAG(HAS_EXP_SZ);
593 FLAG(RUN_IN_SEPARATE);
594 FLAG(HAS_LOGO3ID);
595 FLAG(HAS_DARWINID);
596 FLAG(RUNAS_USER);
597 FLAG(HAS_EXP_ICON_SZ);
598 FLAG(NO_PIDL_ALIAS);
599 FLAG(FORCE_UNCNAME);
600 FLAG(RUN_WITH_SHIMLAYER);
601 FLAG(FORCE_NO_LINKTRACK);
602 FLAG(ENABLE_TARGET_METADATA);
603 FLAG(DISABLE_KNOWNFOLDER_RELATIVE_TRACKING);
604 FLAG(RESERVED);
605 #undef FLAG
606 if (dwFlags)
607 printf("+%04x", dwFlags);
608 printf(")\n");
610 printf("Length: %04x\n", hdr->dwFileLength);
611 printf("\n");
613 if (hdr->dwFlags & SLDF_HAS_ID_LIST)
614 dump_pidl();
615 if (hdr->dwFlags & SLDF_HAS_LINK_INFO)
616 dump_location();
617 if (hdr->dwFlags & SLDF_HAS_NAME)
618 dump_string("Description", hdr->dwFlags & SLDF_UNICODE);
619 if (hdr->dwFlags & SLDF_HAS_RELPATH)
620 dump_string("Relative path", hdr->dwFlags & SLDF_UNICODE);
621 if (hdr->dwFlags & SLDF_HAS_WORKINGDIR)
622 dump_string("Working directory", hdr->dwFlags & SLDF_UNICODE);
623 if (hdr->dwFlags & SLDF_HAS_ARGS)
624 dump_string("Arguments", hdr->dwFlags & SLDF_UNICODE);
625 if (hdr->dwFlags & SLDF_HAS_ICONLOCATION)
626 dump_string("Icon path", hdr->dwFlags & SLDF_UNICODE);
628 bhdr=fetch_block();
629 while (bhdr)
631 if (!bhdr->cbSize)
632 break;
633 switch (bhdr->dwSignature)
635 case EXP_SZ_LINK_SIG:
636 dump_sz_block(bhdr, "exp.link");
637 break;
638 case EXP_SPECIAL_FOLDER_SIG:
639 dump_special_folder_block(bhdr);
640 break;
641 case EXP_SZ_ICON_SIG:
642 dump_sz_block(bhdr, "icon");
643 break;
644 case EXP_DARWIN_ID_SIG:
645 dump_darwin_id(bhdr);
646 break;
647 case EXP_PROPERTYSTORAGE_SIG:
648 dump_property_storage(bhdr);
649 break;
650 default:
651 dump_raw_block(bhdr);
653 bhdr=fetch_block();