Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Support wwwroot and templates files from application resources
#1
When deploy intraweb application using wwwroot and templates, 2 extra folders wwwroot and templates shall deploy to same folder stored the application executable file.

Windows or Delphi application support resources stored in .EXE or .DLL / .BPL, it would be nice if IntraWeb can support loading those files from application resource to avoid deploy extra files at runtime.

I submitted a patch to support loading the templates from TResourceStream for your reference:

Code:
unit IWTemplateProcessorHTML.ResourcePatch;

interface

uses
  System.Classes, System.SysUtils;

var LoadTemplateEx: TFunc<string, TStream>;

implementation

uses
  System.Types,
  DDetours, IW.Common.StrLists, IW.Common.Stream, IW.Common.Strings,
  IW.Common.Threads, IWFilePath, IWGlobal, IWTemplateProcessorHTML;

type
  TIWTemplateCacheAccess = class
  private
    mFiles: TIWStringList;
    mLock: TIWSlimReaderWriter;
  end;

  TIWTemplateCacheHelper = class helper for TIWTemplateCache
    class function FindItem_Address: Pointer;
    class function Load_Address: Pointer;
    function Load_Patch(const aFileName: string; aRefreshFromFile: Boolean): TStream;
  end;

  TIWTemplateProcessorHTMLHelper = class helper for TIWTemplateProcessorHTML
    function Able_Patch: Boolean;
    function TemplatePathname_Patch: string;
  end;

var TIWTemplateProcessorHTML_Able: function(Self: TIWTemplateProcessorHTML): Boolean;

var TIWTemplateProcessorHTML_TemplatePathname: function(Self: TIWTemplateProcessorHTML): string;

var TIWTemplateCache_FindItem: function(Self: TIWTemplateCache;
  const aFileName: string): TIWTemplateCacheItem = nil;

var TIWTemplateCache_Load: function(Self: TIWTemplateCache;
  const aFileName: string; aRefreshFromFile: Boolean): TStream;

class function TIWTemplateCacheHelper.FindItem_Address: Pointer;
begin
  Result := @TIWTemplateCache.FindItem;
end;

class function TIWTemplateCacheHelper.Load_Address: Pointer;
begin
  Result := @TIWTemplateCache.Load;
end;

function TIWTemplateCacheHelper.Load_Patch(const aFileName: string;
  aRefreshFromFile: Boolean): TStream;
var
  LStream: TIWMemoryStream;
  Item: TIWTemplateCacheItem;
begin
  Result := nil;

  (* patched: if FileExists(aFilename) then*) begin
    (* patched: LStream := TIWMemoryStream.Create;
    try
      TIWMemoryStream(LStream).LoadFromFile(aFileName);
    except
      FreeAndNil(LStream);
      raise;
    end;*)

    var sFileName := ExtractFileName(aFileName);
    var o := LoadTemplateEx(sFileName);
    try
      LStream := TIWMemoryStream.CreateCopy(o, 0);
    finally
      o.Free;
    end;

    if aRefreshFromFile or not Able then Exit(LStream);

    Item := TIWTemplateCacheItem.Create(LStream);
    try
      // we are going to return a copy of the stream
      Result := LStream.Clone;
      // the original LStream is going to be stored in our cache
      TIWTemplateCacheAccess(Self).mLock.BeginWrite;
      try
        TIWTemplateCacheAccess(Self).mFiles.AddObject(aFileName, Item);  // add the stream to the cache
      finally
        TIWTemplateCacheAccess(Self).mLock.EndWrite;
      end;
    except
      FreeAndNil(Item);
      raise;
    end;
  end;
end;

function TIWTemplateProcessorHTMLHelper.Able_Patch: Boolean;
begin
(* patched
  Result := False;
  if Enabled then begin
    Result := Assigned(FOnBeforeProcess) or FileExists(TemplatePathname);
  end;
*)
  Result := True;
end;

function TIWTemplateProcessorHTMLHelper.TemplatePathname_Patch: string;
var
  S: string;
begin
  if Templates.Default = '' then begin
    // This is for subtemplates of regions. Right now containername returns:
    // formName.regionName. We rename it to formNameRegionName and that way
    // if no name is specified for the templates for regions, it uses this as
    // the default one
    if Assigned(Container) then begin
      // Remove the T from subclass name (AFTER the .)
      if (s <> '') and (Pos('.T', UpperCase(s)) > 0) then begin
        s := IWStringReplace(UpperCase(Container.ContainerClassName), '.T', '', []);
      end;
      s := IWStringReplace(Container.ContainerClassName, '.', '', []);
      // Remove T from it
      if IWStartsText('T', s) then begin
        Delete(s, 1, 1);
      end;
      s := s + '.html';
    end else begin
      s := '';
    end;
    (* patched if Assigned(gSC) and FileExists(gSC.TemplateDir + s) then *)begin
      FTemplates.Default := s;
    end;
  end;

  if Templates.Default <> '' then begin
    Result := Templates.Default;
  end;
  Result :=  TFilePath.Concat(gSC.TemplateDir, Result);
end;

initialization
  TIWTemplateProcessorHTML_Able := InterceptCreate(@TIWTemplateProcessorHTML.Able, @TIWTemplateProcessorHTML.Able_Patch);
  TIWTemplateProcessorHTML_TemplatePathname := InterceptCreate(@TIWTemplateProcessorHTML.TemplatePathname, @TIWTemplateProcessorHTML.TemplatePathname_Patch);
  TIWTemplateCache_Load := InterceptCreate(TIWTemplateCache.Load_Address, @TIWTemplateCache.Load_Patch);
finalization
  InterceptRemove(@TIWTemplateProcessorHTML_Able);
  InterceptRemove(@TIWTemplateProcessorHTML_TemplatePathname);
  InterceptRemove(@TIWTemplateCache_Load);
end.
Reply
#2
If you need the templates to be somehow safer and not be touched by end users, yes, that's a good solution
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)