{{
import malcat
from filetypes.NSIS import NSIS_CALLBACKS

def pval(key, val=None, fmt="{}", va=False, fa=False, rva=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]")
        else:
            d = fmt.format(val.value)
            ld = len(d)
        val = val.value
    else:
        d = fmt.format(val)
        ld = len(d)
    if val == 0:
        grp = "dim"
    elif fa:
        grp = "fa"
    elif rva:
        grp = "rva"
    elif va:
        grp = "va"
    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))


def get_string(idx):
    if analysis.parser.is_unicode:
        offset = analysis.parser.string_start + idx * 2
    else:
        offset = analysis.parser.string_start + idx
    ea = analysis.map.from_phys(offset)
    if ea is not None:
        if ea in analysis.strings:
            s = analysis.strings[ea]
            if s.address == ea:
                return s.text.replace("[", "\\[")
    return "" 
}}

[color1]Header[/color1]
  {{ pbitfield("Flags", analysis.struct.CommonHeader.Flags) }}
{{for i, cb in enumerate(NSIS_CALLBACKS):}}
{{ 
off = analysis.struct["CommonHeader"]["Callback{}".format(cb)]
if off != 0xffffffff:
}}
  {{ pval(cb, "0x{:06x}".format(off  * 4 * 7 + analysis.parser.code_start), fa=True) }}
{{ :endif}}
{{ :endfor}}
  {{ pval("InstallDir", get_string(analysis.struct["CommonHeader"]["InstallDirPtr"])) }} 
  {{ pval("InstallDirAutoAppend", get_string(analysis.struct["CommonHeader"]["InstallDirAutoAppend"])) }} 
  {{ pval("InstallRegRootkey", get_string(analysis.struct["CommonHeader"]["InstallRegRootkey"])) }} 
  {{ pval("InstallRegKeyPtr", get_string(analysis.struct["CommonHeader"]["InstallRegKeyPtr"])) }} 
  {{ pval("StringUninstallChild", get_string(analysis.struct["CommonHeader"]["StringUninstallChild"])) }} 
  {{ pval("StringUninstallCmd", get_string(analysis.struct["CommonHeader"]["StringUninstallCmd"])) }} 
  {{ pval("StringWinInit", get_string(analysis.struct["CommonHeader"]["StringWinInit"])) }}

[color1]Sections[/color1]
{{for sname, s in analysis.parser.nsis_sections.items():}}
  [normal]{{ "{:16.16s}".format(sname.replace("[", "\\[")) }}[/normal]  --→  CodeIndex: [fa]{{"0x{:06x}".format(s["CodeIndex"] * 4 * 7 + analysis.parser.code_start)}}[/fa]    CodeSize: [normal]{{"{: 6d} bytes".format(s["CodeSize"])}}[/normal]    flags: {{write(bitfieldpp(s["Flags"]))}}
{{ :end }}
