owar.pas 6.9 KB

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