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
35 SLDF_HAS_ID_LIST
= 0x00000001,
36 SLDF_HAS_LINK_INFO
= 0x00000002,
37 SLDF_HAS_NAME
= 0x00000004,
38 SLDF_HAS_RELPATH
= 0x00000008,
39 SLDF_HAS_WORKINGDIR
= 0x00000010,
40 SLDF_HAS_ARGS
= 0x00000020,
41 SLDF_HAS_ICONLOCATION
= 0x00000040,
42 SLDF_UNICODE
= 0x00000080,
43 SLDF_FORCE_NO_LINKINFO
= 0x00000100,
44 SLDF_HAS_EXP_SZ
= 0x00000200,
45 SLDF_RUN_IN_SEPARATE
= 0x00000400,
46 SLDF_HAS_LOGO3ID
= 0x00000800,
47 SLDF_HAS_DARWINID
= 0x00001000,
48 SLDF_RUNAS_USER
= 0x00002000,
49 SLDF_HAS_EXP_ICON_SZ
= 0x00004000,
50 SLDF_NO_PIDL_ALIAS
= 0x00008000,
51 SLDF_FORCE_UNCNAME
= 0x00010000,
52 SLDF_RUN_WITH_SHIMLAYER
= 0x00020000,
53 SLDF_FORCE_NO_LINKTRACK
= 0x00040000,
54 SLDF_ENABLE_TARGET_METADATA
= 0x00080000,
55 SLDF_DISABLE_KNOWNFOLDER_RELATIVE_TRACKING
= 0x00200000,
56 SLDF_RESERVED
= 0x80000000,
57 } SHELL_LINK_DATA_FLAGS
;
59 #define EXP_SZ_LINK_SIG 0xa0000001
60 #define EXP_SPECIAL_FOLDER_SIG 0xa0000005
61 #define EXP_DARWIN_ID_SIG 0xa0000006
62 #define EXP_SZ_ICON_SIG 0xa0000007
63 #define EXP_PROPERTYSTORAGE_SIG 0xa0000009
65 typedef struct tagDATABLOCKHEADER
71 typedef struct _LINK_HEADER
73 UINT dwSize
; /* 0x00 size of the header - 0x4c */
74 GUID MagicGuid
; /* 0x04 is CLSID_ShellLink */
75 UINT dwFlags
; /* 0x14 describes elements following */
76 UINT dwFileAttr
; /* 0x18 attributes of the target file */
77 FILETIME Time1
; /* 0x1c */
78 FILETIME Time2
; /* 0x24 */
79 FILETIME Time3
; /* 0x2c */
80 UINT dwFileLength
; /* 0x34 File length */
81 UINT nIcon
; /* 0x38 icon number */
82 UINT fStartup
; /* 0x3c startup type */
83 UINT wHotKey
; /* 0x40 hotkey */
84 UINT Unknown5
; /* 0x44 */
85 UINT Unknown6
; /* 0x48 */
86 } LINK_HEADER
, * PLINK_HEADER
;
88 typedef struct tagLINK_SZ_BLOCK
96 typedef struct tagLINK_PROPERTYSTORAGE_GUID
101 } LINK_PROPERTYSTORAGE_GUID
;
103 typedef struct tagLINK_PROPERTYSTORAGE_VALUE
110 } LINK_PROPERTYSTORAGE_VALUE
;
112 typedef struct _LOCATION_INFO
119 UINT dwNetworkVolTableOfs
;
123 typedef struct _LOCAL_VOLUME_INFO
131 typedef struct _NETWORK_VOLUME_INFO
138 } NETWORK_VOLUME_INFO
;
144 UINT idSpecialFolder
;
146 } EXP_SPECIAL_FOLDER
;
148 typedef struct lnk_string_tag
159 static unsigned offset
;
161 static const void* fetch_block(void)
166 if (!(u
= PRD(offset
, sizeof(*u
)))) return 0;
167 if ((ret
= PRD(offset
, *u
))) offset
+= *u
;
171 static const lnk_string
* fetch_string(int unicode
)
173 const unsigned short* s
;
177 if (!(s
= PRD(offset
, sizeof(*s
)))) return 0;
178 len
= *s
* (unicode
? sizeof(WCHAR
) : sizeof(char));
179 if ((ret
= PRD(offset
, sizeof(*s
) + len
))) offset
+= sizeof(*s
) + len
;
184 static void dump_pidl(void)
186 const lnk_string
*pidl
;
187 int i
, n
= 0, sz
= 0;
189 pidl
= fetch_string(FALSE
);
198 const lnk_string
*segment
= (const lnk_string
*) &pidl
->str
.a
[sz
];
205 printf("bad pidl\n");
209 printf("segment %d (%2d bytes) : ",n
,segment
->size
);
210 for(i
=0; i
<segment
->size
; i
++)
211 printf("%02x ",segment
->str
.a
[i
]);
217 static void dump_string(const char *what
, int unicode
)
219 const lnk_string
*data
;
222 data
= fetch_string(unicode
);
225 printf("%s : ", what
);
228 while (sz
) printf("%c", data
->str
.w
[data
->size
- sz
--]);
230 while (sz
) printf("%c", data
->str
.a
[data
->size
- sz
--]);
234 static void dump_location(void)
236 const LOCATION_INFO
*loc
;
242 p
= (const char*)loc
;
244 printf("Location\n");
245 printf("--------\n\n");
246 printf("Total size = %d\n", loc
->dwTotalSize
);
247 printf("Header size = %d\n", loc
->dwHeaderSize
);
248 printf("Flags = %08x\n", loc
->dwFlags
);
250 /* dump information about the local volume the link points to */
251 printf("Local volume ofs = %08x ", loc
->dwVolTableOfs
);
252 if (loc
->dwVolTableOfs
&&
253 loc
->dwVolTableOfs
+ sizeof(LOCAL_VOLUME_INFO
) < loc
->dwTotalSize
)
255 const LOCAL_VOLUME_INFO
*vol
= (const LOCAL_VOLUME_INFO
*)&p
[loc
->dwVolTableOfs
];
257 printf("size %d type %d serial %08x label %d ",
258 vol
->dwSize
, vol
->dwType
, vol
->dwVolSerial
, vol
->dwVolLabelOfs
);
259 if(vol
->dwVolLabelOfs
)
260 printf("(\"%s\")", &p
[loc
->dwVolTableOfs
+ vol
->dwVolLabelOfs
]);
264 /* dump information about the network volume the link points to */
265 printf("Network volume ofs = %08x ", loc
->dwNetworkVolTableOfs
);
266 if (loc
->dwNetworkVolTableOfs
&&
267 loc
->dwNetworkVolTableOfs
+ sizeof(NETWORK_VOLUME_INFO
) < loc
->dwTotalSize
)
269 const NETWORK_VOLUME_INFO
*vol
= (const NETWORK_VOLUME_INFO
*)&p
[loc
->dwNetworkVolTableOfs
];
271 printf("size %d name %d ", vol
->dwSize
, vol
->dwShareNameOfs
);
272 if(vol
->dwShareNameOfs
)
273 printf("(\"%s\")", &p
[loc
->dwNetworkVolTableOfs
+ vol
->dwShareNameOfs
]);
277 /* dump out the path the link points to */
278 printf("LocalPath ofs = %08x ", loc
->dwLocalPathOfs
);
279 if( loc
->dwLocalPathOfs
&& (loc
->dwLocalPathOfs
< loc
->dwTotalSize
) )
280 printf("(\"%s\")", &p
[loc
->dwLocalPathOfs
]);
283 printf("Net Path ofs = %08x\n", loc
->dwNetworkVolTableOfs
);
284 printf("Final Path = %08x ", loc
->dwFinalPathOfs
);
285 if( loc
->dwFinalPathOfs
&& (loc
->dwFinalPathOfs
< loc
->dwTotalSize
) )
286 printf("(\"%s\")", &p
[loc
->dwFinalPathOfs
]);
291 static const unsigned char table_dec85
[0x80] = {
292 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
293 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
294 0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
295 0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
296 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
297 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
298 0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
299 0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
302 static BOOL
base85_to_guid( const char *str
, LPGUID guid
)
304 DWORD i
, val
= 0, base
= 1, *p
;
308 for( i
=0; i
<20; i
++ )
318 val
+= table_dec85
[ch
] * base
;
319 if( table_dec85
[ch
] == 0xff )
328 static void dump_special_folder_block(const DATABLOCK_HEADER
* bhdr
)
330 const EXP_SPECIAL_FOLDER
*sfb
= (const EXP_SPECIAL_FOLDER
*)bhdr
;
331 printf("Special folder block\n");
332 printf("--------------------\n\n");
333 printf("folder = 0x%04x\n", sfb
->idSpecialFolder
);
334 printf("offset = %d\n", sfb
->cbOffset
);
338 static void dump_sz_block(const DATABLOCK_HEADER
* bhdr
, const char* label
)
340 const LINK_SZ_BLOCK
*szp
= (const LINK_SZ_BLOCK
*)bhdr
;
341 printf("String block\n");
342 printf("-----------\n\n");
343 printf("magic = %x\n", szp
->magic
);
344 printf("%s = %s\n", label
, szp
->bufA
);
348 static void dump_darwin_id(const DATABLOCK_HEADER
* bhdr
)
350 const LINK_SZ_BLOCK
*szp
= (const LINK_SZ_BLOCK
*)bhdr
;
352 const char *feat
, *comp
, *prod_str
, *feat_str
;
355 printf("Advertise Info\n");
356 printf("--------------\n\n");
357 printf("msi string = %s\n", szp
->bufA
);
359 if (base85_to_guid(szp
->bufA
, &guid
))
360 prod_str
= get_guid_str(&guid
);
364 comp
= &szp
->bufA
[20];
365 feat
= strchr(comp
, '>');
367 feat
= strchr(comp
, '<');
370 memcpy(comp_str
, comp
, feat
- comp
);
371 comp_str
[feat
-comp
] = 0;
375 strcpy(comp_str
, "?");
378 if (feat
&& feat
[0] == '>' && base85_to_guid( &feat
[1], &guid
))
379 feat_str
= get_guid_str( &guid
);
383 printf(" product: %s\n", prod_str
);
384 printf(" component: %s\n", comp_str
);
385 printf(" feature: %s\n", feat_str
);
389 static void dump_property_storage_value(const LINK_PROPERTYSTORAGE_VALUE
*lnk_value_hdr
,
392 BOOL got_terminator
= FALSE
;
394 const unsigned char *value
;
396 while (data_size
>= sizeof(DWORD
))
398 if (!lnk_value_hdr
->size
)
400 got_terminator
= TRUE
;
404 if (lnk_value_hdr
->size
> data_size
|| lnk_value_hdr
->size
< sizeof(*lnk_value_hdr
))
406 printf(" size: %d (invalid)\n", lnk_value_hdr
->size
);
410 printf(" pid: %d\n", lnk_value_hdr
->pid
);
411 printf(" unknown8: %d\n", lnk_value_hdr
->unknown8
);
412 printf(" vartype: %d\n", lnk_value_hdr
->vt
);
413 printf(" unknown25: %d\n", lnk_value_hdr
->unknown25
);
415 value_size
= lnk_value_hdr
->size
- sizeof(*lnk_value_hdr
);
416 value
= (const unsigned char*)(lnk_value_hdr
+1);
418 printf(" value (%2d bytes) : ",value_size
);
419 for(i
=0; i
<value_size
; i
++)
420 printf("%02x ",value
[i
]);
423 data_size
-= lnk_value_hdr
->size
;
424 lnk_value_hdr
= (void*)((char*)lnk_value_hdr
+ lnk_value_hdr
->size
);
428 printf(" missing terminator!\n");
431 static void dump_property_storage(const DATABLOCK_HEADER
* bhdr
)
434 const LINK_PROPERTYSTORAGE_GUID
*lnk_guid_hdr
;
435 BOOL got_terminator
= FALSE
;
437 printf("Property Storage\n");
438 printf("--------------\n\n");
440 data_size
=bhdr
->cbSize
-sizeof(*bhdr
);
442 lnk_guid_hdr
=(void*)((const char*)bhdr
+sizeof(*bhdr
));
444 while (data_size
>= sizeof(DWORD
))
446 if (!lnk_guid_hdr
->size
)
448 got_terminator
= TRUE
;
452 if (lnk_guid_hdr
->size
> data_size
|| lnk_guid_hdr
->size
< sizeof(*lnk_guid_hdr
))
454 printf("size: %d (invalid)\n", lnk_guid_hdr
->size
);
458 if (lnk_guid_hdr
->magic
!= 0x53505331)
459 printf("magic: %x\n", lnk_guid_hdr
->magic
);
461 printf("fmtid: %s\n", get_guid_str(&lnk_guid_hdr
->fmtid
));
463 dump_property_storage_value((void*)(lnk_guid_hdr
+ 1), lnk_guid_hdr
->size
- sizeof(*lnk_guid_hdr
));
465 data_size
-= lnk_guid_hdr
->size
;
467 lnk_guid_hdr
= (void*)((char*)lnk_guid_hdr
+ lnk_guid_hdr
->size
);
471 printf("missing terminator!\n");
476 static void dump_raw_block(const DATABLOCK_HEADER
* bhdr
)
480 printf("Raw Block\n");
481 printf("---------\n\n");
482 printf("size = %d\n", bhdr
->cbSize
);
483 printf("magic = %x\n", bhdr
->dwSignature
);
485 data_size
=bhdr
->cbSize
-sizeof(*bhdr
);
489 const unsigned char *data
;
492 data
=(const unsigned char*)bhdr
+sizeof(*bhdr
);
493 while (data_size
> 0)
495 for (i
=0; i
< 16; i
++)
498 printf("%02x ", data
[i
]);
502 for (i
=0; i
< data_size
&& i
< 16; i
++)
503 printf("%c", (data
[i
] >= 32 && data
[i
] < 128 ? data
[i
] : '.'));
515 static const GUID CLSID_ShellLink
= {0x00021401L
, 0, 0, {0xC0,0,0,0,0,0,0,0x46}};
517 enum FileSig
get_kind_lnk(void)
519 const LINK_HEADER
* hdr
;
521 hdr
= PRD(0, sizeof(*hdr
));
522 if (hdr
&& hdr
->dwSize
== sizeof(LINK_HEADER
) &&
523 !memcmp(&hdr
->MagicGuid
, &CLSID_ShellLink
, sizeof(GUID
)))
530 const LINK_HEADER
* hdr
;
531 const DATABLOCK_HEADER
* bhdr
;
540 printf("------\n\n");
541 printf("Size: %04x\n", hdr
->dwSize
);
542 printf("GUID: %s\n", get_guid_str(&hdr
->MagicGuid
));
544 printf("FileAttr: %08x\n", hdr
->dwFileAttr
);
545 printf("FileLength: %08x\n", hdr
->dwFileLength
);
546 printf("nIcon: %d\n", hdr
->nIcon
);
547 printf("Startup: %d\n", hdr
->fStartup
);
548 printf("HotKey: %08x\n", hdr
->wHotKey
);
549 printf("Unknown5: %08x\n", hdr
->Unknown5
);
550 printf("Unknown6: %08x\n", hdr
->Unknown6
);
552 /* dump out all the flags */
553 printf("Flags: %04x ( ", hdr
->dwFlags
);
554 dwFlags
=hdr
->dwFlags
;
557 if (dwFlags & SLDF_##x) \
560 dwFlags&=~SLDF_##x; \
567 FLAG(HAS_WORKINGDIR
);
569 FLAG(HAS_ICONLOCATION
);
571 FLAG(FORCE_NO_LINKINFO
);
573 FLAG(RUN_IN_SEPARATE
);
577 FLAG(HAS_EXP_ICON_SZ
);
580 FLAG(RUN_WITH_SHIMLAYER
);
581 FLAG(FORCE_NO_LINKTRACK
);
582 FLAG(ENABLE_TARGET_METADATA
);
583 FLAG(DISABLE_KNOWNFOLDER_RELATIVE_TRACKING
);
587 printf("+%04x", dwFlags
);
590 printf("Length: %04x\n", hdr
->dwFileLength
);
593 if (hdr
->dwFlags
& SLDF_HAS_ID_LIST
)
595 if (hdr
->dwFlags
& SLDF_HAS_LINK_INFO
)
597 if (hdr
->dwFlags
& SLDF_HAS_NAME
)
598 dump_string("Description", hdr
->dwFlags
& SLDF_UNICODE
);
599 if (hdr
->dwFlags
& SLDF_HAS_RELPATH
)
600 dump_string("Relative path", hdr
->dwFlags
& SLDF_UNICODE
);
601 if (hdr
->dwFlags
& SLDF_HAS_WORKINGDIR
)
602 dump_string("Working directory", hdr
->dwFlags
& SLDF_UNICODE
);
603 if (hdr
->dwFlags
& SLDF_HAS_ARGS
)
604 dump_string("Arguments", hdr
->dwFlags
& SLDF_UNICODE
);
605 if (hdr
->dwFlags
& SLDF_HAS_ICONLOCATION
)
606 dump_string("Icon path", hdr
->dwFlags
& SLDF_UNICODE
);
613 switch (bhdr
->dwSignature
)
615 case EXP_SZ_LINK_SIG
:
616 dump_sz_block(bhdr
, "exp.link");
618 case EXP_SPECIAL_FOLDER_SIG
:
619 dump_special_folder_block(bhdr
);
621 case EXP_SZ_ICON_SIG
:
622 dump_sz_block(bhdr
, "icon");
624 case EXP_DARWIN_ID_SIG
:
625 dump_darwin_id(bhdr
);
627 case EXP_PROPERTYSTORAGE_SIG
:
628 dump_property_storage(bhdr
);
631 dump_raw_block(bhdr
);