'
'==============================================================================
'                         WIN32 Resource file format
'==============================================================================
'
'Offset		Field		Datatype			Description
'-------------------------------------------------------------------------------
'0  		DataSize  	DWORD
'				4 bytes,
'                               32 bit unsigned integer		The size of the data that
'								follows the header
'                                                               (not including any padding).
'-------------------------------------------------------------------------------
'4 		HeaderSize	DWORD
'				4 bytes,
'                               32 bit unsigned integer		The size of the header structure.
'-------------------------------------------------------------------------------
'8		ResType		Ordinal or UNICODE string
'				Array of 16 bit unsigned
'                               integers (2 bytes each)		Resource Type ID (standard or custom).
'-------------------------------------------------------------------------------
'OfsOf(ResType)
'+SizeOf(ResType)
'+Padding	ResName		Ordinal or UNICODE string
'				Array of 16 bit unsigned
'                                integers (2 bytes each)	Resource name.
'-------------------------------------------------------------------------------
'OfsOf(ResName)							Determines the format of
'+SizeOf(ResName)                                               the information within the
'+Padding	DataVersion	DWORD                           resource header that follows.
'				4 bytes,                        Not currently used.
'                               32 bit unsigned integer		Should be zeroed.
'-------------------------------------------------------------------------------
'OfsOf(DataVersion)+4
'	       MemoryFlags	WORD
'				2 bytes,
'                                16 bit unsigned integer	The state of the resource.
'-------------------------------------------------------------------------------
'OfsOf(MemoryFlags)+2
'	       LanguageID	WORD
'				2 bytes,
'                                16 bit unsigned integer	The language that the strings
'								are written with.
'-------------------------------------------------------------------------------
'OfsOf(LanguageID)+2
'	       Version		DWORD
'				4 bytes,
'                                32 bit unsigned integer	It has no significance to the
'								system. Used by resource editors.
'                                                               Usually zeroed.
'-------------------------------------------------------------------------------
'OfsOf(Version)+4
'	       Characteristics	DWORD
'				4 bytes,
'                                32 bit unsigned integer	It has no significance to the
'								system. Used by resource editors.
'                                                               Usually zeroed.
'-------------------------------------------------------------------------------
' This line needs to be added to the Bcx file for TCC
'-------------------------------------------------------------------------------
'$HEADER
'#ifdef __TINYC__
'int dummy __attribute__ ((section(".rsrc")));
'#endif
'$HEADER
'-------------------------------------------------------------------------------
$TURBO 64

TYPE ResHead1
   DataSize    AS DWORD
   HeaderSize  AS DWORD
END TYPE

TYPE ResHead2
   DataVersion AS DWORD
   MemFlags    AS WORD
   LangId      AS WORD
   Version     AS DWORD
   Charistics  AS DWORD
END TYPE

GLOBAL Verbose

'************************ Main ************************
IF ARGC > 2 THEN
   IF ARGC = 4 THEN
      IF ARGV$[3] = "-verbose" THEN Verbose = TRUE
   END IF
   ' argv$[1] = res
   ' argv$[2] = exe
   FUNCTION = AddRes2File (argv$[1], argv$[2])
ELSE
   PRINT " LinkRes2Exe 1.02  (c)2006 by Mike Henning"
   PRINT " Usage: LinkRes2Exe  file.res  file.exe [-verbose]"
END IF

'******************************************************



FUNCTION AddRes2File (ResFile$, TgtFile$)

   DIM RAW h AS HANDLE
   DIM RAW rh1 AS ResHead1
   DIM RAW rh2 AS ResHead2 PTR
   DIM RAW ResName AS DWORD, szResName$
   DIM RAW ResType AS DWORD, szResType$
   DIM RAW unihead = NULL AS PCHAR
   DIM RAW rdata   = NULL AS PCHAR
   DIM RAW HeadOffset, UniSize
   DIM RAW FileEnd, FilePos = 0, Result = 0

   
   IF NOT EXIST(ResFile$) THEN
      PRINT "File not found: ", ResFile$
      FUNCTION = 1
   ELSEIF NOT EXIST(TgtFile$) THEN
      PRINT "File not found: ", TgtFile$
      FUNCTION = 1
   END IF   

   h = BeginUpdateResource(TgtFile$, TRUE)  ' File to add the resource to
   IF h = NULL THEN
      PRINT "BeginUpdateResource failed..."
      FUNCTION = 1
   END IF

   FileEnd = LOF(ResFile$)

   OPEN ResFile$ FOR BINARY INPUT AS FP1

   WHILE FilePos < FileEnd

      GET$ FP1, &rh1, SIZEOF(rh1)
      INCR FilePos, SIZEOF(rh1)

      UniSize = dwAlign(rh1.HeaderSize - SIZEOF(rh1))
      unihead = (PCHAR)realloc(unihead, UniSize)
      GET$ FP1, unihead, UniSize
      INCR FilePos, UniSize

      rh2 = (LPRESHEAD2)&unihead[UniSize-SIZEOF(*rh2)]

      ' --------------------------------------------
      ' Get the resource type
      ' --------------------------------------------
      HeadOffset = IsUnicode(unihead$)

      IF HeadOffset = 0 THEN
         ResType    = HIWORD(*(DWORD*)unihead)
         szResType$ = RetResType$(ResType)
         HeadOffset = SIZEOF(DWORD)
      ELSE
         szResType$ = WIDETOANSI$((LPWSTR)unihead)
         ResType    = (DWORD)szResType
      END IF

      ' --------------------------------------------
      ' Get the resource name
      ' --------------------------------------------
      IF IsUnicode(&unihead[HeadOffset]) = 0 THEN
         ResName    = HIWORD(*(DWORD*)(unihead + HeadOffset))
         szResName$ = STR$(ResName)
      ELSE
         szResName$ = WIDETOANSI$((LPWSTR)(&unihead[HeadOffset]))
         ResName    = (DWORD)szResName
      END IF

      IF Verbose THEN
         PRINT "DataSize    =" , rh1.DataSize
         PRINT "HeaderSize  =" , rh1.HeaderSize
         PRINT "ResType     = ", szResType$
         PRINT "ResName     = ", szResName$
         PRINT "DataVersion =" , rh2->DataVersion
         PRINT "MemFlags    = ", RetMemFlags$(rh2->MemFlags)
         PRINT "LangId      =" , rh2->LangId
         PRINT "Version     =" , rh2->Version
         PRINT "Charistics  =" , rh2->Charistics

         PRINT STRING$(60, ASC("-"))
      END IF

      HeadOffset = dwAlign(rh1.DataSize)

      rdata = (PCHAR)realloc(rdata, HeadOffset)
      GET$ FP1, rdata$, HeadOffset
      INCR FilePos, HeadOffset

      IF rh1.DataSize THEN
         IF UpdateResource( h, (PCHAR)ResType, (PCHAR)ResName, rh2->LangId, rdata$, rh1.DataSize) = 0 THEN
            PRINT "UpdateResource failed..."
            Result = 1
            EXIT LOOP
         END IF
      END IF

   WEND

   FREE unihead
   FREE rdata
   CLOSE FP1

   IF NOT EndUpdateResource(h, Result) THEN
      PRINT "EndUpdateResource failed..."
      Result = 1
   END IF

   FUNCTION = Result
END FUNCTION




FUNCTION RetResType (ResType) AS LPCSTR

   SELECT CASE ResType

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

   END SELECT

   FUNCTION = "Unknown"
END FUNCTION




FUNCTION RetMemFlags (flags) AS LPSTR

   LOCAL MemFlags$

   SELECT CASE BAND flags
      CASE 0x0010 : MemFlags$ = "MOVEABLE"
      CASE 0x0020 : CONCAT(MemFlags$, " PURE")
      CASE 0x0040 : CONCAT(MemFlags$, " PRELOAD")
      CASE 0x1000 : CONCAT(MemFlags$, " DISCARDABLE")
   END SELECT

   IF flags = 0 THEN MemFlags$ = "None"

   FUNCTION = MemFlags
END FUNCTION


'----------------------------------------------------------
' Returns 0 if sz$ is an ordinal (numeric id)
' Returns a DWORD aligned length if a unicode name
'----------------------------------------------------------
FUNCTION IsUnicode(sz$) AS DWORD

   IF LOWORD(*(DWORD*)sz) = 0xFFFF THEN
      FUNCTION = 0
   END IF

   FUNCTION = dwAlign(2 + (2 * wcslen((LPCWSTR)sz)))
END FUNCTION




FUNCTION dwAlign (ul AS DWORD) AS DWORD
   ul+=3
   ul>>=2
   ul<<=2
   FUNCTION = ul
END FUNCTION
