zutil.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. Unit ZUtil;
  2. {
  3. Copyright (C) 1998 by Jacques Nomssi Nzali
  4. For conditions of distribution and use, see copyright notice in readme.txt
  5. }
  6. interface
  7. {$I zconf.inc}
  8. { Type declarations }
  9. type
  10. {Byte = usigned char; 8 bits}
  11. Bytef = byte;
  12. charf = byte;
  13. {$IFDEF FPC}
  14. int = longint;
  15. {$ELSE}
  16. int = integer;
  17. {$ENDIF}
  18. intf = int;
  19. {$IFDEF MSDOS}
  20. uInt = Word;
  21. {$ELSE}
  22. {$IFDEF FPC}
  23. uInt = longint; { 16 bits or more }
  24. {$INFO Cardinal}
  25. {$ELSE}
  26. uInt = cardinal; { 16 bits or more }
  27. {$ENDIF}
  28. {$ENDIF}
  29. uIntf = uInt;
  30. Long = longint;
  31. uLong = LongInt; { 32 bits or more }
  32. uLongf = uLong;
  33. voidp = pointer;
  34. voidpf = voidp;
  35. pBytef = ^Bytef;
  36. pIntf = ^intf;
  37. puIntf = ^uIntf;
  38. puLong = ^uLongf;
  39. ptr2int = uInt;
  40. { a pointer to integer casting is used to do pointer arithmetic.
  41. ptr2int must be an integer type and sizeof(ptr2int) must be less
  42. than sizeof(pointer) - Nomssi }
  43. type
  44. zByteArray = array[0..(MaxInt div SizeOf(Bytef))-1] of Bytef;
  45. pzByteArray = ^zByteArray;
  46. type
  47. zIntfArray = array[0..(MaxInt div SizeOf(Intf))-1] of Intf;
  48. pzIntfArray = ^zIntfArray;
  49. type
  50. zuIntArray = array[0..(MaxInt div SizeOf(uInt))-1] of uInt;
  51. PuIntArray = ^zuIntArray;
  52. { Type declarations - only for deflate }
  53. type
  54. uch = Byte;
  55. uchf = uch; { FAR }
  56. ush = Word;
  57. ushf = ush;
  58. ulg = LongInt;
  59. unsigned = uInt;
  60. pcharf = ^charf;
  61. puchf = ^uchf;
  62. pushf = ^ushf;
  63. type
  64. zuchfArray = zByteArray;
  65. puchfArray = ^zuchfArray;
  66. type
  67. zushfArray = array[0..(MaxInt div SizeOf(ushf))-1] of ushf;
  68. pushfArray = ^zushfArray;
  69. procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt);
  70. function zmemcmp(s1p, s2p : pBytef; len : uInt) : int;
  71. procedure zmemzero(destp : pBytef; len : uInt);
  72. procedure zcfree(opaque : voidpf; ptr : voidpf);
  73. function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf;
  74. implementation
  75. {$ifdef ver80}
  76. {$define Delphi16}
  77. {$endif}
  78. {$ifdef ver70}
  79. {$define HugeMem}
  80. {$endif}
  81. {$ifdef ver60}
  82. {$define HugeMem}
  83. {$endif}
  84. {$IFDEF CALLDOS}
  85. uses
  86. WinDos;
  87. {$ENDIF}
  88. {$IFDEF Delphi16}
  89. uses
  90. WinTypes,
  91. WinProcs;
  92. {$ENDIF}
  93. {$IFNDEF FPC}
  94. {$IFDEF DPMI}
  95. uses
  96. WinAPI;
  97. {$ENDIF}
  98. {$ENDIF}
  99. {$IFDEF CALLDOS}
  100. { reduce your application memory footprint with $M before using this }
  101. function dosAlloc (Size : Longint) : Pointer;
  102. var
  103. regs: TRegisters;
  104. begin
  105. regs.bx := (Size + 15) div 16; { number of 16-bytes-paragraphs }
  106. regs.ah := $48; { Allocate memory block }
  107. msdos(regs);
  108. if regs.Flags and FCarry <> 0 then
  109. DosAlloc := NIL
  110. else
  111. DosAlloc := Ptr(regs.ax, 0);
  112. end;
  113. function dosFree(P : pointer) : boolean;
  114. var
  115. regs: TRegisters;
  116. begin
  117. dosFree := FALSE;
  118. regs.bx := Seg(P^); { segment }
  119. if Ofs(P) <> 0 then
  120. exit;
  121. regs.ah := $49; { Free memory block }
  122. msdos(regs);
  123. dosFree := (regs.Flags and FCarry = 0);
  124. end;
  125. {$ENDIF}
  126. type
  127. LH = record
  128. L, H : word;
  129. end;
  130. {$IFDEF HugeMem}
  131. {$define HEAP_LIST}
  132. {$endif}
  133. {$IFDEF HEAP_LIST} {--- to avoid Mark and Release --- }
  134. const
  135. MaxAllocEntries = 50;
  136. type
  137. TMemRec = record
  138. orgvalue,
  139. value : pointer;
  140. size: longint;
  141. end;
  142. const
  143. allocatedCount : 0..MaxAllocEntries = 0;
  144. var
  145. allocatedList : array[0..MaxAllocEntries-1] of TMemRec;
  146. function NewAllocation(ptr0, ptr : pointer; memsize : longint) : boolean;
  147. begin
  148. if (allocatedCount < MaxAllocEntries) and (ptr0 <> NIL) then
  149. begin
  150. with allocatedList[allocatedCount] do
  151. begin
  152. orgvalue := ptr0;
  153. value := ptr;
  154. size := memsize;
  155. end;
  156. Inc(allocatedCount); { we don't check for duplicate }
  157. NewAllocation := TRUE;
  158. end
  159. else
  160. NewAllocation := FALSE;
  161. end;
  162. {$ENDIF}
  163. {$IFDEF HugeMem}
  164. { The code below is extremely version specific to the TP 6/7 heap manager!!}
  165. type
  166. PFreeRec = ^TFreeRec;
  167. TFreeRec = record
  168. next: PFreeRec;
  169. size: Pointer;
  170. end;
  171. type
  172. HugePtr = voidpf;
  173. procedure IncPtr(var p:pointer;count:word);
  174. { Increments pointer }
  175. begin
  176. inc(LH(p).L,count);
  177. if LH(p).L < count then
  178. inc(LH(p).H,SelectorInc); { $1000 }
  179. end;
  180. procedure DecPtr(var p:pointer;count:word);
  181. { decrements pointer }
  182. begin
  183. if count > LH(p).L then
  184. dec(LH(p).H,SelectorInc);
  185. dec(LH(p).L,Count);
  186. end;
  187. procedure IncPtrLong(var p:pointer;count:longint);
  188. { Increments pointer; assumes count > 0 }
  189. begin
  190. inc(LH(p).H,SelectorInc*LH(count).H);
  191. inc(LH(p).L,LH(Count).L);
  192. if LH(p).L < LH(count).L then
  193. inc(LH(p).H,SelectorInc);
  194. end;
  195. procedure DecPtrLong(var p:pointer;count:longint);
  196. { Decrements pointer; assumes count > 0 }
  197. begin
  198. if LH(count).L > LH(p).L then
  199. dec(LH(p).H,SelectorInc);
  200. dec(LH(p).L,LH(Count).L);
  201. dec(LH(p).H,SelectorInc*LH(Count).H);
  202. end;
  203. { The next section is for real mode only }
  204. function Normalized(p : pointer) : pointer;
  205. var
  206. count : word;
  207. begin
  208. count := LH(p).L and $FFF0;
  209. Normalized := Ptr(LH(p).H + (count shr 4), LH(p).L and $F);
  210. end;
  211. procedure FreeHuge(var p:HugePtr; size : longint);
  212. const
  213. blocksize = $FFF0;
  214. var
  215. block : word;
  216. begin
  217. while size > 0 do
  218. begin
  219. { block := minimum(size, blocksize); }
  220. if size > blocksize then
  221. block := blocksize
  222. else
  223. block := size;
  224. dec(size,block);
  225. freemem(p,block);
  226. IncPtr(p,block); { we may get ptr($xxxx, $fff8) and 31 bytes left }
  227. p := Normalized(p); { to free, so we must normalize }
  228. end;
  229. end;
  230. function FreeMemHuge(ptr : pointer) : boolean;
  231. var
  232. i : integer; { -1..MaxAllocEntries }
  233. begin
  234. FreeMemHuge := FALSE;
  235. i := allocatedCount - 1;
  236. while (i >= 0) do
  237. begin
  238. if (ptr = allocatedList[i].value) then
  239. begin
  240. with allocatedList[i] do
  241. FreeHuge(orgvalue, size);
  242. Move(allocatedList[i+1], allocatedList[i],
  243. SizeOf(TMemRec)*(allocatedCount - 1 - i));
  244. Dec(allocatedCount);
  245. FreeMemHuge := TRUE;
  246. break;
  247. end;
  248. Dec(i);
  249. end;
  250. end;
  251. procedure GetMemHuge(var p:HugePtr;memsize:Longint);
  252. const
  253. blocksize = $FFF0;
  254. var
  255. size : longint;
  256. prev,free : PFreeRec;
  257. save,temp : pointer;
  258. block : word;
  259. begin
  260. p := NIL;
  261. { Handle the easy cases first }
  262. if memsize > maxavail then
  263. exit
  264. else
  265. if memsize <= blocksize then
  266. begin
  267. getmem(p, memsize);
  268. if not NewAllocation(p, p, memsize) then
  269. begin
  270. FreeMem(p, memsize);
  271. p := NIL;
  272. end;
  273. end
  274. else
  275. begin
  276. size := memsize + 15;
  277. { Find the block that has enough space }
  278. prev := PFreeRec(@freeList);
  279. free := prev^.next;
  280. while (free <> heapptr) and (ptr2int(free^.size) < size) do
  281. begin
  282. prev := free;
  283. free := prev^.next;
  284. end;
  285. { Now free points to a region with enough space; make it the first one and
  286. multiple allocations will be contiguous. }
  287. save := freelist;
  288. freelist := free;
  289. { In TP 6, this works; check against other heap managers }
  290. while size > 0 do
  291. begin
  292. { block := minimum(size, blocksize); }
  293. if size > blocksize then
  294. block := blocksize
  295. else
  296. block := size;
  297. dec(size,block);
  298. getmem(temp,block);
  299. end;
  300. { We've got what we want now; just sort things out and restore the
  301. free list to normal }
  302. p := free;
  303. if prev^.next <> freelist then
  304. begin
  305. prev^.next := freelist;
  306. freelist := save;
  307. end;
  308. if (p <> NIL) then
  309. begin
  310. { return pointer with 0 offset }
  311. temp := p;
  312. if Ofs(p^)<>0 Then
  313. p := Ptr(Seg(p^)+1,0); { hack }
  314. if not NewAllocation(temp, p, memsize + 15) then
  315. begin
  316. FreeHuge(temp, size);
  317. p := NIL;
  318. end;
  319. end;
  320. end;
  321. end;
  322. {$ENDIF}
  323. procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt);
  324. begin
  325. Move(sourcep^, destp^, len);
  326. end;
  327. function zmemcmp(s1p, s2p : pBytef; len : uInt) : int;
  328. var
  329. j : uInt;
  330. source,
  331. dest : pBytef;
  332. begin
  333. source := s1p;
  334. dest := s2p;
  335. for j := 0 to pred(len) do
  336. begin
  337. if (source^ <> dest^) then
  338. begin
  339. zmemcmp := 2*Ord(source^ > dest^)-1;
  340. exit;
  341. end;
  342. Inc(source);
  343. Inc(dest);
  344. end;
  345. zmemcmp := 0;
  346. end;
  347. procedure zmemzero(destp : pBytef; len : uInt);
  348. begin
  349. FillChar(destp^, len, 0);
  350. end;
  351. procedure zcfree(opaque : voidpf; ptr : voidpf);
  352. {$ifdef Delphi16}
  353. var
  354. Handle : THandle;
  355. {$endif}
  356. {$IFDEF FPC}
  357. var
  358. memsize : uint;
  359. {$ENDIF}
  360. begin
  361. {$IFDEF DPMI}
  362. {h :=} GlobalFreePtr(ptr);
  363. {$ELSE}
  364. {$IFDEF CALL_DOS}
  365. dosFree(ptr);
  366. {$ELSE}
  367. {$ifdef HugeMem}
  368. FreeMemHuge(ptr);
  369. {$else}
  370. {$ifdef Delphi16}
  371. Handle := GlobalHandle(LH(ptr).H); { HiWord(LongInt(ptr)) }
  372. GlobalUnLock(Handle);
  373. GlobalFree(Handle);
  374. {$else}
  375. {$IFDEF FPC}
  376. ASM
  377. mov ptr,%edi
  378. subl $4,%edi
  379. mov (%edi),%eax
  380. mov %eax,memsize
  381. mov %edi,ptr
  382. END ['EAX','EDI'];
  383. FreeMem(ptr,memsize); { Delphi 2,3,4 }
  384. {$ELSE}
  385. FreeMem(ptr); { Delphi 2,3,4 }
  386. {$ENDIF}
  387. {$endif}
  388. {$endif}
  389. {$ENDIF}
  390. {$ENDIF}
  391. end;
  392. function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf;
  393. var
  394. p : voidpf;
  395. memsize : LongInt;
  396. {$ifdef Delphi16}
  397. handle : THandle;
  398. {$endif}
  399. begin
  400. memsize := Long(items) * size;
  401. {$IFDEF DPMI}
  402. p := GlobalAllocPtr(gmem_moveable, memsize);
  403. {$ELSE}
  404. {$IFDEF CALLDOS}
  405. p := dosAlloc(memsize);
  406. {$ELSE}
  407. {$ifdef HugeMem}
  408. GetMemHuge(p, memsize);
  409. {$else}
  410. {$ifdef Delphi16}
  411. Handle := GlobalAlloc(HeapAllocFlags, memsize);
  412. p := GlobalLock(Handle);
  413. {$else}
  414. {$IFDEF FPC}
  415. inc(memsize,4);
  416. GetMem(p, memsize); { Delphi: p := AllocMem(memsize); }
  417. ASM
  418. mov memsize,%eax
  419. mov p,%edi
  420. stosl
  421. mov %edi,p
  422. END ['EAX','EDI'];
  423. {$ELSE}
  424. GetMem(p, memsize); { Delphi: p := AllocMem(memsize); }
  425. {$ENDIF}
  426. {$endif}
  427. {$endif}
  428. {$ENDIF}
  429. {$ENDIF}
  430. zcalloc := p;
  431. end;
  432. end.
  433. { edited from a SWAG posting:
  434. In Turbo Pascal 6, the heap is the memory allocated when using the Procedures 'New' and
  435. 'GetMem'. The heap starts at the address location pointed to by 'Heaporg' and
  436. grows to higher addresses as more memory is allocated. The top of the heap,
  437. the first address of allocatable memory space above the allocated memory
  438. space, is pointed to by 'HeapPtr'.
  439. Memory is deallocated by the Procedures 'Dispose' and 'FreeMem'. As memory
  440. blocks are deallocated more memory becomes available, but..... When a block
  441. of memory, which is not the top-most block in the heap is deallocated, a gap
  442. in the heap will appear. to keep track of these gaps Turbo Pascal maintains
  443. a so called free list.
  444. The Function 'MaxAvail' holds the size of the largest contiguous free block
  445. _in_ the heap. The Function 'MemAvail' holds the sum of all free blocks in
  446. the heap.
  447. TP6.0 keeps track of the free blocks by writing a 'free list Record' to the
  448. first eight Bytes of the freed memory block! A (TP6.0) free-list Record
  449. contains two four Byte Pointers of which the first one points to the next
  450. free memory block, the second Pointer is not a Real Pointer but contains the
  451. size of the memory block.
  452. Summary
  453. TP6.0 maintains a linked list with block sizes and Pointers to the _next_
  454. free block. An extra heap Variable 'Heapend' designate the end of the heap.
  455. When 'HeapPtr' and 'FreeList' have the same value, the free list is empty.
  456. TP6.0 Heapend
  457. ÚÄÄÄÄÄÄÄÄÄ¿ <ÄÄÄÄ
  458. ³ ³
  459. ³ ³
  460. ³ ³
  461. ³ ³
  462. ³ ³
  463. ³ ³
  464. ³ ³
  465. ³ ³ HeapPtr
  466. ÚÄ>ÃÄÄÄÄÄÄÄÄÄ´ <ÄÄÄÄ
  467. ³ ³ ³
  468. ³ ÃÄÄÄÄÄÄÄÄÄ´
  469. ÀÄij Free ³
  470. ÚÄ>ÃÄÄÄÄÄÄÄÄÄ´
  471. ³ ³ ³
  472. ³ ÃÄÄÄÄÄÄÄÄÄ´
  473. ÀÄij Free ³ FreeList
  474. ÃÄÄÄÄÄÄÄÄÄ´ <ÄÄÄÄ
  475. ³ ³ Heaporg
  476. ÃÄÄÄÄÄÄÄÄÄ´ <ÄÄÄÄ
  477. }