Browse Source

+ implement TWasmResourceWriter.PrescanResourceTree, based on the ELF
implementation. Call this on Write() to prepare resource stuff for writing.

Nikolay Nikolov 1 year ago
parent
commit
868d5f29c9
2 changed files with 70 additions and 2 deletions
  1. 3 0
      packages/fcl-res/fpmake.pp
  2. 67 2
      packages/fcl-res/src/wasmwriter.pp

+ 3 - 0
packages/fcl-res/fpmake.pp

@@ -126,6 +126,9 @@ begin
       with T.Dependencies do
       with T.Dependencies do
         begin
         begin
           AddUnit('resource');
           AddUnit('resource');
+          AddUnit('resourcetree');
+          AddUnit('strtable');
+          AddUnit('fpcrestypes');
           AddUnit('wasmconsts');
           AddUnit('wasmconsts');
           AddUnit('wasmtypes');
           AddUnit('wasmtypes');
         end;
         end;

+ 67 - 2
packages/fcl-res/src/wasmwriter.pp

@@ -24,10 +24,10 @@ interface
 
 
 {$IFDEF FPC_DOTTEDUNITS}
 {$IFDEF FPC_DOTTEDUNITS}
 uses
 uses
-  System.Classes, System.SysUtils, System.Resources.Resource, System.Resources.WebAssembly.Consts, System.Resources.WebAssembly.Types;
+  System.Classes, System.SysUtils, System.Resources.Resource, System.Resources.Tree, System.Resources.StringTable.Types, System.Resources.Types, System.Resources.WebAssembly.Consts, System.Resources.WebAssembly.Types;
 {$ELSE FPC_DOTTEDUNITS}
 {$ELSE FPC_DOTTEDUNITS}
 uses
 uses
-  Classes, SysUtils, resource, wasmconsts, wasmtypes;
+  Classes, SysUtils, resource, resourcetree, strtable, fpcrestypes, wasmconsts, wasmtypes;
 {$ENDIF FPC_DOTTEDUNITS}
 {$ENDIF FPC_DOTTEDUNITS}
 
 
 type
 type
@@ -38,7 +38,14 @@ type
   private
   private
     fExtensions : string;
     fExtensions : string;
     fDescription : string;
     fDescription : string;
+    fRoot : TRootResTreeNode;
+    fResStringTable : TResStringTable;
+    fDataAlignment : longword;
+    fDataCurOfs : longword;
     FWasmSections: array [TWasmSectionID] of TMemoryStream;
     FWasmSections: array [TWasmSectionID] of TMemoryStream;
+    function NextAligned(aBound, aValue : longword) : longword;
+    procedure PrescanResourceTree;
+    function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
     procedure WriteWasmSection(aStream: TStream; wsid: TWasmSectionID);
     procedure WriteWasmSection(aStream: TStream; wsid: TWasmSectionID);
     procedure WriteWasmSectionIfNotEmpty(aStream: TStream; wsid: TWasmSectionID);
     procedure WriteWasmSectionIfNotEmpty(aStream: TStream; wsid: TWasmSectionID);
   protected
   protected
@@ -67,6 +74,57 @@ end;
 
 
 { TWasmResourceWriter }
 { TWasmResourceWriter }
 
 
+function TWasmResourceWriter.NextAligned(aBound, aValue: longword): longword;
+var topad : longword;
+begin
+  Result:=aValue;
+  topad:=aBound-(aValue mod aBound);
+  if topad<>aBound then inc(Result,topad);
+end;
+
+procedure TWasmResourceWriter.PrescanResourceTree;
+begin
+  fResStringTable.Clear;
+  fRoot.SubDirRVA:=sizeof(TResHdr32)+sizeof(TResInfoNode32);
+  fResStringTable.StartOfs:=PrescanNode(fRoot,sizeof(TResInfoNode32));
+  if fResStringTable.Used then
+    fDataCurOfs:=NextAligned(fDataAlignment,fResStringTable.StartOfs+fResStringTable.Size)
+  else
+    fDataCurOfs:=fResStringTable.StartOfs;
+end;
+
+function TWasmResourceWriter.PrescanNode(aNode: TResourceTreeNode;
+  aNodeSize: longword): longword;
+var curofs : longword;
+    i : integer;
+    subnode : TResourceTreeNode;
+begin
+  if aNode.IsLeaf then
+  begin
+    Result:=aNode.SubDirRVA;
+    exit;
+  end;
+
+  if aNode.Desc.DescType=dtName then
+    aNode.NameRVA:=fResStringTable.Add(aNode.Desc.Name);
+
+  //first node subnodes begin at curofs (after all node headers)
+  curofs:=aNode.SubDirRva+(aNode.NamedCount+aNode.IDCount)*aNodeSize;
+  for i:=0 to aNode.NamedCount-1 do
+  begin
+    subnode:=aNode.NamedEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode,aNodeSize);
+  end;
+  for i:=0 to aNode.IDCount-1 do
+  begin
+    subnode:=aNode.IDEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode,aNodeSize);
+  end;
+  Result:=curofs;
+end;
+
 procedure TWasmResourceWriter.WriteWasmSection(aStream: TStream;
 procedure TWasmResourceWriter.WriteWasmSection(aStream: TStream;
   wsid: TWasmSectionID);
   wsid: TWasmSectionID);
 var
 var
@@ -99,6 +157,9 @@ procedure TWasmResourceWriter.Write(aResources: TResources; aStream: TStream);
 const
 const
   DataSegmentCount = 0;
   DataSegmentCount = 0;
 begin
 begin
+  fRoot:=TRootResTreeNode(GetTree(aResources));
+  PrescanResourceTree;
+
   WriteUleb(FWasmSections[wsiData],DataSegmentCount);
   WriteUleb(FWasmSections[wsiData],DataSegmentCount);
   WriteUleb(FWasmSections[wsiDataCount],DataSegmentCount);
   WriteUleb(FWasmSections[wsiDataCount],DataSegmentCount);
 
 
@@ -114,6 +175,9 @@ var
 begin
 begin
   fExtensions:='.o .or';
   fExtensions:='.o .or';
   fDescription:='WebAssembly resource writer';
   fDescription:='WebAssembly resource writer';
+  fResStringTable:=TResStringTable.Create;
+  fDataCurOfs:=0;
+  fDataAlignment:=4;
   for i in TWasmSectionID do
   for i in TWasmSectionID do
     FWasmSections[i] := TMemoryStream.Create;
     FWasmSections[i] := TMemoryStream.Create;
 end;
 end;
@@ -124,6 +188,7 @@ var
 begin
 begin
   for i in TWasmSectionID do
   for i in TWasmSectionID do
     FreeAndNil(FWasmSections[i]);
     FreeAndNil(FWasmSections[i]);
+  FreeAndNil(fResStringTable);
   inherited Destroy;
   inherited Destroy;
 end;
 end;