zutil.pas 11 KB

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