{ Copyright (c) 1998-2002 by Michael van Canneyt Handles resourcestrings 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 cresstr; {$i fpcdefs.inc} interface uses cclasses; Type { These are used to form a singly-linked list, ordered by hash value } TResourceStringItem = class(TLinkedListItem) Name : String; Value : Pchar; Len : Longint; hash : Cardinal; constructor Create(const AName:string;AValue:pchar;ALen:longint); destructor Destroy;override; procedure CalcHash; end; Tresourcestrings=class private List : TLinkedList; public ResStrCount : longint; constructor Create; destructor Destroy;override; function Register(Const name : string;p : pchar;len : longint) : longint; procedure CreateResourceStringList; Procedure WriteResourceFile(const FileName : String); end; var resourcestrings : Tresourcestrings; implementation uses cutils,globtype,globals, symdef, verbose,fmodule, aasmbase,aasmtai, aasmcpu; { --------------------------------------------------------------------- Calculate hash value, based on the string ---------------------------------------------------------------------} { --------------------------------------------------------------------- TRESOURCESTRING_ITEM ---------------------------------------------------------------------} constructor TResourceStringItem.Create(const AName:string;AValue:pchar;ALen:longint); begin inherited Create; Name:=AName; Len:=ALen; GetMem(Value,Len); Move(AValue^,Value^,Len); CalcHash; end; destructor TResourceStringItem.Destroy; begin FreeMem(Value,Len); end; procedure TResourceStringItem.CalcHash; Var g : Cardinal; I : longint; begin hash:=0; For I:=0 to Len-1 do { 0 terminated } begin hash:=hash shl 4; inc(Hash,Ord(Value[i])); g:=hash and ($f shl 28); if g<>0 then begin hash:=hash xor (g shr 24); hash:=hash xor g; end; end; If Hash=0 then Hash:=$ffffffff; end; { --------------------------------------------------------------------- Tresourcestrings ---------------------------------------------------------------------} Constructor Tresourcestrings.Create; begin List:=TStringList.Create; ResStrCount:=0; end; Destructor Tresourcestrings.Destroy; begin List.Free; end; { --------------------------------------------------------------------- Create the full asmlist for resourcestrings. ---------------------------------------------------------------------} procedure Tresourcestrings.CreateResourceStringList; Procedure AppendToAsmResList (P : TResourceStringItem); Var l1 : tasmlabel; s : pchar; l : longint; begin with p Do begin if (Value=nil) or (len=0) then asmlist[al_resourcestrings].concat(tai_const.create_sym(nil)) else begin objectlibrary.getdatalabel(l1); asmlist[al_resourcestrings].concat(tai_const.create_sym(l1)); maybe_new_object_file(asmlist[al_const]); asmlist[al_const].concat(tai_align.Create(const_align(sizeof(aint)))); asmlist[al_const].concat(tai_const.create_aint(-1)); asmlist[al_const].concat(tai_const.create_aint(len)); asmlist[al_const].concat(tai_label.create(l1)); getmem(s,len+1); move(value^,s^,len); s[len]:=#0; asmlist[al_const].concat(tai_string.create_pchar(s,len)); asmlist[al_const].concat(tai_const.create_8bit(0)); end; { append Current value (nil) and hash...} asmlist[al_resourcestrings].concat(tai_const.create_sym(nil)); asmlist[al_resourcestrings].concat(tai_const.create_32bit(longint(hash))); { Append the name as a ansistring. } objectlibrary.getdatalabel(l1); l:=length(name); asmlist[al_resourcestrings].concat(tai_const.create_sym(l1)); maybe_new_object_file(asmlist[al_const]); asmlist[al_const].concat(tai_align.create(const_align(sizeof(aint)))); asmlist[al_const].concat(tai_const.create_aint(-1)); asmlist[al_const].concat(tai_const.create_aint(l)); asmlist[al_const].concat(tai_label.create(l1)); getmem(s,l+1); move(Name[1],s^,l); s[l]:=#0; asmlist[al_const].concat(tai_string.create_pchar(s,l)); asmlist[al_const].concat(tai_const.create_8bit(0)); end; end; Var R : tresourceStringItem; begin if asmlist[al_resourcestrings]=nil then asmlist[al_resourcestrings]:=taasmoutput.create; maybe_new_object_file(asmlist[al_resourcestrings]); new_section(asmlist[al_resourcestrings],sec_data,'',4); asmlist[al_resourcestrings].concat(tai_align.create(const_align(sizeof(aint)))); asmlist[al_resourcestrings].concat(tai_symbol.createname_global( make_mangledname('RESOURCESTRINGLIST',current_module.localsymtable,''),AT_DATA,0)); asmlist[al_resourcestrings].concat(tai_const.create_32bit(resstrcount)); R:=TResourceStringItem(List.First); while assigned(R) do begin AppendToAsmResList(R); R:=TResourceStringItem(R.Next); end; asmlist[al_resourcestrings].concat(tai_symbol_end.createname( make_mangledname('RESOURCESTRINGLIST',current_module.localsymtable,''))); end; { --------------------------------------------------------------------- Insert 1 resource string in all tables. ---------------------------------------------------------------------} function Tresourcestrings.Register(const name : string;p : pchar;len : longint) : longint; begin List.Concat(tResourceStringItem.Create(lower(current_module.modulename^+'.'+Name),p,len)); Register:=ResStrCount; inc(ResStrCount); end; Procedure Tresourcestrings.WriteResourceFile(const FileName : String); Type TMode = (quoted,unquoted); Var F : Text; Mode : TMode; R : TResourceStringItem; C : char; Col,i : longint; Procedure Add(Const S : String); begin Write(F,S); Col:=Col+length(s); end; begin If List.Empty then exit; message1 (general_i_writingresourcefile,SplitFileName(filename)); Assign(F,Filename); {$i-} Rewrite(f); {$i+} If IOresult<>0 then begin message1(general_e_errorwritingresourcefile,filename); exit; end; R:=TResourceStringItem(List.First); While assigned(R) do begin writeln(f); Writeln(f,'# hash value = ',R.hash); col:=0; Add(R.Name+'='); Mode:=unquoted; For I:=0 to R.Len-1 do begin C:=R.Value[i]; If (ord(C)>31) and (Ord(c)<=128) and (c<>'''') then begin If mode=Quoted then Add(c) else begin Add(''''+c); mode:=quoted end; end else begin If Mode=quoted then begin Add(''''); mode:=unquoted; end; Add('#'+tostr(ord(c))); end; If Col>72 then begin if mode=quoted then Write (F,''''); Writeln(F,'+'); Col:=0; Mode:=unQuoted; end; end; if mode=quoted then writeln (f,''''); Writeln(f); R:=TResourceStringItem(R.Next); end; close(f); end; end.