{{
import datetime
import malcat

def pval(key, val=None, fmt="{}", fa=False, kalign=30, valign=0, formated=False):
    r = "[normal]{}[/normal]:".format(key)
    lr = len(r) - 17
    if lr < kalign:
        r += (" "*(kalign-lr))
    if isinstance(val, malcat.StructAccess):
        if val.has_enum and val.enum:
            d = "[color6]{}[/color6]([dim]{}[/dim])".format(val.enum, fmt.format(val.value))
            formated = True
            ld = len(d) - len("[color3][/color3][dim][/dim]")
        elif isinstance(val.value, datetime.datetime):
            d = val.value.strftime("%Y-%m-%d %H:%M")
            ld = len(d)
        else:
            d = fmt.format(val.value)
            ld = len(d)
        val = val.value
    else:
        d = fmt.format(val)
        ld = len(d)
    if not formated:
        if type(val) == int: 
            if val == 0:
                grp = "dim"
            elif fa:
                grp = "fa"
            else:
                grp = "normal"
        else:
            grp = "normal"
        d = "[{}]{}[/{}]".format(grp,d,grp)
    if ld < valign:
        d += (" "*(valign-ld))
    write(r+d)  

def bitfieldpp(fa):
    s = []
    for i in range(fa.count - 1, -1, -1):
        bit = fa.at(i)
        if bit.value:
            s.append("[color5]{}[/color5]([dim]{:X}[/dim])".format(bit.name, 1 << i))
    if s:
        return  " + ".join(s)
    else:
        return "[dim]0[/dim]"

def pbitfield(key, fa, kalign=30):    
    r = "[normal]{}[/normal]:".format(key)
    lr = len(r) - 17
    if lr < kalign:
        r += (" "*(kalign-lr))
    write(r + bitfieldpp(fa))

}}
[color1]ShellLinkHeader[/color1]
  {{ pbitfield("LinkFlags", analysis.struct.ShellLinkHeader.LinkFlags) }}
  {{ pval("FileSize", analysis.struct.ShellLinkHeader.FileSize, "{:d} bytes", valign=24) }} {{ pval("Write time", analysis.struct.ShellLinkHeader.WriteTime) }}
  {{ pval("Creation time", analysis.struct.ShellLinkHeader.CreationTime, valign=24) }} {{ pval("Access time", analysis.struct.ShellLinkHeader.AccessTime) }}
  {{ pbitfield("File attributes", analysis.struct.ShellLinkHeader.FileAttributesFlags) }}
  {{ pval("Icon index", analysis.struct.ShellLinkHeader.IconIndex, valign=24) }} {{ pval("Show command", analysis.struct.ShellLinkHeader.ShowCommand) }}

[color1]LinkInfo[/color1]
{{ if "LinkInfo" in analysis.struct: }}
{{ if "VolumeId" in analysis.struct["LinkInfo"]: }}
  {{ pval("Drive Type", analysis.struct.LinkInfo.VolumeId.DriveType, valign=24) }} {{ pval("Drive Serial Number", analysis.struct.LinkInfo.VolumeId.DriveSerialNumber, "{:08X}") }}
{{ :endif}}
  {{ pval("LocalBasePath", analysis.struct["LinkInfo"]["LocalBasePath"].replace("[", "\\[")) }}
{{ :endif}}

[color1]LinkTarget[/color1]
{{ if "LinkTargetIDList" in analysis.struct: }}
{{
    path = ""
    for s in analysis.struct.LinkTargetIDList[1:-1]:
        if "Extension" in s:
            c = s["Extension"]["LongName"]
        elif "PrimaryName" in s:
            c = s["PrimaryName"]
        elif "Path" in s:
            c = s["Path"]
        else:
            continue
        if path and not path.endswith("\\"):
            path += "\\"
        path += c
}}
  {{ pval("Link Target", path.replace("[", "\\[")) }}
{{ :endif}}

[color1]Strings[/color1]
{{ for elem in ("NameString", "RelativePath", "WorkingDir", "CommandLineArguments", "IconLocation", ): }}
{{      if elem in analysis.struct and "String" in analysis.struct.at(elem):}}
  {{ pval(elem, analysis.struct.at(elem)["String"].replace("[", "\\[")) }}
{{      :else:}}
  {{ pval(elem, 0, "") }}
{{ :endif}}
{{:endfor}}

[color1]Tracker Data[/color1]
{{ if "TrackerDataBlock" in analysis.struct: }}
  {{ pval("Machine Name", analysis.struct["TrackerDataBlock"]["MachineID"].replace("[", "\\[")) }}
  {{ pval("MAC address", analysis.struct["TrackerDataBlock"]["Droid"][1].split("-")[-1]) }}
{{ :endif}}

[color1]Property Store[/color1]
{{ if "PropertyStoreDataBlock" in analysis.struct: }}
{{ for storage in analysis.struct.PropertyStoreDataBlock[2:-1]: }}
{{
        guid = storage.Format
}}
  [color2]{{ write(guid.enum or guid.value)}}[/color2]
{{ for val in storage[3:-1]: }}
{{
    if not "Data" in val.TypedValue:
        continue
    data = val["TypedValue"]["Data"]
    if isinstance(data, malcat.StructAccess):
        if "String" in data:
            data = data["String"].replace("\x00", "").strip()
        elif "Bytes" in data and data.size < 1024:
            data = data["Bytes"]
            if codec is not None:
                data = data.decode(codec, errors="replace")
            else:
                data = data.hex()
            data = data.replace("\x00", "").strip()
    elif isinstance(data, datetime.datetime):
        data = data.strftime("%Y-%m-%d %H:%M:%S")
    if not data:
        continue
}}
    {{pval(val.Id.enum or "Property #{}".format(val.Id.value), data, kalign=28) }}
{{:endfor}}

{{:endfor}}
{{ :endif}}

