| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 | {    Copyright (c) 1998-2008 by Florian Klaempfl    Handles the resource files handling    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************}unit comprsrc;{$i fpcdefs.inc}interface  uses    Systems, cstreams, cscript;type   tresoutput = (roRES, roOBJ);   tresourcefile = class(TAbstractResourceFile)   private      fname : ansistring;   protected      function SetupCompilerArguments(output: tresoutput; const OutName :      ansistring; respath: ansistring; out ObjUsed : boolean) : ansistring; virtual;   public      constructor Create(const fn : ansistring);override;      function Compile(output: tresoutput; const OutName: ansistring) : boolean; virtual;      procedure PostProcessResourcefile(const s : ansistring);virtual;      function IsCompiled(const fn : ansistring) : boolean;virtual;      procedure Collect(const fn : ansistring);virtual;      procedure EndCollect; virtual;   end;      TWinLikeResourceFile = class(tresourcefile)   private      fResScript : TScript;      fScriptName : ansistring;      fCollectCount : integer;   protected      function SetupCompilerArguments(output: tresoutput; const OutName :        ansistring; respath: ansistring; out ObjUsed : boolean) : ansistring; override;   public      constructor Create(const fn : ansistring);override;      destructor Destroy; override;      function Compile(output: tresoutput; const OutName: ansistring) : boolean; override;      function IsCompiled(const fn : ansistring) : boolean;override;      procedure Collect(const fn : ansistring);override;      procedure EndCollect; override;   end;   TJVMRawResourceFile = class(TWinLikeResourceFile)   private   protected   public      function Compile(output: tresoutput; const OutName: ansistring) : boolean; override;      function IsCompiled(const fn : ansistring) : boolean;override;   end;procedure CompileResourceFiles;procedure CollectResourceFiles;Var  ResCompiler : String;  RCCompiler  : String;  RCForceFPCRes : Boolean;implementationuses  SysUtils,  cutils,cfileutl,cclasses,  Globtype,Globals,Verbose,Fmodule, comphook,cpuinfo,rescmn;{****************************************************************************                              TRESOURCEFILE****************************************************************************}constructor tresourcefile.create(const fn : ansistring);begin  fname:=fn;end;procedure tresourcefile.PostProcessResourcefile(const s : ansistring);beginend;function tresourcefile.IsCompiled(const fn: ansistring): boolean;begin  Result:=CompareText(ExtractFileExt(fn), target_info.resobjext) = 0;end;procedure tresourcefile.Collect(const fn: ansistring);begin  if fn='' then    exit;  fname:=fn;  Compile(roOBJ, ChangeFileExt(fn, target_info.resobjext));end;procedure tresourcefile.EndCollect;beginend;function tresourcefile.SetupCompilerArguments(output: tresoutput; const OutName  : ansistring; respath: ansistring; out ObjUsed : boolean) : ansistring;var  s : TCmdStr;begin  if output=roRES then    begin      if RCForceFPCRes then        s:=FPCResRCArgs      else        s:=target_res.rccmd;      Replace(s,'$RES',maybequoted(OutName));      Replace(s,'$RC',maybequoted(fname));      ObjUsed:=False;    end  else    begin      s:=target_res.rescmd;      ObjUsed:=(pos('$OBJ',s)>0);      Replace(s,'$OBJ',maybequoted(OutName));      Replace(s,'$RES',maybequoted(fname));    end;  Result:=s;end;function tresourcefile.compile(output: tresoutput; const OutName: ansistring)  : boolean;  Function SelectBin(Const Bin1,Bin2 : String) : String;  begin    If (Bin1<>'') then      SelectBin:=Bin1    else      SelectBin:=Bin2;  end;var  respath,  s,  bin,  resbin   : TCmdStr;  resfound,  objused  : boolean;begin  Result:=true;  if output=roRES then    if RCForceFPCRes then      Bin:=SelectBin(RCCompiler,FPCResUtil)    else      Bin:=SelectBin(RCCompiler,target_res.rcbin)  else    Bin:=SelectBin(ResCompiler,target_res.resbin);  if bin='' then  begin    Result:=false;    exit;  end;  resfound:=false;  if utilsdirectory<>'' then    resfound:=FindFile(utilsprefix+bin+source_info.exeext,utilsdirectory,false,resbin);  if not resfound then    begin      resfound:=FindExe(utilsprefix+bin,false,resbin);      if not resfound and (utilsprefix<>'') and ( (output=roRES) or (Pos('$ARCH', target_res.rescmd)<>0) ) then        { Search for resource compiler without utilsprefix, if RC->RES compiler is called }        { or RES->OBJ compiler supports different architectures. }        resfound:=FindExe(bin,false,resbin);    end;  { get also the path to be searched for the windres.h }  respath:=ExtractFilePath(resbin);  if (not resfound) and not(cs_link_nolink in current_settings.globalswitches) then   begin     Message1(exec_e_res_not_found, utilsprefix+bin+source_info.exeext);     current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];     Result:=false;   end;  s:=SetupCompilerArguments(output,OutName,respath,objused);{ Execute the command }{ Always try to compile resources. but don't complain if cs_link_nolink }  if resfound then   begin     Message1(exec_i_compilingresource,fname);     Message2(exec_d_resbin_params,resbin,s);     FlushOutput;     try       if RequotedExecuteProcess(resbin,s) <> 0 then       begin         if not (cs_link_nolink in current_settings.globalswitches) then           Message(exec_e_error_while_compiling_resources);         current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];         Result:=false;       end;     except       on E:EOSError do       begin         if not (cs_link_nolink in current_settings.globalswitches) then           Message1(exec_e_cant_call_resource_compiler, resbin);         current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];         Result:=false;       end     end;    end;  { Update asmres when externmode is set and resource compiling failed }  if (not Result) and (cs_link_nolink in current_settings.globalswitches) then    AsmRes.AddLinkCommand(resbin,s,OutName);  if Result and (output=roOBJ) and ObjUsed then    current_module.linkunitofiles.add(OutName,link_always);end;constructor TWinLikeResourceFile.Create(const fn : ansistring);begin  inherited Create(fn);  fResScript:=nil;  fCollectCount:=0;  if (tf_use_8_3 in target_info.flags) then    fScriptName:=ChangeFileExt(fn,'.rls')  else    fScriptName:=ChangeFileExt(fn,'.reslst');end;destructor TWinLikeResourceFile.Destroy;begin  if fResScript<>nil then    fResScript.Free;  inherited;end;function TWinLikeResourceFile.SetupCompilerArguments(output: tresoutput; const  OutName : ansistring; respath : ansistring; out ObjUsed : boolean) : ansistring;var  srcfilepath,  preprocessorbin,  s : TCmdStr;  arch,  subarch: ansistring;  function WindresFileName(filename: TCmdStr): TCmdStr;  // to be on the safe side, for files that are passed to the preprocessor,  // only give short file names with forward slashes to windres  var    i: longint;  begin    Result := GetShortName(filename);    for I:=1 to Length(Result) do    if Result[I] in AllowDirectorySeparators then      Result[i]:='/';    Result:=maybequoted(Result);  end;begin  srcfilepath:=ExtractFilePath(current_module.mainsource);  if output=roRES then    begin      if RCForceFPCRes then        s:=FPCResRCArgs      else        s:=target_res.rccmd;      if (target_res.rcbin = 'windres') and not RCForceFPCRes then        Replace(s,'$RC',WindresFileName(fname))      else        Replace(s,'$RC',maybequoted(fname));      Replace(s,'$RES',maybequoted(OutName));      ObjUsed:=False;    end  else    begin      s:=target_res.rescmd;      if (res_external_file in target_res.resflags) then        ObjUsed:=false      else        ObjUsed:=(pos('$OBJ',s)>0);      Replace(s,'$OBJ',maybequoted(OutName));      subarch:='all';      arch:=cpu2str[target_cpu];      if (target_info.cpu=systems.cpu_arm) then        begin          //Differentiate between arm and armeb          if (target_info.endian=endian_big) then            arch:=arch+'eb';        end;      if target_info.cpu=systems.cpu_powerpc64 then        begin          { differentiate between ppc64 and ppc64le }          if target_info.endian=endian_little then            arch:=arch+'le';        end;      Replace(s,'$ARCH',arch);      if target_info.system=system_arm_ios then        subarch:=lower(cputypestr[current_settings.cputype]);      Replace(s,'$SUBARCH',subarch);      case target_info.endian of        endian_little : Replace(s,'$ENDIAN','littleendian');        endian_big : Replace(s,'$ENDIAN','bigendian');      end;      //call resource compiler with debug switch      if (status.verbosity and V_Debug)<>0 then        Replace(s,'$DBG','-v')      else        Replace(s,'$DBG','');      if fCollectCount=0 then        s:=s+' '+maybequoted(fname)      else        s:=s+' '+maybequoted('@'+fScriptName);    end;  { windres doesn't like empty include paths }  if respath='' then    respath:='.';  Replace(s,'$INC',maybequoted(respath));  if (output=roRes) and (target_res.rcbin='windres') and not RCForceFPCRes then  begin    { try to find a preprocessor }    preprocessorbin := respath+'cpp'+source_info.exeext;    if FileExists(preprocessorbin,true) then      s:='--preprocessor='+preprocessorbin+' '+s;    if (srcfilepath<>'') then      s:='--include '+WindresFileName(srcfilepath)+' '+s;  end;  Result:=s;end;function TWinLikeResourceFile.compile(output: tresoutput;  const OutName: ansistring) : boolean;begin  Result:=inherited compile(output,OutName);  //delete fpc-res.lst file if things went well  if Result and (output=roOBJ) then    DeleteFile(fScriptName);end;function TWinLikeResourceFile.IsCompiled(const fn: ansistring): boolean;const  ResSignature : array [1..32] of byte =  ($00,$00,$00,$00,$20,$00,$00,$00,$FF,$FF,$00,$00,$FF,$FF,$00,$00,   $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00);  knownexts : array[1..4] of string[4] = ('.lfm', '.dfm', '.xfm', '.tlb');var  f : file;  oldfmode : byte;  buf: array[1..32] of byte;  i: longint;  ext : shortstring;begin  ext:=lower(ExtractFileExt(fn));  Result:=CompareText(ext, target_info.resext) = 0;  if not Result then    for i:=1 to high(knownexts) do    begin      Result:=CompareText(ext, knownexts[i]) = 0;      if Result then break;    end;  if Result or not FileExists(fn, False) then exit;  oldfmode:=Filemode;  Filemode:=0;  assign(f,fn);  reset(f,1);  BlockRead(f, buf, SizeOf(buf), i);  close(f);  Filemode:=oldfmode;    if i<>SizeOf(buf) then    exit;  for i:=1 to 32 do    if buf[i]<>ResSignature[i] then      exit;        Result:=True;end;procedure TWinLikeResourceFile.Collect(const fn: ansistring);begin  if fResScript=nil then    fResScript:=TScript.Create(fScriptName);  fResScript.Add(maybequoted_for_script(fn,script_fpcres));  inc(fCollectCount);end;procedure TWinLikeResourceFile.EndCollect;begin  if fResScript<>nil then  begin    fResScript.WriteToDisk;    FreeAndNil(fResScript);    Compile(roOBJ,ChangeFileExt(fname,target_info.resobjext));  end;end;{****************************************************************************                              TJVMRawResourceFile****************************************************************************}function TJVMRawResourceFile.Compile(output: tresoutput; const OutName: ansistring): boolean;  begin    if output<>roOBJ then      internalerror(2011081703);    result:=inherited;  end;function TJVMRawResourceFile.IsCompiled(const fn: ansistring): boolean;  begin    internalerror(2011081704);    result:=true;  end;function CopyResFile(inf,outf : TCmdStr) : boolean;var  src,dst : TCCustomFileStream;begin  { Copy .res file to units output dir. }  Result:=false;  src:=CFileStreamClass.Create(inf,fmOpenRead or fmShareDenyNone);  if CStreamError<>0 then    begin      Message1(exec_e_cant_open_resource_file, src.FileName);      Include(current_settings.globalswitches, cs_link_nolink);      exit;    end;  dst:=CFileStreamClass.Create(current_module.outputpath+outf,fmCreate);  if CStreamError<>0 then    begin      Message1(exec_e_cant_write_resource_file, dst.FileName);      Include(current_settings.globalswitches, cs_link_nolink);      exit;    end;  dst.CopyFrom(src,src.Size);  dst.Free;  src.Free;  Result:=true;end; procedure CompileResourceFiles;var  resourcefile : tresourcefile;  res: TCmdStrListItem;  p,s : TCmdStr;  outfmt : tresoutput;begin  { Don't do anything for systems supporting resources without using resource    file classes (e.g. Mac OS). They process resources elsewhere. }  if ((target_info.res<>res_none) and (target_res.resourcefileclass=nil)) or     (res_no_compile in target_res.resflags) then    exit;  p:=ExtractFilePath(ExpandFileName(current_module.mainsource));  res:=TCmdStrListItem(current_module.ResourceFiles.First);  while res<>nil do    begin      if target_info.res=res_none then        Message(scan_e_resourcefiles_not_supported);      s:=res.FPStr;      if not path_absolute(s) then        s:=p+s;      if not FileExists(s, True) then        begin          Message1(exec_e_cant_open_resource_file, s);          Include(current_settings.globalswitches, cs_link_nolink);          exit;        end;      resourcefile:=TResourceFile(resinfos[target_info.res]^.resourcefileclass.create(s));      if resourcefile.IsCompiled(s) then        begin          resourcefile.free;          if AnsiCompareFileName(IncludeTrailingPathDelimiter(ExpandFileName(current_module.outputpath)), p) <> 0 then            begin              { Copy .res file to units output dir. Otherwise .res file will not be found                when only compiled units path is available }              res.FPStr:=ExtractFileName(res.FPStr); //store file name only in PPU.              if not CopyResFile(s,res.FPStr) then exit;            end;        end      else        begin          res.FPStr:=ExtractFileName(res.FPStr);          if (target_res.rcbin='') and (RCCompiler='') then            begin              { if target does not have .rc to .res compiler, create obj }              outfmt:=roOBJ;              res.FPStr:=ChangeFileExt(res.FPStr,target_info.resobjext);            end          else            begin              outfmt:=roRES;              res.FPStr:=ChangeFileExt(res.FPStr,target_info.resext);            end;          resourcefile.compile(outfmt, current_module.outputpath+res.FPStr);          resourcefile.free;        end;      res:=TCmdStrListItem(res.Next);    end;end;procedure CollectResourceFiles;var  resourcefile : tresourcefile;    procedure ProcessModule(u : tmodule);  var    res : TCmdStrListItem;    s   : TCmdStr;  begin    res:=TCmdStrListItem(u.ResourceFiles.First);    while assigned(res) do      begin        if path_absolute(res.FPStr) then          s:=res.FPStr        else          begin            s:=u.path+res.FPStr;            if not FileExists(s,True) then              s:=u.outputpath+res.FPStr;          end;        resourcefile.Collect(s);        res:=TCmdStrListItem(res.Next);      end;  end;  var  hp : tused_unit;  s : TCmdStr;begin  if (target_info.res=res_none) or ((target_res.resbin='')    and (ResCompiler='')) then      exit;//  if cs_link_nolink in current_settings.globalswitches then//    exit;  s:=ChangeFileExt(current_module.ppufilename,target_info.resobjext);  if (res_arch_in_file_name in target_res.resflags) then    s:=ChangeFileExt(s,'.'+cpu2str[target_cpu]+target_info.resobjext);  resourcefile:=TResourceFile(resinfos[target_info.res]^.resourcefileclass.create(s));  hp:=tused_unit(usedunits.first);  while assigned(hp) do    begin      ProcessModule(hp.u);      hp:=tused_unit(hp.next);    end;  ProcessModule(current_module);  { Finish collection }  resourcefile.EndCollect;  resourcefile.free;end;procedure initglobals;begin  ResCompiler:='';  RCCompiler:='';  RCForceFPCRes:=false;end;initialization  register_initdone_proc(@initglobals,nil);end.
 |