owar.pas 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Peter Vreman
  4. Contains the stuff for writing .a files directly
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit owar;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cclasses,
  23. owbase;
  24. type
  25. tarhdr=packed record
  26. name : array[0..15] of char;
  27. date : array[0..11] of char;
  28. uid : array[0..5] of char;
  29. gid : array[0..5] of char;
  30. mode : array[0..7] of char;
  31. size : array[0..9] of char;
  32. fmag : array[0..1] of char;
  33. end;
  34. tarobjectwriter=class(tobjectwriter)
  35. constructor create(const Aarfn:string);
  36. destructor destroy;override;
  37. function createfile(const fn:string):boolean;override;
  38. procedure closefile;override;
  39. procedure writesym(const sym:string);override;
  40. procedure write(const b;len:longint);override;
  41. private
  42. arfn : string;
  43. arhdr : tarhdr;
  44. symreloc,
  45. symstr,
  46. lfnstr,
  47. ardata : TDynamicArray;
  48. objpos : longint;
  49. objfn : string;
  50. timestamp : string[12];
  51. procedure createarhdr(fn:string;size:longint;const gid,uid,mode:string);
  52. procedure writear;
  53. end;
  54. implementation
  55. uses
  56. cstreams,
  57. systems,
  58. globals,
  59. verbose,
  60. {$ifdef Delphi}
  61. dmisc;
  62. {$else Delphi}
  63. dos;
  64. {$endif Delphi}
  65. const
  66. symrelocbufsize = 4096;
  67. symstrbufsize = 8192;
  68. lfnstrbufsize = 4096;
  69. arbufsize = 65536;
  70. {*****************************************************************************
  71. Helpers
  72. *****************************************************************************}
  73. const
  74. C1970=2440588;
  75. D0=1461;
  76. D1=146097;
  77. D2=1721119;
  78. Function Gregorian2Julian(DT:DateTime):LongInt;
  79. Var
  80. Century,XYear,Month : LongInt;
  81. Begin
  82. Month:=DT.Month;
  83. If Month<=2 Then
  84. Begin
  85. Dec(DT.Year);
  86. Inc(Month,12);
  87. End;
  88. Dec(Month,3);
  89. Century:=(longint(DT.Year Div 100)*D1) shr 2;
  90. XYear:=(longint(DT.Year Mod 100)*D0) shr 2;
  91. Gregorian2Julian:=((((Month*153)+2) div 5)+DT.Day)+D2+XYear+Century;
  92. End;
  93. function DT2Unix(DT:DateTime):LongInt;
  94. Begin
  95. DT2Unix:=(Gregorian2Julian(DT)-C1970)*86400+(LongInt(DT.Hour)*3600)+(DT.Min*60)+DT.Sec;
  96. end;
  97. {*****************************************************************************
  98. TArObjectWriter
  99. *****************************************************************************}
  100. constructor tarobjectwriter.create(const Aarfn:string);
  101. var
  102. time : datetime;
  103. dummy : word;
  104. begin
  105. arfn:=Aarfn;
  106. ardata:=TDynamicArray.Create(arbufsize);
  107. symreloc:=TDynamicArray.Create(symrelocbufsize);
  108. symstr:=TDynamicArray.Create(symstrbufsize);
  109. lfnstr:=TDynamicArray.Create(lfnstrbufsize);
  110. { create timestamp }
  111. getdate(time.year,time.month,time.day,dummy);
  112. gettime(time.hour,time.min,time.sec,dummy);
  113. Str(DT2Unix(time),timestamp);
  114. end;
  115. destructor tarobjectwriter.destroy;
  116. begin
  117. if Errorcount=0 then
  118. writear;
  119. arData.Free;
  120. symreloc.Free;
  121. symstr.Free;
  122. lfnstr.Free;
  123. end;
  124. procedure tarobjectwriter.createarhdr(fn:string;size:longint;const gid,uid,mode:string);
  125. var
  126. tmp : string[9];
  127. begin
  128. fillchar(arhdr,sizeof(tarhdr),' ');
  129. { create ar header }
  130. { win32 will change names starting with .\ to ./ when using lfn, corrupting
  131. the sort order required for the idata sections. To prevent this strip
  132. always the path from the filename. (PFV) }
  133. fn:=SplitFileName(fn)+'/';
  134. if length(fn)>16 then
  135. begin
  136. arhdr.name[0]:='/';
  137. str(lfnstr.size,tmp);
  138. move(tmp[1],arhdr.name[1],length(tmp));
  139. fn:=fn+#10;
  140. lfnstr.write(fn[1],length(fn));
  141. end
  142. else
  143. move(fn[1],arhdr.name,length(fn));
  144. { don't write a date if also no gid/uid/mode is specified }
  145. if gid<>'' then
  146. move(timestamp[1],arhdr.date,sizeof(timestamp));
  147. str(size,tmp);
  148. move(tmp[1],arhdr.size,length(tmp));
  149. move(gid[1],arhdr.gid,length(gid));
  150. move(uid[1],arhdr.uid,length(uid));
  151. move(mode[1],arhdr.mode,length(mode));
  152. arhdr.fmag:='`'#10;
  153. end;
  154. function tarobjectwriter.createfile(const fn:string):boolean;
  155. begin
  156. objfn:=fn;
  157. objpos:=ardata.size;
  158. ardata.seek(objpos + sizeof(tarhdr));
  159. createfile:=true;
  160. end;
  161. procedure tarobjectwriter.closefile;
  162. begin
  163. ardata.align(2);
  164. { fix the size in the header }
  165. createarhdr(objfn,ardata.size-objpos-sizeof(tarhdr),'42','42','644');
  166. { write the header }
  167. ardata.seek(objpos);
  168. ardata.write(arhdr,sizeof(tarhdr));
  169. end;
  170. procedure tarobjectwriter.writesym(const sym:string);
  171. var
  172. c : char;
  173. begin
  174. c:=#0;
  175. symreloc.write(objpos,4);
  176. symstr.write(sym[1],length(sym));
  177. symstr.write(c,1);
  178. end;
  179. procedure tarobjectwriter.write(const b;len:longint);
  180. begin
  181. ardata.write(b,len);
  182. end;
  183. procedure tarobjectwriter.writear;
  184. function lsb2msb(l:longint):longint;
  185. type
  186. bytearr=array[0..3] of byte;
  187. var
  188. l1 : longint;
  189. begin
  190. bytearr(l1)[0]:=bytearr(l)[3];
  191. bytearr(l1)[1]:=bytearr(l)[2];
  192. bytearr(l1)[2]:=bytearr(l)[1];
  193. bytearr(l1)[3]:=bytearr(l)[0];
  194. lsb2msb:=l1;
  195. end;
  196. const
  197. armagic:array[1..8] of char='!<arch>'#10;
  198. var
  199. arf : TCFileStream;
  200. fixup,l,
  201. relocs,i : longint;
  202. begin
  203. arf:=TCFileStream.Create(arfn,fmCreate);
  204. if CStreamError<>0 then
  205. begin
  206. Message1(exec_e_cant_create_archivefile,arfn);
  207. exit;
  208. end;
  209. arf.Write(armagic,sizeof(armagic));
  210. { align first, because we need the size for the fixups of the symbol reloc }
  211. if lfnstr.size>0 then
  212. lfnstr.align(2);
  213. if symreloc.size>0 then
  214. begin
  215. symstr.align(2);
  216. fixup:=12+sizeof(tarhdr)+symreloc.size+symstr.size;
  217. if lfnstr.size>0 then
  218. inc(fixup,lfnstr.size+sizeof(tarhdr));
  219. relocs:=symreloc.size div 4;
  220. { fixup relocs }
  221. for i:=0to relocs-1 do
  222. begin
  223. symreloc.seek(i*4);
  224. symreloc.read(l,4);
  225. symreloc.seek(i*4);
  226. l:=lsb2msb(l+fixup);
  227. symreloc.write(l,4);
  228. end;
  229. createarhdr('',4+symreloc.size+symstr.size,'0','0','0');
  230. arf.Write(arhdr,sizeof(tarhdr));
  231. relocs:=lsb2msb(relocs);
  232. arf.Write(relocs,4);
  233. symreloc.WriteStream(arf);
  234. symstr.WriteStream(arf);
  235. end;
  236. if lfnstr.size>0 then
  237. begin
  238. createarhdr('/',lfnstr.size,'','','');
  239. arf.Write(arhdr,sizeof(tarhdr));
  240. lfnstr.WriteStream(arf);
  241. end;
  242. ardata.WriteStream(arf);
  243. Arf.Free;
  244. end;
  245. end.
  246. {
  247. $Log$
  248. Revision 1.13 2004-05-09 11:07:39 peter
  249. strip path from filenames of members, because win32 changes .\ to ./ for long filenames
  250. Revision 1.12 2002/05/18 13:34:11 peter
  251. * readded missing revisions
  252. Revision 1.11 2002/05/16 19:46:42 carl
  253. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  254. + try to fix temp allocation (still in ifdef)
  255. + generic constructor calls
  256. + start of tassembler / tmodulebase class cleanup
  257. Revision 1.9 2002/04/04 19:06:00 peter
  258. * removed unused units
  259. * use tlocation.size in cg.a_*loc*() routines
  260. }