pcp.pas 6.1 KB

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