pcp.pas 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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=1;
  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. protected
  50. function getheadersize:longint;override;
  51. function getheaderaddr:pentryheader;override;
  52. procedure newheader;override;
  53. function readheader:longint;override;
  54. procedure resetfile;override;
  55. public
  56. procedure writeheader;override;
  57. function checkpcpid:boolean;
  58. end;
  59. implementation
  60. { tpcpfile }
  61. function tpcpfile.getheadersize: longint;
  62. begin
  63. result:=sizeof(tpcpheader);
  64. end;
  65. function tpcpfile.getheaderaddr: pentryheader;
  66. begin
  67. result:=@header;
  68. end;
  69. procedure tpcpfile.newheader;
  70. var
  71. s : string;
  72. begin
  73. fillchar(header,sizeof(tpcpheader),0);
  74. str(CurrentPCPVersion,s);
  75. while length(s)<3 do
  76. s:='0'+s;
  77. with header.common do
  78. begin
  79. id[1]:='P';
  80. id[2]:='C';
  81. id[3]:='P';
  82. ver[1]:=s[1];
  83. ver[2]:=s[2];
  84. ver[3]:=s[3];
  85. end;
  86. end;
  87. function tpcpfile.readheader: longint;
  88. begin
  89. if fsize<sizeof(tpcpheader) then
  90. exit(0);
  91. result:=f.Read(header,sizeof(tpcpheader));
  92. { The header is always stored in little endian order }
  93. { therefore swap if on a big endian machine }
  94. {$IFDEF ENDIAN_BIG}
  95. header.common.compiler := swapendian(header.common.compiler);
  96. header.common.cpu := swapendian(header.common.cpu);
  97. header.common.target := swapendian(header.common.target);
  98. header.common.flags := swapendian(header.common.flags);
  99. header.common.size := swapendian(header.common.size);
  100. header.checksum := swapendian(header.checksum);
  101. header.requiredlistsize:=swapendian(header.requiredlistsize);
  102. header.ppulistsize:=swapendian(header.ppulistsize);
  103. {$ENDIF}
  104. { the PPU DATA is stored in native order }
  105. if (header.common.flags and pf_big_endian) = pf_big_endian then
  106. Begin
  107. {$IFDEF ENDIAN_LITTLE}
  108. change_endian := TRUE;
  109. {$ELSE}
  110. change_endian := FALSE;
  111. {$ENDIF}
  112. End
  113. else if (header.common.flags and pf_little_endian) = pf_little_endian then
  114. Begin
  115. {$IFDEF ENDIAN_BIG}
  116. change_endian := TRUE;
  117. {$ELSE}
  118. change_endian := FALSE;
  119. {$ENDIF}
  120. End;
  121. end;
  122. procedure tpcpfile.resetfile;
  123. begin
  124. crc:=0;
  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. end.