pcp.pas 5.8 KB

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