zutil.pas 12 KB

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