ppu.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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. unit ppu;
  19. interface
  20. const
  21. { buffer sizes }
  22. maxentrysize = 1024;
  23. {$ifdef TP}
  24. ppubufsize = 1024;
  25. {$else}
  26. ppubufsize = 16384;
  27. {$endif}
  28. {ppu entries}
  29. ibunitname = 1;
  30. ibsourcefile = 2;
  31. ibloadunit_int = 3;
  32. ibloadunit_imp = 4;
  33. ibinitunit = 5;
  34. iblinkofile = 6;
  35. ibsharedlibs = 7;
  36. ibstaticlibs = 8;
  37. ibdbxcount = 9;
  38. ibref = 10;
  39. ibentry = 254;
  40. ibend = 255;
  41. {syms}
  42. ibtypesym = 20;
  43. ibprocsym = 21;
  44. ibvarsym = 22;
  45. ibconstsym = 23;
  46. ibenumsym = 24;
  47. ibtypedconstsym = 25;
  48. ibabsolutesym = 26;
  49. ibpropertysym = 27;
  50. {defenitions}
  51. iborddef = 40;
  52. ibpointerdef = 41;
  53. ibarraydef = 42;
  54. ibprocdef = 43;
  55. ibstringdef = 44;
  56. ibrecorddef = 45;
  57. ibfiledef = 46;
  58. ibformaldef = 47;
  59. ibobjectdef = 48;
  60. ibenumdef = 49;
  61. ibsetdef = 50;
  62. ibprocvardef = 51;
  63. ibfloatdef = 52;
  64. ibextsymref = 53;
  65. ibextdefref = 54;
  66. ibclassrefdef = 55;
  67. iblongstringdef = 56;
  68. ibansistringdef = 57;
  69. ibwidestringdef = 58;
  70. { unit flags }
  71. uf_init = $1;
  72. uf_uses_dbx = $2;
  73. uf_uses_browser = $4;
  74. uf_big_endian = $8;
  75. uf_in_library = $10;
  76. uf_shared_library = $20;
  77. uf_smartlink = $40;
  78. type
  79. tppuerror=(ppuentrytoobig,ppuentryerror);
  80. tppuheader=packed record
  81. id : array[1..3] of char; { = 'PPU' }
  82. ver : array[1..3] of char;
  83. compiler : word;
  84. target : word;
  85. flags : longint;
  86. size : longint;
  87. checksum : longint;
  88. end;
  89. tppuentry=packed record
  90. id : byte;
  91. nr : byte;
  92. size : word;
  93. end;
  94. pppufile=^tppufile;
  95. tppufile=object
  96. f : file;
  97. error,
  98. writing : boolean;
  99. fname : string;
  100. fsize : longint;
  101. header : tppuheader;
  102. size,crc : longint;
  103. do_crc,
  104. change_endian : boolean;
  105. buf : pchar;
  106. bufstart,
  107. bufsize,
  108. bufidx : longint;
  109. entry : tppuentry;
  110. entrystart,
  111. entryidx : longint;
  112. constructor init(fn:string);
  113. destructor done;
  114. procedure flush;
  115. procedure close;
  116. function CheckPPUId:boolean;
  117. function GetPPUVersion:longint;
  118. procedure NewHeader;
  119. procedure NewEntry;
  120. function EndOfEntry:boolean;
  121. {read}
  122. function open:boolean;
  123. procedure reloadbuf;
  124. procedure readdata(var b;len:longint);
  125. function readentry:byte;
  126. procedure getdata(var b;len:longint);
  127. function getbyte:byte;
  128. function getword:word;
  129. function getlongint:longint;
  130. function getstring:string;
  131. {write}
  132. function create:boolean;
  133. procedure writeheader;
  134. procedure writebuf;
  135. procedure writedata(var b;len:longint);
  136. procedure writeentry(ibnr:byte);
  137. procedure putdata(var b;len:longint);
  138. procedure putbyte(b:byte);
  139. procedure putword(w:word);
  140. procedure putlongint(l:longint);
  141. procedure putstring(s:string);
  142. end;
  143. implementation
  144. {*****************************************************************************
  145. Crc 32
  146. *****************************************************************************}
  147. var
  148. Crc32Tbl : array[0..255] of longint;
  149. procedure MakeCRC32Tbl;
  150. var
  151. crc : longint;
  152. i,n : byte;
  153. begin
  154. for i:=0 to 255 do
  155. begin
  156. crc:=i;
  157. for n:=1 to 8 do
  158. if odd(crc) then
  159. crc:=(crc shr 1) xor $edb88320
  160. else
  161. crc:=crc shr 1;
  162. Crc32Tbl[i]:=crc;
  163. end;
  164. end;
  165. {CRC 32}
  166. Function Crc32(Const HStr:String):longint;
  167. var
  168. i,InitCrc : longint;
  169. begin
  170. if Crc32Tbl[1]=0 then
  171. MakeCrc32Tbl;
  172. InitCrc:=$ffffffff;
  173. for i:=1to Length(Hstr) do
  174. InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(Hstr[i])] xor (InitCrc shr 8);
  175. Crc32:=InitCrc;
  176. end;
  177. Function UpdateCrc32(InitCrc:longint;var InBuf;InLen:Longint):longint;
  178. var
  179. i : word;
  180. p : pchar;
  181. begin
  182. if Crc32Tbl[1]=0 then
  183. MakeCrc32Tbl;
  184. p:=@InBuf;
  185. for i:=1to InLen do
  186. begin
  187. InitCrc:=Crc32Tbl[byte(InitCrc) xor byte(p^)] xor (InitCrc shr 8);
  188. inc(longint(p));
  189. end;
  190. UpdateCrc32:=InitCrc;
  191. end;
  192. Function UpdCrc32(InitCrc:longint;b:byte):longint;
  193. begin
  194. if Crc32Tbl[1]=0 then
  195. MakeCrc32Tbl;
  196. UpdCrc32:=Crc32Tbl[byte(InitCrc) xor b] xor (InitCrc shr 8);
  197. end;
  198. {*****************************************************************************
  199. TPPUFile
  200. *****************************************************************************}
  201. constructor tppufile.init(fn:string);
  202. begin
  203. fname:=fn;
  204. change_endian:=false;
  205. writing:=false;
  206. NewHeader;
  207. getmem(buf,ppubufsize);
  208. end;
  209. destructor tppufile.done;
  210. begin
  211. close;
  212. freemem(buf,ppubufsize);
  213. end;
  214. procedure tppufile.flush;
  215. begin
  216. if writing then
  217. writebuf;
  218. end;
  219. procedure tppufile.close;
  220. var
  221. i : word;
  222. begin
  223. Flush;
  224. {$I-}
  225. system.close(f);
  226. {$I+}
  227. i:=ioresult;
  228. end;
  229. function tppufile.CheckPPUId:boolean;
  230. begin
  231. CheckPPUId:=((Header.Id[1]='P') and (Header.Id[2]='P') and (Header.Id[3]='U'));
  232. end;
  233. function tppufile.GetPPUVersion:longint;
  234. var
  235. l : longint;
  236. code : word;
  237. begin
  238. Val(header.ver[1]+header.ver[2]+header.ver[3],l,code);
  239. if code=0 then
  240. GetPPUVersion:=l
  241. else
  242. GetPPUVersion:=0;
  243. end;
  244. procedure tppufile.NewHeader;
  245. begin
  246. fillchar(header,sizeof(tppuheader),0);
  247. with header do
  248. begin
  249. Id[1]:='P';
  250. Id[2]:='P';
  251. Id[3]:='U';
  252. Ver[1]:='0';
  253. Ver[2]:='1';
  254. Ver[3]:='5';
  255. end;
  256. end;
  257. procedure tppufile.NewEntry;
  258. begin
  259. with entry do
  260. begin
  261. id:=ibentry;
  262. nr:=ibend;
  263. size:=0;
  264. end;
  265. entryidx:=0;
  266. end;
  267. function tppufile.endofentry:boolean;
  268. begin
  269. endofentry:=(entryidx>=entry.size);
  270. end;
  271. {*****************************************************************************
  272. TPPUFile Reading
  273. *****************************************************************************}
  274. function tppufile.open:boolean;
  275. var
  276. ofmode : byte;
  277. i : word;
  278. begin
  279. open:=false;
  280. assign(f,fname);
  281. ofmode:=filemode;
  282. filemode:=$0;
  283. {$I-}
  284. reset(f,1);
  285. {$I+}
  286. filemode:=ofmode;
  287. if ioresult<>0 then
  288. exit;
  289. {read ppuheader}
  290. fsize:=filesize(f);
  291. if fsize<sizeof(tppuheader) then
  292. exit;
  293. blockread(f,header,sizeof(tppuheader),i);
  294. {reset buffer}
  295. bufstart:=i;
  296. bufsize:=0;
  297. writing:=false;
  298. open:=true;
  299. end;
  300. procedure tppufile.reloadbuf;
  301. {$ifdef TP}
  302. var
  303. i : word;
  304. {$endif}
  305. begin
  306. inc(bufstart,bufsize);
  307. {$ifdef TP}
  308. blockread(f,buf,ppubufsize,i);
  309. bufsize:=i;
  310. {$else}
  311. blockread(f,buf,ppubufsize,bufsize);
  312. {$endif}
  313. bufidx:=0;
  314. end;
  315. procedure tppufile.readdata(var b;len:longint);
  316. var
  317. p : pchar;
  318. left,
  319. idx : longint;
  320. begin
  321. p:=pchar(@b);
  322. idx:=0;
  323. while len>0 do
  324. begin
  325. left:=bufsize-bufidx;
  326. if len>left then
  327. begin
  328. move(buf[bufidx],p[idx],left);
  329. dec(len,left);
  330. inc(idx,left);
  331. reloadbuf;
  332. if bufsize=0 then
  333. exit;
  334. end
  335. else
  336. begin
  337. move(buf[bufidx],p[idx],len);
  338. inc(bufidx,len);
  339. exit;
  340. end;
  341. end;
  342. end;
  343. function tppufile.readentry:byte;
  344. begin
  345. readdata(entry,sizeof(tppuentry));
  346. if entry.id<>ibentry then
  347. begin
  348. error:=true;
  349. exit;
  350. end;
  351. readentry:=entry.nr;
  352. entryidx:=0;
  353. end;
  354. procedure tppufile.getdata(var b;len:longint);
  355. begin
  356. if entryidx+len>entry.size then
  357. begin
  358. error:=true;
  359. exit;
  360. end;
  361. readdata(b,len);
  362. inc(entryidx,len);
  363. end;
  364. function tppufile.getbyte:byte;
  365. var
  366. b : byte;
  367. begin
  368. if entryidx+1>entry.size then
  369. begin
  370. error:=true;
  371. exit;
  372. end;
  373. { if bufidx+1>bufsize then
  374. getbyte:=ord(buf[bufidx]);
  375. inc(bufidx);}
  376. readdata(b,1);
  377. getbyte:=b;
  378. inc(entryidx);
  379. end;
  380. function tppufile.getword:word;
  381. type
  382. pword = ^word;
  383. var
  384. w : word;
  385. begin
  386. if entryidx+2>entry.size then
  387. begin
  388. error:=true;
  389. exit;
  390. end;
  391. { getword:=pword(@entrybuf[entrybufidx])^;}
  392. readdata(w,2);
  393. getword:=w;
  394. inc(entryidx,2);
  395. end;
  396. function tppufile.getlongint:longint;
  397. type
  398. plongint = ^longint;
  399. var
  400. l : longint;
  401. begin
  402. if entryidx+4>entry.size then
  403. begin
  404. error:=true;
  405. exit;
  406. end;
  407. readdata(l,4);
  408. getlongint:=l;
  409. {
  410. getlongint:=plongint(@entrybuf[entrybufidx])^;}
  411. inc(entryidx,4);
  412. end;
  413. function tppufile.getstring:string;
  414. var
  415. s : string;
  416. begin
  417. s[0]:=chr(getbyte);
  418. if entryidx+length(s)>entry.size then
  419. begin
  420. error:=true;
  421. exit;
  422. end;
  423. ReadData(s[1],length(s));
  424. getstring:=s;
  425. { move(entrybuf[entrybufidx],s[1],length(s));}
  426. inc(entryidx,length(s));
  427. end;
  428. {*****************************************************************************
  429. TPPUFile Writing
  430. *****************************************************************************}
  431. function tppufile.create:boolean;
  432. begin
  433. create:=false;
  434. assign(f,fname);
  435. {$I-}
  436. rewrite(f,1);
  437. {$I+}
  438. if ioresult<>0 then
  439. exit;
  440. {write header for sure}
  441. blockwrite(f,header,sizeof(tppuheader));
  442. bufsize:=ppubufsize;
  443. {reset}
  444. crc:=$ffffffff;
  445. do_crc:=true;
  446. size:=0;
  447. writing:=true;
  448. create:=true;
  449. end;
  450. procedure tppufile.writeheader;
  451. var
  452. opos : longint;
  453. begin
  454. writebuf;
  455. opos:=filepos(f);
  456. seek(f,0);
  457. blockwrite(f,header,sizeof(tppuheader));
  458. seek(f,opos);
  459. end;
  460. procedure tppufile.writebuf;
  461. begin
  462. if do_crc then
  463. UpdateCrc32(crc,buf,bufidx);
  464. blockwrite(f,buf,bufidx);
  465. inc(bufstart,bufidx);
  466. bufidx:=0;
  467. end;
  468. procedure tppufile.writedata(var b;len:longint);
  469. var
  470. p : pchar;
  471. left,
  472. idx : longint;
  473. begin
  474. p:=pchar(@b);
  475. idx:=0;
  476. while len>0 do
  477. begin
  478. left:=bufsize-bufidx;
  479. if len>left then
  480. begin
  481. move(p[idx],buf[bufidx],left);
  482. dec(len,left);
  483. inc(idx,left);
  484. writebuf;
  485. end
  486. else
  487. begin
  488. move(p[idx],buf[bufidx],len);
  489. inc(bufidx,len);
  490. exit;
  491. end;
  492. end;
  493. end;
  494. procedure tppufile.writeentry(ibnr:byte);
  495. var
  496. opos : longint;
  497. begin
  498. {create entry}
  499. entry.id:=ibentry;
  500. entry.nr:=ibnr;
  501. entry.size:=entryidx;
  502. {flush}
  503. writebuf;
  504. {write entry}
  505. opos:=filepos(f);
  506. seek(f,entrystart);
  507. blockwrite(f,entry,sizeof(tppuentry));
  508. seek(f,opos);
  509. entrystart:=opos; {next entry position}
  510. {Add New Entry, which is ibend by default}
  511. NewEntry;
  512. writedata(entry,sizeof(tppuentry));
  513. end;
  514. procedure tppufile.putdata(var b;len:longint);
  515. begin
  516. writedata(b,len);
  517. inc(entryidx,len);
  518. end;
  519. procedure tppufile.putbyte(b:byte);
  520. begin
  521. writedata(b,1);
  522. {
  523. entrybuf[entrybufidx]:=chr(b);}
  524. inc(entryidx);
  525. end;
  526. procedure tppufile.putword(w:word);
  527. type
  528. pword = ^word;
  529. begin
  530. if change_endian then
  531. w:=swap(w);
  532. { pword(@entrybuf[entrybufidx])^:=w;}
  533. writedata(w,2);
  534. inc(entryidx,2);
  535. end;
  536. procedure tppufile.putlongint(l:longint);
  537. type
  538. plongint = ^longint;
  539. begin
  540. { plongint(@entrybuf[entrybufidx])^:=l;}
  541. if change_endian then
  542. l:=swap(l shr 16) or (longint(swap(l and $ffff)) shl 16);
  543. writedata(l,4);
  544. inc(entryidx,4);
  545. end;
  546. procedure tppufile.putstring(s:string);
  547. begin
  548. writedata(s,length(s)+1);
  549. { move(s,entrybuf[entrybufidx],length(s)+1);}
  550. inc(entryidx,length(s)+1);
  551. end;
  552. end.
  553. {
  554. $Log$
  555. Revision 1.1 1998-05-12 10:56:07 peter
  556. + the ppufile object unit
  557. }