Windows shell link file: C++11/STL parsing library

Windows .lnk files (AKA "shell link" file) are most frequently used in Windows shell to create "shortcuts" to another files, usually for purposes of running a program from some other directory, sometimes with certain preconfigured arguments and some other options.

This page hosts a formal specification of Windows shell link file using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.lnk", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    windows_lnk_file_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.header() // => get header

C++11/STL source code to parse Windows shell link file

windows_lnk_file.h

#pragma once

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include "windows_shell_items.h"

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class windows_shell_items_t;

/**
 * Windows .lnk files (AKA "shell link" file) are most frequently used
 * in Windows shell to create "shortcuts" to another files, usually for
 * purposes of running a program from some other directory, sometimes
 * with certain preconfigured arguments and some other options.
 * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Source
 */

class windows_lnk_file_t : public kaitai::kstruct {

public:
    class link_target_id_list_t;
    class string_data_t;
    class link_info_t;
    class link_flags_t;
    class file_header_t;

    enum window_state_t {
        WINDOW_STATE_NORMAL = 1,
        WINDOW_STATE_MAXIMIZED = 3,
        WINDOW_STATE_MIN_NO_ACTIVE = 7
    };

    enum drive_types_t {
        DRIVE_TYPES_UNKNOWN = 0,
        DRIVE_TYPES_NO_ROOT_DIR = 1,
        DRIVE_TYPES_REMOVABLE = 2,
        DRIVE_TYPES_FIXED = 3,
        DRIVE_TYPES_REMOTE = 4,
        DRIVE_TYPES_CDROM = 5,
        DRIVE_TYPES_RAMDISK = 6
    };

    windows_lnk_file_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

private:
    void _read();
    void _clean_up();

public:
    ~windows_lnk_file_t();

    /**
     * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.2
     */

    class link_target_id_list_t : public kaitai::kstruct {

    public:

        link_target_id_list_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~link_target_id_list_t();

    private:
        uint16_t m_len_id_list;
        std::unique_ptr<windows_shell_items_t> m_id_list;
        windows_lnk_file_t* m__root;
        windows_lnk_file_t* m__parent;
        std::string m__raw_id_list;
        std::unique_ptr<kaitai::kstream> m__io__raw_id_list;

    public:
        uint16_t len_id_list() const { return m_len_id_list; }
        windows_shell_items_t* id_list() const { return m_id_list.get(); }
        windows_lnk_file_t* _root() const { return m__root; }
        windows_lnk_file_t* _parent() const { return m__parent; }
        std::string _raw_id_list() const { return m__raw_id_list; }
        kaitai::kstream* _io__raw_id_list() const { return m__io__raw_id_list.get(); }
    };

    class string_data_t : public kaitai::kstruct {

    public:

        string_data_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~string_data_t();

    private:
        uint16_t m_chars_str;
        std::string m_str;
        windows_lnk_file_t* m__root;
        windows_lnk_file_t* m__parent;

    public:
        uint16_t chars_str() const { return m_chars_str; }
        std::string str() const { return m_str; }
        windows_lnk_file_t* _root() const { return m__root; }
        windows_lnk_file_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.3
     */

    class link_info_t : public kaitai::kstruct {

    public:
        class volume_id_body_t;
        class all_t;
        class volume_id_spec_t;
        class link_info_flags_t;
        class header_t;

        link_info_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~link_info_t();

        /**
         * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.3.1
         */

        class volume_id_body_t : public kaitai::kstruct {

        public:

            volume_id_body_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::volume_id_spec_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

        private:
            void _read();
            void _clean_up();

        public:
            ~volume_id_body_t();

        private:
            bool f_is_unicode;
            bool m_is_unicode;

        public:
            bool is_unicode();

        private:
            bool f_volume_label_ansi;
            std::string m_volume_label_ansi;
            bool n_volume_label_ansi;

        public:
            bool _is_null_volume_label_ansi() { volume_label_ansi(); return n_volume_label_ansi; };

        private:

        public:
            std::string volume_label_ansi();

        private:
            drive_types_t m_drive_type;
            uint32_t m_drive_serial_number;
            uint32_t m_ofs_volume_label;
            uint32_t m_ofs_volume_label_unicode;
            bool n_ofs_volume_label_unicode;

        public:
            bool _is_null_ofs_volume_label_unicode() { ofs_volume_label_unicode(); return n_ofs_volume_label_unicode; };

        private:
            windows_lnk_file_t* m__root;
            windows_lnk_file_t::link_info_t::volume_id_spec_t* m__parent;

        public:
            drive_types_t drive_type() const { return m_drive_type; }
            uint32_t drive_serial_number() const { return m_drive_serial_number; }
            uint32_t ofs_volume_label() const { return m_ofs_volume_label; }
            uint32_t ofs_volume_label_unicode() const { return m_ofs_volume_label_unicode; }
            windows_lnk_file_t* _root() const { return m__root; }
            windows_lnk_file_t::link_info_t::volume_id_spec_t* _parent() const { return m__parent; }
        };

        /**
         * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.3
         */

        class all_t : public kaitai::kstruct {

        public:

            all_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

        private:
            void _read();
            void _clean_up();

        public:
            ~all_t();

        private:
            bool f_volume_id;
            std::unique_ptr<volume_id_spec_t> m_volume_id;
            bool n_volume_id;

        public:
            bool _is_null_volume_id() { volume_id(); return n_volume_id; };

        private:

        public:
            volume_id_spec_t* volume_id();

        private:
            bool f_local_base_path;
            std::string m_local_base_path;
            bool n_local_base_path;

        public:
            bool _is_null_local_base_path() { local_base_path(); return n_local_base_path; };

        private:

        public:
            std::string local_base_path();

        private:
            uint32_t m_len_header;
            std::unique_ptr<header_t> m_header;
            windows_lnk_file_t* m__root;
            windows_lnk_file_t::link_info_t* m__parent;
            std::string m__raw_header;
            std::unique_ptr<kaitai::kstream> m__io__raw_header;

        public:
            uint32_t len_header() const { return m_len_header; }
            header_t* header() const { return m_header.get(); }
            windows_lnk_file_t* _root() const { return m__root; }
            windows_lnk_file_t::link_info_t* _parent() const { return m__parent; }
            std::string _raw_header() const { return m__raw_header; }
            kaitai::kstream* _io__raw_header() const { return m__io__raw_header.get(); }
        };

        /**
         * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.3.1
         */

        class volume_id_spec_t : public kaitai::kstruct {

        public:

            volume_id_spec_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::all_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

        private:
            void _read();
            void _clean_up();

        public:
            ~volume_id_spec_t();

        private:
            uint32_t m_len_all;
            std::unique_ptr<volume_id_body_t> m_body;
            windows_lnk_file_t* m__root;
            windows_lnk_file_t::link_info_t::all_t* m__parent;
            std::string m__raw_body;
            std::unique_ptr<kaitai::kstream> m__io__raw_body;

        public:
            uint32_t len_all() const { return m_len_all; }
            volume_id_body_t* body() const { return m_body.get(); }
            windows_lnk_file_t* _root() const { return m__root; }
            windows_lnk_file_t::link_info_t::all_t* _parent() const { return m__parent; }
            std::string _raw_body() const { return m__raw_body; }
            kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); }
        };

        /**
         * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.3
         */

        class link_info_flags_t : public kaitai::kstruct {

        public:

            link_info_flags_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::header_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

        private:
            void _read();
            void _clean_up();

        public:
            ~link_info_flags_t();

        private:
            uint64_t m_reserved1;
            bool m_has_common_net_rel_link;
            bool m_has_volume_id_and_local_base_path;
            uint64_t m_reserved2;
            windows_lnk_file_t* m__root;
            windows_lnk_file_t::link_info_t::header_t* m__parent;

        public:
            uint64_t reserved1() const { return m_reserved1; }
            bool has_common_net_rel_link() const { return m_has_common_net_rel_link; }
            bool has_volume_id_and_local_base_path() const { return m_has_volume_id_and_local_base_path; }
            uint64_t reserved2() const { return m_reserved2; }
            windows_lnk_file_t* _root() const { return m__root; }
            windows_lnk_file_t::link_info_t::header_t* _parent() const { return m__parent; }
        };

        /**
         * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.3
         */

        class header_t : public kaitai::kstruct {

        public:

            header_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::all_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

        private:
            void _read();
            void _clean_up();

        public:
            ~header_t();

        private:
            std::unique_ptr<link_info_flags_t> m_flags;
            uint32_t m_ofs_volume_id;
            uint32_t m_ofs_local_base_path;
            uint32_t m_ofs_common_net_rel_link;
            uint32_t m_ofs_common_path_suffix;
            uint32_t m_ofs_local_base_path_unicode;
            bool n_ofs_local_base_path_unicode;

        public:
            bool _is_null_ofs_local_base_path_unicode() { ofs_local_base_path_unicode(); return n_ofs_local_base_path_unicode; };

        private:
            uint32_t m_ofs_common_path_suffix_unicode;
            bool n_ofs_common_path_suffix_unicode;

        public:
            bool _is_null_ofs_common_path_suffix_unicode() { ofs_common_path_suffix_unicode(); return n_ofs_common_path_suffix_unicode; };

        private:
            windows_lnk_file_t* m__root;
            windows_lnk_file_t::link_info_t::all_t* m__parent;

        public:
            link_info_flags_t* flags() const { return m_flags.get(); }
            uint32_t ofs_volume_id() const { return m_ofs_volume_id; }
            uint32_t ofs_local_base_path() const { return m_ofs_local_base_path; }
            uint32_t ofs_common_net_rel_link() const { return m_ofs_common_net_rel_link; }
            uint32_t ofs_common_path_suffix() const { return m_ofs_common_path_suffix; }
            uint32_t ofs_local_base_path_unicode() const { return m_ofs_local_base_path_unicode; }
            uint32_t ofs_common_path_suffix_unicode() const { return m_ofs_common_path_suffix_unicode; }
            windows_lnk_file_t* _root() const { return m__root; }
            windows_lnk_file_t::link_info_t::all_t* _parent() const { return m__parent; }
        };

    private:
        uint32_t m_len_all;
        std::unique_ptr<all_t> m_all;
        windows_lnk_file_t* m__root;
        windows_lnk_file_t* m__parent;
        std::string m__raw_all;
        std::unique_ptr<kaitai::kstream> m__io__raw_all;

    public:
        uint32_t len_all() const { return m_len_all; }
        all_t* all() const { return m_all.get(); }
        windows_lnk_file_t* _root() const { return m__root; }
        windows_lnk_file_t* _parent() const { return m__parent; }
        std::string _raw_all() const { return m__raw_all; }
        kaitai::kstream* _io__raw_all() const { return m__io__raw_all.get(); }
    };

    /**
     * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.1.1
     */

    class link_flags_t : public kaitai::kstruct {

    public:

        link_flags_t(kaitai::kstream* p__io, windows_lnk_file_t::file_header_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~link_flags_t();

    private:
        bool m_is_unicode;
        bool m_has_icon_location;
        bool m_has_arguments;
        bool m_has_work_dir;
        bool m_has_rel_path;
        bool m_has_name;
        bool m_has_link_info;
        bool m_has_link_target_id_list;
        uint64_t m__unnamed8;
        uint64_t m_reserved;
        bool m_keep_local_id_list_for_unc_target;
        uint64_t m__unnamed11;
        windows_lnk_file_t* m__root;
        windows_lnk_file_t::file_header_t* m__parent;

    public:
        bool is_unicode() const { return m_is_unicode; }
        bool has_icon_location() const { return m_has_icon_location; }
        bool has_arguments() const { return m_has_arguments; }
        bool has_work_dir() const { return m_has_work_dir; }
        bool has_rel_path() const { return m_has_rel_path; }
        bool has_name() const { return m_has_name; }
        bool has_link_info() const { return m_has_link_info; }
        bool has_link_target_id_list() const { return m_has_link_target_id_list; }
        uint64_t _unnamed8() const { return m__unnamed8; }
        uint64_t reserved() const { return m_reserved; }
        bool keep_local_id_list_for_unc_target() const { return m_keep_local_id_list_for_unc_target; }
        uint64_t _unnamed11() const { return m__unnamed11; }
        windows_lnk_file_t* _root() const { return m__root; }
        windows_lnk_file_t::file_header_t* _parent() const { return m__parent; }
    };

    /**
     * \sa https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-SHLLINK/[MS-SHLLINK].pdf Section 2.1
     */

    class file_header_t : public kaitai::kstruct {

    public:

        file_header_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent = nullptr, windows_lnk_file_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~file_header_t();

    private:
        std::string m_len_header;
        std::string m_link_clsid;
        std::unique_ptr<link_flags_t> m_flags;
        uint32_t m_file_attrs;
        uint64_t m_time_creation;
        uint64_t m_time_access;
        uint64_t m_time_write;
        uint32_t m_target_file_size;
        int32_t m_icon_index;
        window_state_t m_show_command;
        uint16_t m_hotkey;
        std::string m_reserved;
        windows_lnk_file_t* m__root;
        windows_lnk_file_t* m__parent;
        std::string m__raw_flags;
        std::unique_ptr<kaitai::kstream> m__io__raw_flags;

    public:

        /**
         * Technically, a size of the header, but in reality, it's
         * fixed by standard.
         */
        std::string len_header() const { return m_len_header; }

        /**
         * 16-byte class identified (CLSID), reserved for Windows shell
         * link files.
         */
        std::string link_clsid() const { return m_link_clsid; }
        link_flags_t* flags() const { return m_flags.get(); }
        uint32_t file_attrs() const { return m_file_attrs; }
        uint64_t time_creation() const { return m_time_creation; }
        uint64_t time_access() const { return m_time_access; }
        uint64_t time_write() const { return m_time_write; }

        /**
         * Lower 32 bits of the size of the file that this link targets
         */
        uint32_t target_file_size() const { return m_target_file_size; }

        /**
         * Index of an icon to use from target file
         */
        int32_t icon_index() const { return m_icon_index; }

        /**
         * Window state to set after the launch of target executable
         */
        window_state_t show_command() const { return m_show_command; }
        uint16_t hotkey() const { return m_hotkey; }
        std::string reserved() const { return m_reserved; }
        windows_lnk_file_t* _root() const { return m__root; }
        windows_lnk_file_t* _parent() const { return m__parent; }
        std::string _raw_flags() const { return m__raw_flags; }
        kaitai::kstream* _io__raw_flags() const { return m__io__raw_flags.get(); }
    };

private:
    std::unique_ptr<file_header_t> m_header;
    std::unique_ptr<link_target_id_list_t> m_target_id_list;
    bool n_target_id_list;

public:
    bool _is_null_target_id_list() { target_id_list(); return n_target_id_list; };

private:
    std::unique_ptr<link_info_t> m_info;
    bool n_info;

public:
    bool _is_null_info() { info(); return n_info; };

private:
    std::unique_ptr<string_data_t> m_name;
    bool n_name;

public:
    bool _is_null_name() { name(); return n_name; };

private:
    std::unique_ptr<string_data_t> m_rel_path;
    bool n_rel_path;

public:
    bool _is_null_rel_path() { rel_path(); return n_rel_path; };

private:
    std::unique_ptr<string_data_t> m_work_dir;
    bool n_work_dir;

public:
    bool _is_null_work_dir() { work_dir(); return n_work_dir; };

private:
    std::unique_ptr<string_data_t> m_arguments;
    bool n_arguments;

public:
    bool _is_null_arguments() { arguments(); return n_arguments; };

private:
    std::unique_ptr<string_data_t> m_icon_location;
    bool n_icon_location;

public:
    bool _is_null_icon_location() { icon_location(); return n_icon_location; };

private:
    windows_lnk_file_t* m__root;
    kaitai::kstruct* m__parent;

public:
    file_header_t* header() const { return m_header.get(); }
    link_target_id_list_t* target_id_list() const { return m_target_id_list.get(); }
    link_info_t* info() const { return m_info.get(); }
    string_data_t* name() const { return m_name.get(); }
    string_data_t* rel_path() const { return m_rel_path.get(); }
    string_data_t* work_dir() const { return m_work_dir.get(); }
    string_data_t* arguments() const { return m_arguments.get(); }
    string_data_t* icon_location() const { return m_icon_location.get(); }
    windows_lnk_file_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

windows_lnk_file.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "windows_lnk_file.h"
#include "kaitai/exceptions.h"

windows_lnk_file_t::windows_lnk_file_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_header = nullptr;
    m_target_id_list = nullptr;
    m_info = nullptr;
    m_name = nullptr;
    m_rel_path = nullptr;
    m_work_dir = nullptr;
    m_arguments = nullptr;
    m_icon_location = nullptr;
    _read();
}

void windows_lnk_file_t::_read() {
    m_header = std::unique_ptr<file_header_t>(new file_header_t(m__io, this, m__root));
    n_target_id_list = true;
    if (header()->flags()->has_link_target_id_list()) {
        n_target_id_list = false;
        m_target_id_list = std::unique_ptr<link_target_id_list_t>(new link_target_id_list_t(m__io, this, m__root));
    }
    n_info = true;
    if (header()->flags()->has_link_info()) {
        n_info = false;
        m_info = std::unique_ptr<link_info_t>(new link_info_t(m__io, this, m__root));
    }
    n_name = true;
    if (header()->flags()->has_name()) {
        n_name = false;
        m_name = std::unique_ptr<string_data_t>(new string_data_t(m__io, this, m__root));
    }
    n_rel_path = true;
    if (header()->flags()->has_rel_path()) {
        n_rel_path = false;
        m_rel_path = std::unique_ptr<string_data_t>(new string_data_t(m__io, this, m__root));
    }
    n_work_dir = true;
    if (header()->flags()->has_work_dir()) {
        n_work_dir = false;
        m_work_dir = std::unique_ptr<string_data_t>(new string_data_t(m__io, this, m__root));
    }
    n_arguments = true;
    if (header()->flags()->has_arguments()) {
        n_arguments = false;
        m_arguments = std::unique_ptr<string_data_t>(new string_data_t(m__io, this, m__root));
    }
    n_icon_location = true;
    if (header()->flags()->has_icon_location()) {
        n_icon_location = false;
        m_icon_location = std::unique_ptr<string_data_t>(new string_data_t(m__io, this, m__root));
    }
}

windows_lnk_file_t::~windows_lnk_file_t() {
    _clean_up();
}

void windows_lnk_file_t::_clean_up() {
    if (!n_target_id_list) {
    }
    if (!n_info) {
    }
    if (!n_name) {
    }
    if (!n_rel_path) {
    }
    if (!n_work_dir) {
    }
    if (!n_arguments) {
    }
    if (!n_icon_location) {
    }
}

windows_lnk_file_t::link_target_id_list_t::link_target_id_list_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_id_list = nullptr;
    m__io__raw_id_list = nullptr;
    _read();
}

void windows_lnk_file_t::link_target_id_list_t::_read() {
    m_len_id_list = m__io->read_u2le();
    m__raw_id_list = m__io->read_bytes(len_id_list());
    m__io__raw_id_list = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_id_list));
    m_id_list = std::unique_ptr<windows_shell_items_t>(new windows_shell_items_t(m__io__raw_id_list.get()));
}

windows_lnk_file_t::link_target_id_list_t::~link_target_id_list_t() {
    _clean_up();
}

void windows_lnk_file_t::link_target_id_list_t::_clean_up() {
}

windows_lnk_file_t::string_data_t::string_data_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void windows_lnk_file_t::string_data_t::_read() {
    m_chars_str = m__io->read_u2le();
    m_str = kaitai::kstream::bytes_to_str(m__io->read_bytes((chars_str() * 2)), std::string("UTF-16LE"));
}

windows_lnk_file_t::string_data_t::~string_data_t() {
    _clean_up();
}

void windows_lnk_file_t::string_data_t::_clean_up() {
}

windows_lnk_file_t::link_info_t::link_info_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_all = nullptr;
    m__io__raw_all = nullptr;
    _read();
}

void windows_lnk_file_t::link_info_t::_read() {
    m_len_all = m__io->read_u4le();
    m__raw_all = m__io->read_bytes((len_all() - 4));
    m__io__raw_all = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_all));
    m_all = std::unique_ptr<all_t>(new all_t(m__io__raw_all.get(), this, m__root));
}

windows_lnk_file_t::link_info_t::~link_info_t() {
    _clean_up();
}

void windows_lnk_file_t::link_info_t::_clean_up() {
}

windows_lnk_file_t::link_info_t::volume_id_body_t::volume_id_body_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::volume_id_spec_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_is_unicode = false;
    f_volume_label_ansi = false;
    _read();
}

void windows_lnk_file_t::link_info_t::volume_id_body_t::_read() {
    m_drive_type = static_cast<windows_lnk_file_t::drive_types_t>(m__io->read_u4le());
    m_drive_serial_number = m__io->read_u4le();
    m_ofs_volume_label = m__io->read_u4le();
    n_ofs_volume_label_unicode = true;
    if (is_unicode()) {
        n_ofs_volume_label_unicode = false;
        m_ofs_volume_label_unicode = m__io->read_u4le();
    }
}

windows_lnk_file_t::link_info_t::volume_id_body_t::~volume_id_body_t() {
    _clean_up();
}

void windows_lnk_file_t::link_info_t::volume_id_body_t::_clean_up() {
    if (!n_ofs_volume_label_unicode) {
    }
    if (f_volume_label_ansi && !n_volume_label_ansi) {
    }
}

bool windows_lnk_file_t::link_info_t::volume_id_body_t::is_unicode() {
    if (f_is_unicode)
        return m_is_unicode;
    m_is_unicode = ofs_volume_label() == 20;
    f_is_unicode = true;
    return m_is_unicode;
}

std::string windows_lnk_file_t::link_info_t::volume_id_body_t::volume_label_ansi() {
    if (f_volume_label_ansi)
        return m_volume_label_ansi;
    n_volume_label_ansi = true;
    if (!(is_unicode())) {
        n_volume_label_ansi = false;
        std::streampos _pos = m__io->pos();
        m__io->seek((ofs_volume_label() - 4));
        m_volume_label_ansi = kaitai::kstream::bytes_to_str(m__io->read_bytes_term(0, false, true, true), std::string("cp437"));
        m__io->seek(_pos);
        f_volume_label_ansi = true;
    }
    return m_volume_label_ansi;
}

windows_lnk_file_t::link_info_t::all_t::all_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_header = nullptr;
    m__io__raw_header = nullptr;
    m_volume_id = nullptr;
    f_volume_id = false;
    f_local_base_path = false;
    _read();
}

void windows_lnk_file_t::link_info_t::all_t::_read() {
    m_len_header = m__io->read_u4le();
    m__raw_header = m__io->read_bytes((len_header() - 8));
    m__io__raw_header = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_header));
    m_header = std::unique_ptr<header_t>(new header_t(m__io__raw_header.get(), this, m__root));
}

windows_lnk_file_t::link_info_t::all_t::~all_t() {
    _clean_up();
}

void windows_lnk_file_t::link_info_t::all_t::_clean_up() {
    if (f_volume_id && !n_volume_id) {
    }
    if (f_local_base_path && !n_local_base_path) {
    }
}

windows_lnk_file_t::link_info_t::volume_id_spec_t* windows_lnk_file_t::link_info_t::all_t::volume_id() {
    if (f_volume_id)
        return m_volume_id.get();
    n_volume_id = true;
    if (header()->flags()->has_volume_id_and_local_base_path()) {
        n_volume_id = false;
        std::streampos _pos = m__io->pos();
        m__io->seek((header()->ofs_volume_id() - 4));
        m_volume_id = std::unique_ptr<volume_id_spec_t>(new volume_id_spec_t(m__io, this, m__root));
        m__io->seek(_pos);
        f_volume_id = true;
    }
    return m_volume_id.get();
}

std::string windows_lnk_file_t::link_info_t::all_t::local_base_path() {
    if (f_local_base_path)
        return m_local_base_path;
    n_local_base_path = true;
    if (header()->flags()->has_volume_id_and_local_base_path()) {
        n_local_base_path = false;
        std::streampos _pos = m__io->pos();
        m__io->seek((header()->ofs_local_base_path() - 4));
        m_local_base_path = m__io->read_bytes_term(0, false, true, true);
        m__io->seek(_pos);
        f_local_base_path = true;
    }
    return m_local_base_path;
}

windows_lnk_file_t::link_info_t::volume_id_spec_t::volume_id_spec_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::all_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_body = nullptr;
    m__io__raw_body = nullptr;
    _read();
}

void windows_lnk_file_t::link_info_t::volume_id_spec_t::_read() {
    m_len_all = m__io->read_u4le();
    m__raw_body = m__io->read_bytes((len_all() - 4));
    m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
    m_body = std::unique_ptr<volume_id_body_t>(new volume_id_body_t(m__io__raw_body.get(), this, m__root));
}

windows_lnk_file_t::link_info_t::volume_id_spec_t::~volume_id_spec_t() {
    _clean_up();
}

void windows_lnk_file_t::link_info_t::volume_id_spec_t::_clean_up() {
}

windows_lnk_file_t::link_info_t::link_info_flags_t::link_info_flags_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::header_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void windows_lnk_file_t::link_info_t::link_info_flags_t::_read() {
    m_reserved1 = m__io->read_bits_int_be(6);
    m_has_common_net_rel_link = m__io->read_bits_int_be(1);
    m_has_volume_id_and_local_base_path = m__io->read_bits_int_be(1);
    m_reserved2 = m__io->read_bits_int_be(24);
}

windows_lnk_file_t::link_info_t::link_info_flags_t::~link_info_flags_t() {
    _clean_up();
}

void windows_lnk_file_t::link_info_t::link_info_flags_t::_clean_up() {
}

windows_lnk_file_t::link_info_t::header_t::header_t(kaitai::kstream* p__io, windows_lnk_file_t::link_info_t::all_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = nullptr;
    _read();
}

void windows_lnk_file_t::link_info_t::header_t::_read() {
    m_flags = std::unique_ptr<link_info_flags_t>(new link_info_flags_t(m__io, this, m__root));
    m_ofs_volume_id = m__io->read_u4le();
    m_ofs_local_base_path = m__io->read_u4le();
    m_ofs_common_net_rel_link = m__io->read_u4le();
    m_ofs_common_path_suffix = m__io->read_u4le();
    n_ofs_local_base_path_unicode = true;
    if (!(_io()->is_eof())) {
        n_ofs_local_base_path_unicode = false;
        m_ofs_local_base_path_unicode = m__io->read_u4le();
    }
    n_ofs_common_path_suffix_unicode = true;
    if (!(_io()->is_eof())) {
        n_ofs_common_path_suffix_unicode = false;
        m_ofs_common_path_suffix_unicode = m__io->read_u4le();
    }
}

windows_lnk_file_t::link_info_t::header_t::~header_t() {
    _clean_up();
}

void windows_lnk_file_t::link_info_t::header_t::_clean_up() {
    if (!n_ofs_local_base_path_unicode) {
    }
    if (!n_ofs_common_path_suffix_unicode) {
    }
}

windows_lnk_file_t::link_flags_t::link_flags_t(kaitai::kstream* p__io, windows_lnk_file_t::file_header_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void windows_lnk_file_t::link_flags_t::_read() {
    m_is_unicode = m__io->read_bits_int_be(1);
    m_has_icon_location = m__io->read_bits_int_be(1);
    m_has_arguments = m__io->read_bits_int_be(1);
    m_has_work_dir = m__io->read_bits_int_be(1);
    m_has_rel_path = m__io->read_bits_int_be(1);
    m_has_name = m__io->read_bits_int_be(1);
    m_has_link_info = m__io->read_bits_int_be(1);
    m_has_link_target_id_list = m__io->read_bits_int_be(1);
    m__unnamed8 = m__io->read_bits_int_be(16);
    m_reserved = m__io->read_bits_int_be(5);
    m_keep_local_id_list_for_unc_target = m__io->read_bits_int_be(1);
    m__unnamed11 = m__io->read_bits_int_be(2);
}

windows_lnk_file_t::link_flags_t::~link_flags_t() {
    _clean_up();
}

void windows_lnk_file_t::link_flags_t::_clean_up() {
}

windows_lnk_file_t::file_header_t::file_header_t(kaitai::kstream* p__io, windows_lnk_file_t* p__parent, windows_lnk_file_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_flags = nullptr;
    m__io__raw_flags = nullptr;
    _read();
}

void windows_lnk_file_t::file_header_t::_read() {
    m_len_header = m__io->read_bytes(4);
    if (!(len_header() == std::string("\x4C\x00\x00\x00", 4))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x4C\x00\x00\x00", 4), len_header(), _io(), std::string("/types/file_header/seq/0"));
    }
    m_link_clsid = m__io->read_bytes(16);
    if (!(link_clsid() == std::string("\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46", 16))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x01\x14\x02\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x46", 16), link_clsid(), _io(), std::string("/types/file_header/seq/1"));
    }
    m__raw_flags = m__io->read_bytes(4);
    m__io__raw_flags = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_flags));
    m_flags = std::unique_ptr<link_flags_t>(new link_flags_t(m__io__raw_flags.get(), this, m__root));
    m_file_attrs = m__io->read_u4le();
    m_time_creation = m__io->read_u8le();
    m_time_access = m__io->read_u8le();
    m_time_write = m__io->read_u8le();
    m_target_file_size = m__io->read_u4le();
    m_icon_index = m__io->read_s4le();
    m_show_command = static_cast<windows_lnk_file_t::window_state_t>(m__io->read_u4le());
    m_hotkey = m__io->read_u2le();
    m_reserved = m__io->read_bytes(10);
    if (!(reserved() == std::string("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10), reserved(), _io(), std::string("/types/file_header/seq/11"));
    }
}

windows_lnk_file_t::file_header_t::~file_header_t() {
    _clean_up();
}

void windows_lnk_file_t::file_header_t::_clean_up() {
}