123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 |
- {
- Copyright (c) 2013-2016 by Free Pascal development team
- This unit implements the loading and searching of package files
- 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 fpcp;
- {$i fpcdefs.inc}
- interface
- uses
- cclasses,cstreams,
- globtype,
- pcp,finput,fpkg;
- type
- tpcppackage=class(tpackage)
- private
- loaded : boolean;
- pcpfile : tpcpfile;
- private
- function openpcp:boolean;
- function search_package(ashortname:boolean):boolean;
- function search_package_file:boolean;
- procedure setfilename(const fn:string;allowoutput:boolean);
- procedure writecontainernames;
- procedure writecontainedunits;
- procedure writerequiredpackages;
- procedure writepputable;
- procedure writeppudata;
- procedure readcontainernames;
- procedure readcontainedunits;
- procedure readrequiredpackages;
- procedure readpputable;
- public
- constructor create(const pn:string);
- destructor destroy; override;
- procedure loadpcp;
- procedure savepcp;
- function getmodulestream(module:tmodulebase):tcstream;
- procedure initmoduleinfo(module:tmodulebase);
- procedure addunit(module:tmodulebase);
- procedure add_required_package(pkg:tpackage);
- end;
- implementation
- uses
- sysutils,
- cfileutl,cutils,
- systems,globals,version,
- verbose,
- ppu,
- entfile,pkgutil;
- { tpcppackage }
- function tpcppackage.openpcp: boolean;
- var
- pcpfiletime : longint;
- begin
- result:=false;
- Message1(package_t_pcp_loading,pcpfilename);
- { Get pcpfile time (also check if the file exists) }
- pcpfiletime:=getnamedfiletime(pcpfilename);
- if pcpfiletime=-1 then
- exit;
- { Open the pcpfile }
- Message1(package_u_pcp_name,pcpfilename);
- pcpfile:=tpcpfile.create(pcpfilename);
- if not pcpfile.openfile then
- begin
- pcpfile.free;
- pcpfile:=nil;
- Message(package_u_pcp_file_too_short);
- exit;
- end;
- { check for a valid PPU file }
- if not pcpfile.checkpcpid then
- begin
- pcpfile.free;
- pcpfile:=nil;
- Message(package_u_pcp_invalid_header);
- exit;
- end;
- { check for allowed PCP versions }
- if not (pcpfile.getversion=CurrentPCPVersion) then
- begin
- Message1(package_u_pcp_invalid_version,tostr(pcpfile.getversion));
- pcpfile.free;
- pcpfile:=nil;
- exit;
- end;
- { check the target processor }
- if tsystemcpu(pcpfile.header.common.cpu)<>target_cpu then
- begin
- pcpfile.free;
- pcpfile:=nil;
- Message(package_u_pcp_invalid_processor);
- exit;
- end;
- { check target }
- if tsystem(pcpfile.header.common.target)<>target_info.system then
- begin
- pcpfile.free;
- pcpfile:=nil;
- Message(package_u_pcp_invalid_target);
- exit;
- end;
- {$ifdef cpufpemu}
- { check if floating point emulation is on?
- fpu emulation isn't unit levelwise because it affects calling convention }
- if ((uf_fpu_emulation and pcpfile.header.common.flags)<>0) <>
- (cs_fp_emulation in current_settings.moduleswitches) then
- begin
- pcpfile.free;
- pcpfile:=nil;
- Message(package_u_pcp_invalid_fpumode);
- exit;
- end;
- {$endif cpufpemu}
- { Show Debug info }
- Message1(package_u_pcp_time,filetimestring(pcpfiletime));
- Message1(package_u_pcp_flags,tostr(pcpfile.header.common.flags{flags}));
- Message1(package_u_pcp_crc,hexstr(pcpfile.header.checksum,8));
- (*Message1(package_u_pcp_crc,hexstr(ppufile.header.interface_checksum,8)+' (intfc)');
- Message1(package_u_pcp_crc,hexstr(ppufile.header.indirect_checksum,8)+' (indc)');
- Comment(V_used,'Number of definitions: '+tostr(ppufile.header.deflistsize));
- Comment(V_used,'Number of symbols: '+tostr(ppufile.header.symlistsize));
- do_compile:=false;*)
- result:=true;
- end;
- function tpcppackage.search_package(ashortname:boolean):boolean;
- var
- singlepathstring,
- filename : TCmdStr;
- function package_exists(const ext:string;var foundfile:TCmdStr):boolean;
- begin
- if CheckVerbosity(V_Tried) then
- Message1(package_t_packagesearch,Singlepathstring+filename+ext);
- result:=FindFile(filename+ext,singlepathstring,true,foundfile);
- end;
- function package_search_path(const s:TCmdStr):boolean;
- var
- found : boolean;
- hs : TCmdStr;
- begin
- found:=false;
- singlepathstring:=FixPath(s,false);
- { Check for package file }
- { TODO }
- found:=package_exists({target_info.pkginfoext}'.pcp',hs);
- if found then
- begin
- setfilename(hs,false);
- found:=openpcp;
- end;
- result:=found;
- end;
- function search_path_list(list:TSearchPathList):boolean;
- var
- hp : TCmdStrListItem;
- found : boolean;
- begin
- found:=false;
- hp:=TCmdStrListItem(list.First);
- while assigned(hp) do
- begin
- found:=package_search_path(hp.Str);
- if found then
- break;
- hp:=TCmdStrListItem(hp.next);
- end;
- result:=found;
- end;
- begin
- filename:=packagename^;
- result:=search_path_list(packagesearchpath);
- end;
- function tpcppackage.search_package_file: boolean;
- var
- found : boolean;
- begin
- found:=false;
- if search_package(false) then
- found:=true;
- if not found and
- (length(packagename^)>8) and
- search_package(true) then
- found:=true;
- result:=found;
- end;
- procedure tpcppackage.setfilename(const fn:string;allowoutput:boolean);
- var
- p,n : tpathstr;
- begin
- p:=FixPath(ExtractFilePath(fn),false);
- n:=FixFileName(ChangeFileExt(ExtractFileName(fn),''));
- { pcp name }
- if allowoutput then
- if (OutputUnitDir<>'') then
- p:=OutputUnitDir
- else
- if (OutputExeDir<>'') then
- p:=OutputExeDir;
- pcpfilename:=p+n+{target_info.pkginfoext}'.pcp';
- end;
- procedure tpcppackage.writecontainernames;
- begin
- pcpfile.putstring(pplfilename);
- //pcpfile.putstring(ppafilename);
- pcpfile.writeentry(ibpackagefiles);
- end;
- procedure tpcppackage.writecontainedunits;
- var
- p : pcontainedunit;
- i : longint;
- begin
- pcpfile.putlongint(containedmodules.count);
- pcpfile.writeentry(ibstartcontained);
- { for now we write the unit name and the ppu file name }
- for i:=0 to containedmodules.count-1 do
- begin
- p:=pcontainedunit(containedmodules.items[i]);
- pcpfile.putstring(p^.module.modulename^);
- pcpfile.putstring(p^.ppufile);
- end;
- pcpfile.writeentry(ibendcontained);
- end;
- procedure tpcppackage.writerequiredpackages;
- var
- i : longint;
- begin
- pcpfile.putlongint(requiredpackages.count);
- pcpfile.writeentry(ibstartrequireds);
- for i:=0 to requiredpackages.count-1 do
- begin
- pcpfile.putstring(requiredpackages.NameOfIndex(i));
- end;
- pcpfile.writeentry(ibendrequireds);
- end;
- procedure tpcppackage.writepputable;
- var
- module : pcontainedunit;
- i : longint;
- begin
- { no need to write the count again; it's the same as for the contained units }
- for i:=0 to containedmodules.count-1 do
- begin
- module:=pcontainedunit(containedmodules[i]);
- pcpfile.putlongint(module^.offset);
- pcpfile.putlongint(module^.size);
- end;
- pcpfile.writeentry(ibpputable);
- end;
- procedure tpcppackage.writeppudata;
- const
- align: array[0..15] of byte = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
- var
- i,
- pos,
- rem : longint;
- module : pcontainedunit;
- stream : TCStream;
- begin
- pcpfile.flush;
- for i:=0 to containedmodules.count-1 do
- begin
- module:=pcontainedunit(containedmodules[i]);
- pos:=pcpfile.position;
- { align to 16 byte so that it can be nicely viewed in hex editors;
- maybe we could also use 512 byte alignment instead }
- rem:=$f-(pos and $f);
- pcpfile.stream.write(align[0],rem+1);
- pcpfile.flush;
- module^.offset:=pcpfile.position;
- { retrieve substream for the current position }
- stream:=pcpfile.substream(module^.offset,-1);
- rewriteppu(module^.module.ppufilename,stream);
- module^.size:=stream.position;
- stream.free;
- end;
- pos:=pcpfile.position;
- { align to 16 byte so that it can be nicely viewed in hex editors;
- maybe we could also use 512 byte alignment instead }
- rem:=$f-(pos and $f);
- pcpfile.stream.write(align[0],rem+1);
- end;
- procedure tpcppackage.readcontainernames;
- begin
- if pcpfile.readentry<>ibpackagefiles then
- begin
- message(package_f_pcp_read_error);
- internalerror(2020100818);
- end;
- pplfilename:=pcpfile.getstring;
- message1(package_u_ppl_filename,pplfilename);
- end;
- procedure tpcppackage.readcontainedunits;
- var
- cnt,i : longint;
- name,path : string;
- p : pcontainedunit;
- begin
- if pcpfile.readentry<>ibstartcontained then
- begin
- message(package_f_pcp_read_error);
- internalerror(2020100819);
- end;
- cnt:=pcpfile.getlongint;
- if pcpfile.readentry<>ibendcontained then
- begin
- message(package_f_pcp_read_error);
- internalerror(2020100820);
- end;
- for i:=0 to cnt-1 do
- begin
- name:=pcpfile.getstring;
- path:=pcpfile.getstring;
- new(p);
- p^.module:=nil;
- p^.ppufile:=path;
- p^.offset:=0;
- p^.size:=0;
- containedmodules.add(name,p);
- message1(package_u_contained_unit,name);
- end;
- end;
- procedure tpcppackage.readrequiredpackages;
- var
- cnt,i : longint;
- name : string;
- begin
- if pcpfile.readentry<>ibstartrequireds then
- begin
- message(package_f_pcp_read_error);
- internalerror(2014110901);
- end;
- cnt:=pcpfile.getlongint;
- if pcpfile.readentry<>ibendrequireds then
- begin
- message(package_f_pcp_read_error);
- internalerror(2014110902);
- end;
- for i:=0 to cnt-1 do
- begin
- name:=pcpfile.getstring;
- requiredpackages.add(name,nil);
- message1(package_u_required_package,name);
- end;
- end;
- procedure tpcppackage.readpputable;
- var
- module : pcontainedunit;
- i : longint;
- begin
- if pcpfile.readentry<>ibpputable then
- begin
- message(package_f_pcp_read_error);
- internalerror(2015103001);
- end;
- for i:=0 to containedmodules.count-1 do
- begin
- module:=pcontainedunit(containedmodules[i]);
- module^.offset:=pcpfile.getlongint;
- module^.size:=pcpfile.getlongint;
- end;
- end;
- constructor tpcppackage.create(const pn: string);
- begin
- inherited create(pn);
- setfilename(pn+'.ppk',true);
- end;
- destructor tpcppackage.destroy;
- begin
- pcpfile.free;
- inherited destroy;
- end;
- procedure tpcppackage.loadpcp;
- var
- newpackagename : string;
- begin
- if loaded then
- exit;
- if not search_package_file then
- begin
- Message1(package_f_cant_find_pcp,realpackagename^);
- exit;
- end
- else
- Message1(package_u_pcp_found,realpackagename^);
- if not assigned(pcpfile) then
- internalerror(2013053101);
- if pcpfile.readentry<>ibpackagename then
- Message1(package_f_cant_read_pcp,realpackagename^);
- newpackagename:=pcpfile.getstring;
- if upper(newpackagename)<>packagename^ then
- Comment(V_Error,'Package was renamed: '+realpackagename^);
- readcontainernames;
- readrequiredpackages;
- readcontainedunits;
- readpputable;
- end;
- procedure tpcppackage.savepcp;
- var
- tablepos,
- oldpos : longint;
- begin
- { create new ppufile }
- pcpfile:=tpcpfile.create(pcpfilename);
- if not pcpfile.createfile then
- Message2(package_f_cant_create_pcp,realpackagename^,pcpfilename);
- pcpfile.putstring(realpackagename^);
- pcpfile.writeentry(ibpackagename);
- writecontainernames;
- writerequiredpackages;
- writecontainedunits;
- { the offsets and the contents of the ppus are not crc'd }
- pcpfile.do_crc:=false;
- pcpfile.flush;
- tablepos:=pcpfile.position;
- { this will write a table with empty entries }
- writepputable;
- pcpfile.do_crc:=true;
- { the last entry ibend is written automatically }
- { flush to be sure }
- pcpfile.flush;
- { create and write header }
- pcpfile.header.common.size:=pcpfile.size;
- pcpfile.header.checksum:=pcpfile.crc;
- pcpfile.header.common.compiler:=wordversion;
- pcpfile.header.common.cpu:=word(target_cpu);
- pcpfile.header.common.target:=word(target_info.system);
- //pcpfile.header.flags:=flags;
- pcpfile.header.ppulistsize:=containedmodules.count;
- pcpfile.header.requiredlistsize:=requiredpackages.count;
- pcpfile.writeheader;
- { write the ppu table which will also fill the offsets/sizes }
- writeppudata;
- pcpfile.flush;
- oldpos:=pcpfile.position;
- { now write the filled PPU table at the previously stored position }
- pcpfile.position:=tablepos;
- writepputable;
- pcpfile.position:=oldpos;
- { save crc in current module also }
- //crc:=pcpfile.crc;
- pcpfile.closefile;
- pcpfile.free;
- pcpfile:=nil;
- end;
- function tpcppackage.getmodulestream(module:tmodulebase):tcstream;
- var
- i : longint;
- contained : pcontainedunit;
- begin
- for i:=0 to containedmodules.count-1 do
- begin
- contained:=pcontainedunit(containedmodules[i]);
- if contained^.module=module then
- begin
- result:=pcpfile.substream(contained^.offset,contained^.size);
- exit;
- end;
- end;
- result:=nil;
- end;
- procedure tpcppackage.initmoduleinfo(module: tmodulebase);
- begin
- pplfilename:=extractfilename(module.sharedlibfilename);
- end;
- procedure tpcppackage.addunit(module: tmodulebase);
- var
- containedunit : pcontainedunit;
- begin
- new(containedunit);
- containedunit^.module:=module;
- containedunit^.ppufile:=extractfilename(module.ppufilename);
- containedunit^.offset:=0;
- containedunit^.size:=0;
- containedmodules.add(module.modulename^,containedunit);
- end;
- procedure tpcppackage.add_required_package(pkg:tpackage);
- var
- p : tpackage;
- begin
- p:=tpackage(requiredpackages.find(pkg.packagename^));
- if not assigned(p) then
- requiredpackages.Add(pkg.packagename^,pkg)
- else
- if p<>pkg then
- internalerror(2015112302);
- end;
- end.
|