'
'https://docs.microsoft.com/en-us/windows/win32/menurc/resource-file-formats


  $ Filename "LinkRes.exe"
  uses RTL64
  uses kernel
  %NoConsole
  uses console
  uses oxide.res
  indexbase 1


type ResHead1
  dword DataSize
  dword HeaderSize
end type

type ResHead2
  dword DataVersion
  word  MemFlags
  word  LangId
  dword Version
  dword Charistics
end type



function RetResType (int ResType) as string
===========================================
  '
  select ResType

  case 0x0000 : return "NULL"
  case 0x0001 : return "Cursor"
  case 0x0002 : return "Bitmap"
  case 0x0003 : return "Icon"
  case 0x0004 : return "Menu"
  case 0x0005 : return "Dialog"
  case 0x0006 : return "String Table"
  case 0x0007 : return "Font Directory"
  case 0x0008 : return "Font"
  case 0x0009 : return "Accelerators Table"
  case 0x000A : return "RC Data (custom binary data)"
  case 0x000B : return "Message table"
  case 0x000C : return "Group Cursor"
  case 0x000E : return "Group Icon"
  case 0x0010 : return "Version Information"
  case 0x0011 : return "Dialog Include"
  case 0x0013 : return "Plug'n'Play"
  case 0x0014 : return "VXD"
  case 0x0015 : return "Animated Cursor"
  case 0x0018 : return "Manifest"
  case 0x2002 : return "Bitmap (new version)"
  case 0x2004 : return "Menu (new version)"
  case 0x2005 : return "Dialog (new version)"

  end select
  '
  return "Unknown"
end function


function RetMemFlags (int flags) as string
==========================================
  if flags = 0 then return "None"
  string MemFlags
  if flags and 0x10 then MemFlags="MOVEABLE"
  if flags and 0x20 then MemFlags+=" PURE"
  if flags and 0x40 then MemFlags+=" PRELOAD"
  if flags and 0x1000 then MemFlags+=" DISCARDABLE"
  return MemFlags
end function


function AddResources(string ResFile, TgtFile, int verbose=0) as int
====================================================================

  sys      hRes
  sys      ResBase
  sys      ResData
  sys      ResLen
  sys      ResPos
  sys      ResName
  sys      ResType
  wchar*   ResNameStr
  wchar*   ResTypeStr
  wchar*   unihead
  int      HeadOffset
  int      UniSize
  int      DataSpace
  int      Result
  ResHead1 *rh1
  ResHead2 *rh2
  string   ResBuf

  ResBuf=getfile(ResFile)
  if not ResBuf
    print "File not found: " ResFile cr
    return 1
  endif
  '
  hRes=BeginUpdateResource(TgtFile, 1)  ' File to add the resource to
  if not hRes
    print "BeginUpdateResource failed..." cr
    return 1
  endif
  '
  ResBase=strptr(ResBuf)
  ResLen = len(ResBuf)
  ResPos = 0
  int rhe1 = sizeof(rh1)
  int rhe2 = sizeof(rh2)
  while ResPos < ResLen
    @rh1=ResBase + ResPos
    UniSize = rh1.HeaderSize - rhe1
    Unisize=(Unisize + 3) and 0x7ffffffc 'dword align
    @Unihead=ResBase + ResPos + rhe1  'unicode/ordinal data then rh2
    @rh2 = @UniHead + UniSize - rhe2
    '
    ' Get the resource type
    word *w
    wchar st[64],sn[64]
    int i
    '
    @w=@unihead 'word overlay
    if w=0xffff
      ResType=w[2]
      st=RetResType(ResType)
      @ResTypeStr = @st
      HeadOffset=4 'dword
    else
      @ResTypeStr=@Unihead 'unicode
      ResType=@ResTypestr
      '
      'locate unicode null terminator
      i=0
      while w<>0
        i+=2 : @w+=2
      wend
      HeadOffset=i+2 'for start of ResName
    endif
    '
    ' Get the resource name
    word w at @unihead+HeadOffset
    if w=0xffff
      ResName = w[2]
      sn=str(ResName)
      @ResNameStr = @sn
    else
       @ResNameStr = @unihead+HeadOffset
       ResName    = @ResNameStr
    endif
    if Verbose
      string rt,rn
      rt=ResTypeStr
      rn=ResNameStr
      print "DataSize    = " rh1.DataSize cr
      print "HeaderSize  = " rh1.HeaderSize cr
      print "ResType     = " rt cr
      print "ResName     = " rn cr
      print "DataVersion = " rh2.DataVersion cr
      print "MemFlags    = " RetMemFlags(rh2.MemFlags) cr
      print "LangId      = " rh2.LangId cr
      print "Version     = " rh2.Version cr
      print "Charistics  = " rh2.Charistics cr
      print string(60, "-") cr
    endif
    '
    ResPos += rhe1 + UniSize 'ready for ResData
    ResData = ResBase+ResPos
    DataSpace = (rh1.DataSize+3) and 0x7ffffffc
    '
    ResPos+=DataSpace
    '
    if rh1.DataSize
      if not UpdateResourceW( hRes, ResType, ResName, rh2.LangId, ResData, rh1.DataSize)
        print "UpdateResource failed..." cr
        Result = 1
        exit while
      endif
    endif
  wend
  
  if not EndUpdateResource(hRes, Result)
    print "EndUpdateResource failed..." cr
    Result = 1
  endif
  return Result
end function




indexbase 1
int swd,lenw,ascw,ascn

sub SkipSpace(string*s, int*i)
==============================
  byte bb at strptr(s)
  do
    ascn=bb[i]
    select ascn
    case 0 : exit do
    'case 65 to 90 : ascn+=32 : exit do 'force lowercase
    case 33 to 255 : exit do
    end select
    i++
  loop
end sub


function GetWord(string*s, int*i) as string
===========================================
  byte bb at strptr(s)
  skipspace(s,i)
  swd=i
  do
    ascn=bb[i]
    select ascn
    case 0 to 32 : exit do
    case 34 : i=instr(i+1,s,chr(ascn))
      if i=0
        i=len(s)
      endif
    end select
    i++
  loop
  lenw=i-swd
  skipspace(s,i)
  if lenw>0
    return mid(s,swd,lenw)
  endif
end function


function CommandLineArgs() as string
====================================
  string s,command
  int i=1
  Command = (char*) GetCommandLine
  s=GetWord command,i 'step over command filepath\file
  SkipSpace command,i
  return mid Command, i
end function


function main() as int
======================
  int vb=0
  int i=1
  string s=lcase(CommandLineArgs())
  string resfile=getword(s,i)
  string tgtfile=getword(s,i)
  string opts=getword(s,i)
  '
  AttachConsole(-1) 'attach to console of parent process
  sys ho=GetStdHandle( STD_OUTPUT_HANDLE )
  if ho<>consout then consout=ho 'Windows10
  '
  if tgtfile
    if opts="-verbose"
      vb=1
    endif
    function = AddResources(resfile, tgtfile, vb)
  else
    print " LinkRes 2019" cr "  LinkRes  file.res  file.exe [-verbose]" cr
  endif
  FreeConsole
end function

return main()
