2
0

pcp.pas 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. {
  2. Copyright (c) 2013-2016 by Free Pascal development team
  3. Routines to read/write pcp files
  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 pcp;
  18. {$i fpcdefs.inc}
  19. {$H+}
  20. interface
  21. uses
  22. cstreams,entfile;
  23. const
  24. CurrentPCPVersion=3;
  25. { unit flags }
  26. //uf_init = $000001; { unit has initialization section }
  27. //uf_finalize = $000002; { unit has finalization section }
  28. pf_big_endian = $000004;
  29. //uf_has_browser = $000010;
  30. //uf_in_library = $000020; { is the file in another file than <ppufile>.* ? }
  31. //uf_smart_linked = $000040; { the ppu can be smartlinked }
  32. //uf_static_linked = $000080; { the ppu can be linked static }
  33. //uf_shared_linked = $000100; { the ppu can be linked shared }
  34. //uf_local_browser = $000200;
  35. //uf_no_link = $000400; { unit has no .o generated, but can still have external linking! }
  36. //uf_has_resourcestrings = $000800; { unit has resource string section }
  37. pf_little_endian = $001000;
  38. type
  39. tpcpheader=record
  40. common : tentryheader;
  41. checksum : cardinal; { checksum for this pcpfile }
  42. requiredlistsize, { number of entries for required packages }
  43. ppulistsize : longint; { number of entries for contained PPUs }
  44. end;
  45. tpcpfile=class(tentryfile)
  46. public
  47. header : tpcpheader;
  48. { crc for the entire package }
  49. crc : cardinal;
  50. do_crc : boolean;
  51. protected
  52. function getheadersize:longint;override;
  53. function getheaderaddr:pentryheader;override;
  54. procedure newheader;override;
  55. function readheader:longint;override;
  56. procedure resetfile;override;
  57. procedure RaiseAssertion(Code: Longint); override;
  58. public
  59. procedure writeheader;override;
  60. function checkpcpid:boolean;
  61. procedure putdata(const b;len:integer);override;
  62. end;
  63. implementation
  64. uses
  65. fpccrc;
  66. { tpcpfile }
  67. function tpcpfile.getheadersize: longint;
  68. begin
  69. result:=sizeof(tpcpheader);
  70. end;
  71. function tpcpfile.getheaderaddr: pentryheader;
  72. begin
  73. result:=@header;
  74. end;
  75. procedure tpcpfile.RaiseAssertion(Code: Longint);
  76. begin
  77. // InternalError(nb);
  78. inherited RaiseAssertion(Code);
  79. end;
  80. procedure tpcpfile.newheader;
  81. var
  82. s : string;
  83. begin
  84. fillchar(header,sizeof(tpcpheader),0);
  85. str(CurrentPCPVersion,s);
  86. while length(s)<3 do
  87. s:='0'+s;
  88. with header.common do
  89. begin
  90. id[1]:='P';
  91. id[2]:='C';
  92. id[3]:='P';
  93. ver[1]:=s[1];
  94. ver[2]:=s[2];
  95. ver[3]:=s[3];
  96. end;
  97. end;
  98. function tpcpfile.readheader: longint;
  99. begin
  100. if fsize<sizeof(tpcpheader) then
  101. exit(0);
  102. result:=f.Read(header,sizeof(tpcpheader));
  103. { The header is always stored in little endian order }
  104. { therefore swap if on a big endian machine }
  105. {$IFDEF ENDIAN_BIG}
  106. header.common.compiler := swapendian(header.common.compiler);
  107. header.common.cpu := swapendian(header.common.cpu);
  108. header.common.target := swapendian(header.common.target);
  109. header.common.flags := swapendian(header.common.flags);
  110. header.common.size := swapendian(header.common.size);
  111. header.checksum := swapendian(header.checksum);
  112. header.requiredlistsize:=swapendian(header.requiredlistsize);
  113. header.ppulistsize:=swapendian(header.ppulistsize);
  114. {$ENDIF}
  115. { the PPU DATA is stored in native order }
  116. if (header.common.flags and pf_big_endian) = pf_big_endian then
  117. Begin
  118. {$IFDEF ENDIAN_LITTLE}
  119. change_endian := TRUE;
  120. {$ELSE}
  121. change_endian := FALSE;
  122. {$ENDIF}
  123. End
  124. else if (header.common.flags and pf_little_endian) = pf_little_endian then
  125. Begin
  126. {$IFDEF ENDIAN_BIG}
  127. change_endian := TRUE;
  128. {$ELSE}
  129. change_endian := FALSE;
  130. {$ENDIF}
  131. End;
  132. end;
  133. procedure tpcpfile.resetfile;
  134. begin
  135. crc:=0;
  136. do_crc:=true;
  137. end;
  138. procedure tpcpfile.writeheader;
  139. var
  140. opos : integer;
  141. begin
  142. { flush buffer }
  143. writebuf;
  144. { update size (w/o header!) in the header }
  145. header.common.size:=bufstart-sizeof(tpcpheader);
  146. { set the endian flag }
  147. {$ifndef FPC_BIG_ENDIAN}
  148. header.common.flags:=header.common.flags or pf_little_endian;
  149. {$else not FPC_BIG_ENDIAN}
  150. header.common.flags:=header.common.flags or pf_big_endian;
  151. { Now swap the header in the correct endian (always little endian) }
  152. header.common.compiler:=swapendian(header.common.compiler);
  153. header.common.cpu:=swapendian(header.common.cpu);
  154. header.common.target:=swapendian(header.common.target);
  155. header.common.flags:=swapendian(header.common.flags);
  156. header.common.size:=swapendian(header.common.size);
  157. header.checksum:=swapendian(header.checksum);
  158. header.requiredlistsize:=swapendian(header.requiredlistsize);
  159. header.ppulistsize:=swapendian(header.ppulistsize);
  160. {$endif not FPC_BIG_ENDIAN}
  161. { write header and restore filepos after it }
  162. opos:=f.Position;
  163. f.Position:=0;
  164. f.Write(header,sizeof(tpcpheader));
  165. f.Position:=opos;
  166. end;
  167. function tpcpfile.checkpcpid:boolean;
  168. begin
  169. result:=((Header.common.Id[1]='P') and
  170. (Header.common.Id[2]='C') and
  171. (Header.common.Id[3]='P'));
  172. end;
  173. procedure tpcpfile.putdata(const b;len:integer);
  174. begin
  175. if do_crc then
  176. begin
  177. crc:=UpdateCrc32(crc,b,len);
  178. end;
  179. inherited putdata(b, len);
  180. end;
  181. end.