pcp.pas 6.0 KB

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