ppu.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Routines to read/write ppu files
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$ifdef TP}
  19. {$N+,E+}
  20. {$endif}
  21. unit ppu;
  22. interface
  23. const
  24. { buffer sizes }
  25. maxentrysize = 1024;
  26. {$ifdef TP}
  27. ppubufsize = 1024;
  28. {$else}
  29. ppubufsize = 16384;
  30. {$endif}
  31. {ppu entries}
  32. mainentryid = 1;
  33. subentryid = 2;
  34. {special}
  35. iberror = 0;
  36. ibenddefs = 250;
  37. ibendsyms = 251;
  38. ibendinterface = 252;
  39. ibendimplementation = 253;
  40. ibendbrowser = 254;
  41. ibend = 255;
  42. {general}
  43. ibmodulename = 1;
  44. ibsourcefiles = 2;
  45. ibloadunit_int = 3;
  46. ibloadunit_imp = 4;
  47. ibinitunit = 5;
  48. iblinkofiles = 6;
  49. iblinksharedlibs = 7;
  50. iblinkstaticlibs = 8;
  51. ibdbxcount = 9;
  52. ibsymref = 10;
  53. ibdefref = 11;
  54. {syms}
  55. ibtypesym = 20;
  56. ibprocsym = 21;
  57. ibvarsym = 22;
  58. ibconstsym = 23;
  59. ibenumsym = 24;
  60. ibtypedconstsym = 25;
  61. ibabsolutesym = 26;
  62. ibpropertysym = 27;
  63. ibvarsym_C = 28;
  64. {defenitions}
  65. iborddef = 40;
  66. ibpointerdef = 41;
  67. ibarraydef = 42;
  68. ibprocdef = 43;
  69. ibstringdef = 44;
  70. ibrecorddef = 45;
  71. ibfiledef = 46;
  72. ibformaldef = 47;
  73. ibobjectdef = 48;
  74. ibenumdef = 49;
  75. ibsetdef = 50;
  76. ibprocvardef = 51;
  77. ibfloatdef = 52;
  78. ibclassrefdef = 53;
  79. iblongstringdef = 54;
  80. ibansistringdef = 55;
  81. ibwidestringdef = 56;
  82. { unit flags }
  83. uf_init = $1;
  84. uf_has_dbx = $2;
  85. uf_has_browser = $4;
  86. uf_big_endian = $8;
  87. uf_in_library = $10;
  88. uf_shared_library = $20;
  89. uf_smartlink = $40;
  90. uf_finalize = $80;
  91. type
  92. tppuerror=(ppuentrytoobig,ppuentryerror);
  93. tppuheader=packed record
  94. id : array[1..3] of char; { = 'PPU' }
  95. ver : array[1..3] of char;
  96. compiler : word;
  97. cpu : word;
  98. target : word;
  99. flags : longint;
  100. size : longint; { size of the ppufile without header }
  101. checksum : longint; { checksum for this ppufile }
  102. end;
  103. tppuentry=packed record
  104. id : byte;
  105. nr : byte;
  106. size : longint;
  107. end;
  108. pppufile=^tppufile;
  109. tppufile=object
  110. f : file;
  111. mode : byte; {0 - Closed, 1 - Reading, 2 - Writing}
  112. error : boolean;
  113. fname : string;
  114. fsize : longint;
  115. header : tppuheader;
  116. size,crc : longint;
  117. do_crc,
  118. change_endian : boolean;
  119. buf : pchar;
  120. bufstart,
  121. bufsize,
  122. bufidx : longint;
  123. entrybufstart,
  124. entrystart,
  125. entryidx : longint;
  126. entry : tppuentry;
  127. entrytyp : byte;
  128. constructor init(fn:string);
  129. destructor done;
  130. procedure flush;
  131. procedure close;
  132. function CheckPPUId:boolean;
  133. function GetPPUVersion:longint;
  134. procedure NewHeader;
  135. procedure NewEntry;
  136. {read}
  137. function open:boolean;
  138. procedure reloadbuf;
  139. procedure readdata(var b;len:longint);
  140. procedure skipdata(len:longint);
  141. function readentry:byte;
  142. function EndOfEntry:boolean;
  143. procedure getdatabuf(var b;len:longint;var result:longint);
  144. procedure getdata(var b;len:longint);
  145. function getbyte:byte;
  146. function getword:word;
  147. function getlongint:longint;
  148. function getdouble:double;
  149. function getstring:string;
  150. function skipuntilentry(untilb:byte):boolean;
  151. {write}
  152. function create:boolean;
  153. procedure writeheader;
  154. procedure writebuf;
  155. procedure writedata(var b;len:longint);
  156. procedure writeentry(ibnr:byte);
  157. procedure putdata(var b;len:longint);
  158. procedure putbyte(b:byte);
  159. procedure putword(w:word);
  160. procedure putlongint(l:longint);
  161. procedure putdouble(d:double);
  162. procedure putstring(s:string);
  163. end;
  164. implementation
  165. {*****************************************************************************
  166. Crc 32
  167. *****************************************************************************}
  168. var
  169. Crc32Tbl : array[0..255] of longint;
  170. procedure MakeCRC32Tbl;
  171. var
  172. crc : longint;
  173. i,n : byte;
  174. begin
  175. for i:=0 to 255 do
  176. begin
  177. crc:=i;
  178. for n:=1 to 8 do
  179. if odd(crc) then
  180. crc:=(crc shr 1) xor $edb88320
  181. else
  182. crc:=crc shr 1;
  183. Crc32Tbl[i]:=crc;
  184. end;
  185. end;
  186. {CRC 32}
  187. Function Crc32(Const HStr:String):longint;
  188. var
  189. i,InitCrc : longint;
  190. begin
  191. if Crc32Tbl[1]=0 then
  192. MakeCrc32Tbl;
  193. InitCrc:=$ffffffff;
  194. for i:=1to Length(Hstr) do
  195. InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(Hstr[i])] xor (InitCrc shr 8);
  196. Crc32:=InitCrc;
  197. end;
  198. Function UpdateCrc32(InitCrc:longint;var InBuf;InLen:Longint):longint;
  199. var
  200. i : word;
  201. p : pchar;
  202. begin
  203. if Crc32Tbl[1]=0 then
  204. MakeCrc32Tbl;
  205. p:=@InBuf;
  206. for i:=1to InLen do
  207. begin
  208. InitCrc:=Crc32Tbl[byte(InitCrc) xor byte(p^)] xor (InitCrc shr 8);
  209. inc(longint(p));
  210. end;
  211. UpdateCrc32:=InitCrc;
  212. end;
  213. Function UpdCrc32(InitCrc:longint;b:byte):longint;
  214. begin
  215. if Crc32Tbl[1]=0 then
  216. MakeCrc32Tbl;
  217. UpdCrc32:=Crc32Tbl[byte(InitCrc) xor b] xor (InitCrc shr 8);
  218. end;
  219. {*****************************************************************************
  220. TPPUFile
  221. *****************************************************************************}
  222. constructor tppufile.init(fn:string);
  223. begin
  224. fname:=fn;
  225. change_endian:=false;
  226. Mode:=0;
  227. NewHeader;
  228. Error:=false;
  229. getmem(buf,ppubufsize);
  230. end;
  231. destructor tppufile.done;
  232. begin
  233. close;
  234. freemem(buf,ppubufsize);
  235. end;
  236. procedure tppufile.flush;
  237. begin
  238. if Mode=2 then
  239. writebuf;
  240. end;
  241. procedure tppufile.close;
  242. var
  243. i : word;
  244. begin
  245. if Mode<>0 then
  246. begin
  247. Flush;
  248. {$I-}
  249. system.close(f);
  250. {$I+}
  251. i:=ioresult;
  252. Mode:=0;
  253. end;
  254. end;
  255. function tppufile.CheckPPUId:boolean;
  256. begin
  257. CheckPPUId:=((Header.Id[1]='P') and (Header.Id[2]='P') and (Header.Id[3]='U'));
  258. end;
  259. function tppufile.GetPPUVersion:longint;
  260. var
  261. l : longint;
  262. code : word;
  263. begin
  264. Val(header.ver[1]+header.ver[2]+header.ver[3],l,code);
  265. if code=0 then
  266. GetPPUVersion:=l
  267. else
  268. GetPPUVersion:=0;
  269. end;
  270. procedure tppufile.NewHeader;
  271. begin
  272. fillchar(header,sizeof(tppuheader),0);
  273. with header do
  274. begin
  275. Id[1]:='P';
  276. Id[2]:='P';
  277. Id[3]:='U';
  278. Ver[1]:='0';
  279. Ver[2]:='1';
  280. Ver[3]:='5';
  281. end;
  282. end;
  283. {*****************************************************************************
  284. TPPUFile Reading
  285. *****************************************************************************}
  286. function tppufile.open:boolean;
  287. var
  288. ofmode : byte;
  289. i : word;
  290. begin
  291. open:=false;
  292. assign(f,fname);
  293. ofmode:=filemode;
  294. filemode:=$0;
  295. {$I-}
  296. reset(f,1);
  297. {$I+}
  298. filemode:=ofmode;
  299. if ioresult<>0 then
  300. exit;
  301. {read ppuheader}
  302. fsize:=filesize(f);
  303. if fsize<sizeof(tppuheader) then
  304. exit;
  305. blockread(f,header,sizeof(tppuheader),i);
  306. {reset buffer}
  307. bufstart:=i;
  308. bufsize:=0;
  309. bufidx:=0;
  310. Mode:=1;
  311. FillChar(entry,sizeof(tppuentry),0);
  312. entryidx:=0;
  313. entrystart:=0;
  314. entrybufstart:=0;
  315. Error:=false;
  316. open:=true;
  317. end;
  318. procedure tppufile.reloadbuf;
  319. {$ifdef TP}
  320. var
  321. i : word;
  322. {$endif}
  323. begin
  324. inc(bufstart,bufsize);
  325. {$ifdef TP}
  326. blockread(f,buf^,ppubufsize,i);
  327. bufsize:=i;
  328. {$else}
  329. blockread(f,buf^,ppubufsize,bufsize);
  330. {$endif}
  331. bufidx:=0;
  332. end;
  333. procedure tppufile.readdata(var b;len:longint);
  334. var
  335. p : pchar;
  336. left,
  337. idx : longint;
  338. begin
  339. p:=pchar(@b);
  340. idx:=0;
  341. while len>0 do
  342. begin
  343. left:=bufsize-bufidx;
  344. if len>left then
  345. begin
  346. move(buf[bufidx],p[idx],left);
  347. dec(len,left);
  348. inc(idx,left);
  349. reloadbuf;
  350. if bufsize=0 then
  351. exit;
  352. end
  353. else
  354. begin
  355. move(buf[bufidx],p[idx],len);
  356. inc(bufidx,len);
  357. exit;
  358. end;
  359. end;
  360. end;
  361. procedure tppufile.skipdata(len:longint);
  362. var
  363. left : longint;
  364. begin
  365. while len>0 do
  366. begin
  367. left:=bufsize-bufidx;
  368. if len>left then
  369. begin
  370. dec(len,left);
  371. reloadbuf;
  372. if bufsize=0 then
  373. exit;
  374. end
  375. else
  376. begin
  377. inc(bufidx,len);
  378. exit;
  379. end;
  380. end;
  381. end;
  382. function tppufile.readentry:byte;
  383. begin
  384. if entryidx<entry.size then
  385. skipdata(entry.size-entryidx);
  386. readdata(entry,sizeof(tppuentry));
  387. entrystart:=bufstart+bufidx;
  388. entryidx:=0;
  389. if not entry.id in [mainentryid,subentryid] then
  390. begin
  391. readentry:=iberror;
  392. error:=true;
  393. exit;
  394. end;
  395. readentry:=entry.nr;
  396. end;
  397. function tppufile.endofentry:boolean;
  398. begin
  399. endofentry:=(entryidx>=entry.size);
  400. end;
  401. procedure tppufile.getdatabuf(var b;len:longint;var result:longint);
  402. begin
  403. if entryidx+len>entry.size then
  404. result:=entry.size-entryidx
  405. else
  406. result:=len;
  407. readdata(b,result);
  408. inc(entryidx,result);
  409. end;
  410. procedure tppufile.getdata(var b;len:longint);
  411. begin
  412. if entryidx+len>entry.size then
  413. begin
  414. error:=true;
  415. exit;
  416. end;
  417. readdata(b,len);
  418. inc(entryidx,len);
  419. end;
  420. function tppufile.getbyte:byte;
  421. var
  422. b : byte;
  423. begin
  424. if entryidx+1>entry.size then
  425. begin
  426. error:=true;
  427. exit;
  428. end;
  429. readdata(b,1);
  430. getbyte:=b;
  431. inc(entryidx);
  432. end;
  433. function tppufile.getword:word;
  434. type
  435. pword = ^word;
  436. var
  437. w : word;
  438. begin
  439. if entryidx+2>entry.size then
  440. begin
  441. error:=true;
  442. exit;
  443. end;
  444. readdata(w,2);
  445. getword:=w;
  446. inc(entryidx,2);
  447. end;
  448. function tppufile.getlongint:longint;
  449. type
  450. plongint = ^longint;
  451. var
  452. l : longint;
  453. begin
  454. if entryidx+4>entry.size then
  455. begin
  456. error:=true;
  457. exit;
  458. end;
  459. readdata(l,4);
  460. getlongint:=l;
  461. inc(entryidx,4);
  462. end;
  463. function tppufile.getdouble:double;
  464. type
  465. pdouble = ^double;
  466. var
  467. d : double;
  468. begin
  469. if entryidx+sizeof(double)>entry.size then
  470. begin
  471. error:=true;
  472. exit;
  473. end;
  474. readdata(d,sizeof(double));
  475. getdouble:=d;
  476. inc(entryidx,sizeof(double));
  477. end;
  478. function tppufile.getstring:string;
  479. var
  480. s : string;
  481. begin
  482. s[0]:=chr(getbyte);
  483. if entryidx+length(s)>entry.size then
  484. begin
  485. error:=true;
  486. exit;
  487. end;
  488. ReadData(s[1],length(s));
  489. getstring:=s;
  490. inc(entryidx,length(s));
  491. end;
  492. function tppufile.skipuntilentry(untilb:byte):boolean;
  493. var
  494. b : byte;
  495. begin
  496. repeat
  497. b:=readentry;
  498. until (b in [ibend,iberror]) or ((b=untilb) and (entry.id=mainentryid));
  499. skipuntilentry:=(b=untilb);
  500. end;
  501. {*****************************************************************************
  502. TPPUFile Writing
  503. *****************************************************************************}
  504. function tppufile.create:boolean;
  505. begin
  506. create:=false;
  507. assign(f,fname);
  508. {$I-}
  509. rewrite(f,1);
  510. {$I+}
  511. if ioresult<>0 then
  512. exit;
  513. Mode:=2;
  514. {write header for sure}
  515. blockwrite(f,header,sizeof(tppuheader));
  516. bufsize:=ppubufsize;
  517. bufstart:=sizeof(tppuheader);
  518. bufidx:=0;
  519. {reset}
  520. crc:=$ffffffff;
  521. Error:=false;
  522. do_crc:=true;
  523. size:=0;
  524. entrytyp:=mainentryid;
  525. {start}
  526. NewEntry;
  527. create:=true;
  528. end;
  529. procedure tppufile.writeheader;
  530. var
  531. opos : longint;
  532. begin
  533. { flush buffer }
  534. writebuf;
  535. { update size (w/o header!) in the header }
  536. header.size:=bufstart-sizeof(tppuheader);
  537. { write header and restore filepos after it }
  538. opos:=filepos(f);
  539. seek(f,0);
  540. blockwrite(f,header,sizeof(tppuheader));
  541. seek(f,opos);
  542. end;
  543. procedure tppufile.writebuf;
  544. begin
  545. blockwrite(f,buf^,bufidx);
  546. inc(bufstart,bufidx);
  547. bufidx:=0;
  548. end;
  549. procedure tppufile.writedata(var b;len:longint);
  550. var
  551. p : pchar;
  552. left,
  553. idx : longint;
  554. begin
  555. p:=pchar(@b);
  556. idx:=0;
  557. while len>0 do
  558. begin
  559. left:=bufsize-bufidx;
  560. if len>left then
  561. begin
  562. move(p[idx],buf[bufidx],left);
  563. dec(len,left);
  564. inc(idx,left);
  565. inc(bufidx,left);
  566. writebuf;
  567. end
  568. else
  569. begin
  570. move(p[idx],buf[bufidx],len);
  571. inc(bufidx,len);
  572. exit;
  573. end;
  574. end;
  575. end;
  576. procedure tppufile.NewEntry;
  577. begin
  578. with entry do
  579. begin
  580. id:=entrytyp;
  581. nr:=ibend;
  582. size:=0;
  583. end;
  584. {Reset Entry State}
  585. entryidx:=0;
  586. entrybufstart:=bufstart;
  587. entrystart:=bufstart+bufidx;
  588. {Alloc in buffer}
  589. writedata(entry,sizeof(tppuentry));
  590. end;
  591. procedure tppufile.writeentry(ibnr:byte);
  592. var
  593. opos : longint;
  594. begin
  595. {create entry}
  596. entry.id:=entrytyp;
  597. entry.nr:=ibnr;
  598. entry.size:=entryidx;
  599. {it's already been sent to disk ?}
  600. if entrybufstart<>bufstart then
  601. begin
  602. {flush to be sure}
  603. WriteBuf;
  604. {write entry}
  605. opos:=filepos(f);
  606. seek(f,entrystart);
  607. blockwrite(f,entry,sizeof(tppuentry));
  608. seek(f,opos);
  609. entrybufstart:=bufstart;
  610. end
  611. else
  612. move(entry,buf[entrystart-bufstart],sizeof(entry));
  613. {Add New Entry, which is ibend by default}
  614. entrystart:=bufstart+bufidx; {next entry position}
  615. NewEntry;
  616. end;
  617. procedure tppufile.putdata(var b;len:longint);
  618. begin
  619. if do_crc then
  620. crc:=UpdateCrc32(crc,b,len);
  621. writedata(b,len);
  622. inc(entryidx,len);
  623. end;
  624. procedure tppufile.putbyte(b:byte);
  625. begin
  626. writedata(b,1);
  627. inc(entryidx);
  628. end;
  629. procedure tppufile.putword(w:word);
  630. begin
  631. if change_endian then
  632. w:=swap(w);
  633. putdata(w,2);
  634. end;
  635. procedure tppufile.putlongint(l:longint);
  636. begin
  637. if change_endian then
  638. l:=swap(l shr 16) or (longint(swap(l and $ffff)) shl 16);
  639. putdata(l,4);
  640. end;
  641. procedure tppufile.putdouble(d:double);
  642. begin
  643. putdata(d,sizeof(double));
  644. end;
  645. procedure tppufile.putstring(s:string);
  646. begin
  647. putdata(s,length(s)+1);
  648. end;
  649. end.
  650. {
  651. $Log$
  652. Revision 1.7 1998-06-25 10:51:01 pierre
  653. * removed a remaining ifndef NEWPPU
  654. replaced by ifdef OLDPPU
  655. * added uf_finalize to ppu unit
  656. Revision 1.6 1998/06/16 08:56:26 peter
  657. + targetcpu
  658. * cleaner pmodules for newppu
  659. Revision 1.5 1998/06/13 00:10:12 peter
  660. * working browser and newppu
  661. * some small fixes against crashes which occured in bp7 (but not in
  662. fpc?!)
  663. Revision 1.4 1998/06/09 16:01:48 pierre
  664. + added procedure directive parsing for procvars
  665. (accepted are popstack cdecl and pascal)
  666. + added C vars with the following syntax
  667. var C calias 'true_c_name';(can be followed by external)
  668. reason is that you must add the Cprefix
  669. which is target dependent
  670. Revision 1.3 1998/05/28 14:40:26 peter
  671. * fixes for newppu, remake3 works now with it
  672. Revision 1.2 1998/05/27 19:45:08 peter
  673. * symtable.pas splitted into includefiles
  674. * symtable adapted for $ifdef NEWPPU
  675. Revision 1.1 1998/05/12 10:56:07 peter
  676. + the ppufile object unit
  677. }