home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume34 / jpeg / part06 < prev    next >
Encoding:
Text File  |  1992-12-16  |  57.8 KB  |  1,778 lines

  1. Newsgroups: comp.sources.misc
  2. From: jpeg-info@uunet.uu.net (Independent JPEG Group)
  3. Subject:  v34i060:  jpeg - JPEG image compression, Part06/18
  4. Message-ID: <1992Dec17.041729.23463@sparky.imd.sterling.com>
  5. X-Md4-Signature: 28131414719afba0209e9e66c3532a5d
  6. Date: Thu, 17 Dec 1992 04:17:29 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: jpeg-info@uunet.uu.net (Independent JPEG Group)
  10. Posting-number: Volume 34, Issue 60
  11. Archive-name: jpeg/part06
  12. Environment: UNIX, VMS, MS-DOS, Mac, Amiga, Atari, Cray
  13. Supersedes: jpeg: Volume 29, Issue 1-18
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then feed it
  17. # into a shell via "sh file" or similar.  To overwrite existing files,
  18. # type "sh file -c".
  19. # Contents:  jmemdos.c jmemmgr.c
  20. # Wrapped by kent@sparky on Wed Dec 16 20:52:26 1992
  21. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 6 (of 18)."'
  24. if test -f 'jmemdos.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'jmemdos.c'\"
  26. else
  27.   echo shar: Extracting \"'jmemdos.c'\" \(17557 characters\)
  28.   sed "s/^X//" >'jmemdos.c' <<'END_OF_FILE'
  29. X/*
  30. X * jmemdos.c  (jmemsys.c)
  31. X *
  32. X * Copyright (C) 1992, Thomas G. Lane.
  33. X * This file is part of the Independent JPEG Group's software.
  34. X * For conditions of distribution and use, see the accompanying README file.
  35. X *
  36. X * This file provides an MS-DOS-compatible implementation of the system-
  37. X * dependent portion of the JPEG memory manager.  Temporary data can be
  38. X * stored in extended or expanded memory as well as in regular DOS files.
  39. X *
  40. X * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
  41. X * if you compile in a small-data memory model; it should NOT be defined if
  42. X * you use a large-data memory model.  This file is not recommended if you
  43. X * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
  44. X *
  45. X * Based on code contributed by Ge' Weijers.
  46. X */
  47. X
  48. X/*
  49. X * If you have both extended and expanded memory, you may want to change the
  50. X * order in which they are tried in jopen_backing_store.  On a 286 machine
  51. X * expanded memory is usually faster, since extended memory access involves
  52. X * an expensive protected-mode-and-back switch.  On 386 and better, extended
  53. X * memory is usually faster.  As distributed, the code tries extended memory
  54. X * first (what? not everyone has a 386? :-).
  55. X *
  56. X * You can disable use of extended/expanded memory entirely by altering these
  57. X * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
  58. X */
  59. X
  60. X#ifndef XMS_SUPPORTED
  61. X#define XMS_SUPPORTED  1
  62. X#endif
  63. X#ifndef EMS_SUPPORTED
  64. X#define EMS_SUPPORTED  1
  65. X#endif
  66. X
  67. X
  68. X#include "jinclude.h"
  69. X#include "jmemsys.h"
  70. X
  71. X#ifdef INCLUDES_ARE_ANSI
  72. X#include <stdlib.h>        /* to declare malloc(), free(), getenv() */
  73. X#else
  74. Xextern void * malloc PP((size_t size));
  75. Xextern void free PP((void *ptr));
  76. Xextern char * getenv PP((const char * name));
  77. X#endif
  78. X
  79. X#ifdef NEED_FAR_POINTERS
  80. X
  81. X#ifdef __TURBOC__
  82. X/* These definitions work for Borland C (Turbo C) */
  83. X#include <alloc.h>        /* need farmalloc(), farfree() */
  84. X#define far_malloc(x)    farmalloc(x)
  85. X#define far_free(x)    farfree(x)
  86. X#else
  87. X/* These definitions work for Microsoft C and compatible compilers */
  88. X#include <malloc.h>        /* need _fmalloc(), _ffree() */
  89. X#define far_malloc(x)    _fmalloc(x)
  90. X#define far_free(x)    _ffree(x)
  91. X#endif
  92. X
  93. X#endif
  94. X
  95. X#ifdef DONT_USE_B_MODE        /* define mode parameters for fopen() */
  96. X#define READ_BINARY    "r"
  97. X#else
  98. X#define READ_BINARY    "rb"
  99. X#endif
  100. X
  101. X
  102. X/*
  103. X * Declarations for assembly-language support routines (see jmemdosa.asm).
  104. X *
  105. X * The functions are declared "far" as are all pointer arguments;
  106. X * this ensures the assembly source code will work regardless of the
  107. X * compiler memory model.  We assume "short" is 16 bits, "long" is 32.
  108. X */
  109. X
  110. Xtypedef void far * XMSDRIVER;    /* actually a pointer to code */
  111. Xtypedef struct {        /* registers for calling XMS driver */
  112. X    unsigned short ax, dx, bx;
  113. X    void far * ds_si;
  114. X      } XMScontext;
  115. Xtypedef struct {        /* registers for calling EMS driver */
  116. X    unsigned short ax, dx, bx;
  117. X    void far * ds_si;
  118. X      } EMScontext;
  119. X
  120. XEXTERN short far jdos_open PP((short far * handle, char far * filename));
  121. XEXTERN short far jdos_close PP((short handle));
  122. XEXTERN short far jdos_seek PP((short handle, long offset));
  123. XEXTERN short far jdos_read PP((short handle, void far * buffer,
  124. X                   unsigned short count));
  125. XEXTERN short far jdos_write PP((short handle, void far * buffer,
  126. X                unsigned short count));
  127. XEXTERN void far jxms_getdriver PP((XMSDRIVER far *));
  128. XEXTERN void far jxms_calldriver PP((XMSDRIVER, XMScontext far *));
  129. XEXTERN short far jems_available PP((void));
  130. XEXTERN void far jems_calldriver PP((EMScontext far *));
  131. X
  132. X
  133. Xstatic external_methods_ptr methods; /* saved for access to error_exit */
  134. X
  135. Xstatic long total_used;        /* total FAR memory requested so far */
  136. X
  137. X
  138. X/*
  139. X * Selection of a file name for a temporary file.
  140. X * This is highly system-dependent, and you may want to customize it.
  141. X */
  142. X
  143. Xstatic int next_file_num;    /* to distinguish among several temp files */
  144. X
  145. XLOCAL void
  146. Xselect_file_name (char * fname)
  147. X{
  148. X  const char * env;
  149. X  char * ptr;
  150. X  FILE * tfile;
  151. X
  152. X  /* Keep generating file names till we find one that's not in use */
  153. X  for (;;) {
  154. X    /* Get temp directory name from environment TMP or TEMP variable;
  155. X     * if none, use "."
  156. X     */
  157. X    if ((env = (const char *) getenv("TMP")) == NULL)
  158. X      if ((env = (const char *) getenv("TEMP")) == NULL)
  159. X    env = ".";
  160. X    if (*env == '\0')        /* null string means "." */
  161. X      env = ".";
  162. X    ptr = fname;        /* copy name to fname */
  163. X    while (*env != '\0')
  164. X      *ptr++ = *env++;
  165. X    if (ptr[-1] != '\\' && ptr[-1] != '/')
  166. X      *ptr++ = '\\';        /* append backslash if not in env variable */
  167. X    /* Append a suitable file name */
  168. X    next_file_num++;        /* advance counter */
  169. X    sprintf(ptr, "JPG%03d.TMP", next_file_num);
  170. X    /* Probe to see if file name is already in use */
  171. X    if ((tfile = fopen(fname, READ_BINARY)) == NULL)
  172. X      break;
  173. X    fclose(tfile);        /* oops, it's there; close tfile & try again */
  174. X  }
  175. X}
  176. X
  177. X
  178. X/*
  179. X * Near-memory allocation and freeing are controlled by the regular library
  180. X * routines malloc() and free().
  181. X */
  182. X
  183. XGLOBAL void *
  184. Xjget_small (size_t sizeofobject)
  185. X{
  186. X  /* near data space is NOT counted in total_used */
  187. X#ifndef NEED_FAR_POINTERS
  188. X  total_used += sizeofobject;
  189. X#endif
  190. X  return (void *) malloc(sizeofobject);
  191. X}
  192. X
  193. XGLOBAL void
  194. Xjfree_small (void * object)
  195. X{
  196. X  free(object);
  197. X}
  198. X
  199. X
  200. X/*
  201. X * Far-memory allocation and freeing
  202. X */
  203. X
  204. X#ifdef NEED_FAR_POINTERS
  205. X
  206. XGLOBAL void FAR *
  207. Xjget_large (size_t sizeofobject)
  208. X{
  209. X  total_used += sizeofobject;
  210. X  return (void FAR *) far_malloc(sizeofobject);
  211. X}
  212. X
  213. XGLOBAL void
  214. Xjfree_large (void FAR * object)
  215. X{
  216. X  far_free(object);
  217. X}
  218. X
  219. X#endif
  220. X
  221. X
  222. X/*
  223. X * This routine computes the total memory space available for allocation.
  224. X * It's impossible to do this in a portable way; our current solution is
  225. X * to make the user tell us (with a default value set at compile time).
  226. X * If you can actually get the available space, it's a good idea to subtract
  227. X * a slop factor of 5% or so.
  228. X */
  229. X
  230. X#ifndef DEFAULT_MAX_MEM        /* so can override from makefile */
  231. X#define DEFAULT_MAX_MEM        300000L /* for total usage about 450K */
  232. X#endif
  233. X
  234. XGLOBAL long
  235. Xjmem_available (long min_bytes_needed, long max_bytes_needed)
  236. X{
  237. X  return methods->max_memory_to_use - total_used;
  238. X}
  239. X
  240. X
  241. X/*
  242. X * Backing store (temporary file) management.
  243. X * Backing store objects are only used when the value returned by
  244. X * jmem_available is less than the total space needed.  You can dispense
  245. X * with these routines if you have plenty of virtual memory; see jmemnobs.c.
  246. X */
  247. X
  248. X/*
  249. X * For MS-DOS we support three types of backing storage:
  250. X *   1. Conventional DOS files.  We access these by direct DOS calls rather
  251. X *      than via the stdio package.  This provides a bit better performance,
  252. X *      but the real reason is that the buffers to be read or written are FAR.
  253. X *      The stdio library for small-data memory models can't cope with that.
  254. X *   2. Extended memory, accessed per the XMS V2.0 specification.
  255. X *   3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
  256. X * You'll need copies of those specs to make sense of the related code.
  257. X * The specs are available by Internet FTP from SIMTEL20 and its various
  258. X * mirror sites; see microsoft/xms20.arc and info/limems41.zip.
  259. X */
  260. X
  261. X
  262. X/*
  263. X * Access methods for a DOS file.
  264. X */
  265. X
  266. X
  267. XMETHODDEF void
  268. Xread_file_store (backing_store_ptr info, void FAR * buffer_address,
  269. X         long file_offset, long byte_count)
  270. X{
  271. X  if (jdos_seek(info->handle.file_handle, file_offset))
  272. X    ERREXIT(methods, "seek failed on temporary file");
  273. X  /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  274. X  if (byte_count > 65535L)    /* safety check */
  275. X    ERREXIT(methods, "MAX_ALLOC_CHUNK should be less than 64K");
  276. X  if (jdos_read(info->handle.file_handle, buffer_address,
  277. X        (unsigned short) byte_count))
  278. X    ERREXIT(methods, "read failed on temporary file");
  279. X}
  280. X
  281. X
  282. XMETHODDEF void
  283. Xwrite_file_store (backing_store_ptr info, void FAR * buffer_address,
  284. X          long file_offset, long byte_count)
  285. X{
  286. X  if (jdos_seek(info->handle.file_handle, file_offset))
  287. X    ERREXIT(methods, "seek failed on temporary file");
  288. X  /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  289. X  if (byte_count > 65535L)    /* safety check */
  290. X    ERREXIT(methods, "MAX_ALLOC_CHUNK should be less than 64K");
  291. X  if (jdos_write(info->handle.file_handle, buffer_address,
  292. X         (unsigned short) byte_count))
  293. X    ERREXIT(methods, "write failed on temporary file --- out of disk space?");
  294. X}
  295. X
  296. X
  297. XMETHODDEF void
  298. Xclose_file_store (backing_store_ptr info)
  299. X{
  300. X  jdos_close(info->handle.file_handle);    /* close the file */
  301. X  remove(info->temp_name);    /* delete the file */
  302. X/* If your system doesn't have remove(), try unlink() instead.
  303. X * remove() is the ANSI-standard name for this function, but
  304. X * unlink() was more common in pre-ANSI systems.
  305. X */
  306. X  TRACEMS1(methods, 1, "Closed DOS file %d", info->handle.file_handle);
  307. X}
  308. X
  309. X
  310. XLOCAL boolean
  311. Xopen_file_store (backing_store_ptr info, long total_bytes_needed)
  312. X{
  313. X  short handle;
  314. X  char tracemsg[TEMP_NAME_LENGTH+40];
  315. X
  316. X  select_file_name(info->temp_name);
  317. X  if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
  318. X    /* hack to get around TRACEMS' inability to handle string parameters */
  319. X    sprintf(tracemsg, "Failed to create temporary file %s", info->temp_name);
  320. X    ERREXIT(methods, tracemsg);    /* jopen_backing_store will fail anyway */
  321. X    return FALSE;
  322. X  }
  323. X  info->handle.file_handle = handle;
  324. X  info->read_backing_store = read_file_store;
  325. X  info->write_backing_store = write_file_store;
  326. X  info->close_backing_store = close_file_store;
  327. X  /* hack to get around TRACEMS' inability to handle string parameters */
  328. X  sprintf(tracemsg, "Opened DOS file %d  %s", handle, info->temp_name);
  329. X  TRACEMS(methods, 1, tracemsg);
  330. X  return TRUE;            /* succeeded */
  331. X}
  332. X
  333. X
  334. X/*
  335. X * Access methods for extended memory.
  336. X */
  337. X
  338. X#if XMS_SUPPORTED
  339. X
  340. Xstatic XMSDRIVER xms_driver;    /* saved address of XMS driver */
  341. X
  342. Xtypedef union {            /* either long offset or real-mode pointer */
  343. X    long offset;
  344. X    void far * ptr;
  345. X      } XMSPTR;
  346. X
  347. Xtypedef struct {        /* XMS move specification structure */
  348. X    long length;
  349. X    XMSH src_handle;
  350. X    XMSPTR src;
  351. X    XMSH dst_handle;
  352. X    XMSPTR dst;
  353. X      } XMSspec;
  354. X
  355. X#define ODD(X)    (((X) & 1L) != 0)
  356. X
  357. X
  358. XMETHODDEF void
  359. Xread_xms_store (backing_store_ptr info, void FAR * buffer_address,
  360. X        long file_offset, long byte_count)
  361. X{
  362. X  XMScontext ctx;
  363. X  XMSspec spec;
  364. X  char endbuffer[2];
  365. X
  366. X  /* The XMS driver can't cope with an odd length, so handle the last byte
  367. X   * specially if byte_count is odd.  We don't expect this to be common.
  368. X   */
  369. X
  370. X  spec.length = byte_count & (~ 1L);
  371. X  spec.src_handle = info->handle.xms_handle;
  372. X  spec.src.offset = file_offset;
  373. X  spec.dst_handle = 0;
  374. X  spec.dst.ptr = buffer_address;
  375. X  
  376. X  ctx.ds_si = (void far *) & spec;
  377. X  ctx.ax = 0x0b00;        /* EMB move */
  378. X  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  379. X  if (ctx.ax != 1)
  380. X    ERREXIT(methods, "read from extended memory failed");
  381. X
  382. X  if (ODD(byte_count)) {
  383. X    read_xms_store(info, (void FAR *) endbuffer,
  384. X           file_offset + byte_count - 1L, 2L);
  385. X    ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
  386. X  }
  387. X}
  388. X
  389. X
  390. XMETHODDEF void
  391. Xwrite_xms_store (backing_store_ptr info, void FAR * buffer_address,
  392. X         long file_offset, long byte_count)
  393. X{
  394. X  XMScontext ctx;
  395. X  XMSspec spec;
  396. X  char endbuffer[2];
  397. X
  398. X  /* The XMS driver can't cope with an odd length, so handle the last byte
  399. X   * specially if byte_count is odd.  We don't expect this to be common.
  400. X   */
  401. X
  402. X  spec.length = byte_count & (~ 1L);
  403. X  spec.src_handle = 0;
  404. X  spec.src.ptr = buffer_address;
  405. X  spec.dst_handle = info->handle.xms_handle;
  406. X  spec.dst.offset = file_offset;
  407. X
  408. X  ctx.ds_si = (void far *) & spec;
  409. X  ctx.ax = 0x0b00;        /* EMB move */
  410. X  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  411. X  if (ctx.ax != 1)
  412. X    ERREXIT(methods, "write to extended memory failed");
  413. X
  414. X  if (ODD(byte_count)) {
  415. X    read_xms_store(info, (void FAR *) endbuffer,
  416. X           file_offset + byte_count - 1L, 2L);
  417. X    endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
  418. X    write_xms_store(info, (void FAR *) endbuffer,
  419. X            file_offset + byte_count - 1L, 2L);
  420. X  }
  421. X}
  422. X
  423. X
  424. XMETHODDEF void
  425. Xclose_xms_store (backing_store_ptr info)
  426. X{
  427. X  XMScontext ctx;
  428. X
  429. X  ctx.dx = info->handle.xms_handle;
  430. X  ctx.ax = 0x0a00;
  431. X  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  432. X  TRACEMS1(methods, 1, "Freed XMS handle %u", info->handle.xms_handle);
  433. X  /* we ignore any error return from the driver */
  434. X}
  435. X
  436. X
  437. XLOCAL boolean
  438. Xopen_xms_store (backing_store_ptr info, long total_bytes_needed)
  439. X{
  440. X  XMScontext ctx;
  441. X
  442. X  /* Get address of XMS driver */
  443. X  jxms_getdriver((XMSDRIVER far *) & xms_driver);
  444. X  if (xms_driver == NULL)
  445. X    return FALSE;        /* no driver to be had */
  446. X
  447. X  /* Get version number, must be >= 2.00 */
  448. X  ctx.ax = 0x0000;
  449. X  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  450. X  if (ctx.ax < (unsigned short) 0x0200)
  451. X    return FALSE;
  452. X
  453. X  /* Try to get space (expressed in kilobytes) */
  454. X  ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
  455. X  ctx.ax = 0x0900;
  456. X  jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  457. X  if (ctx.ax != 1)
  458. X    return FALSE;
  459. X
  460. X  /* Succeeded, save the handle and away we go */
  461. X  info->handle.xms_handle = ctx.dx;
  462. X  info->read_backing_store = read_xms_store;
  463. X  info->write_backing_store = write_xms_store;
  464. X  info->close_backing_store = close_xms_store;
  465. X  TRACEMS1(methods, 1, "Obtained XMS handle %u", ctx.dx);
  466. X  return TRUE;            /* succeeded */
  467. X}
  468. X
  469. X#endif /* XMS_SUPPORTED */
  470. X
  471. X
  472. X/*
  473. X * Access methods for expanded memory.
  474. X */
  475. X
  476. X#if EMS_SUPPORTED
  477. X
  478. Xtypedef union {            /* either offset/page or real-mode pointer */
  479. X    struct { unsigned short offset, page; } ems;
  480. X    void far * ptr;
  481. X      } EMSPTR;
  482. X
  483. Xtypedef struct {        /* EMS move specification structure */
  484. X    long length;
  485. X    char src_type;        /* 1 = EMS, 0 = conventional memory */
  486. X    EMSH src_handle;    /* use 0 if conventional memory */
  487. X    EMSPTR src;
  488. X    char dst_type;
  489. X    EMSH dst_handle;
  490. X    EMSPTR dst;
  491. X      } EMSspec;
  492. X
  493. X#define EMSPAGESIZE    16384L    /* gospel, see the EMS specs */
  494. X
  495. X#define HIBYTE(W)  (((W) >> 8) & 0xFF)
  496. X#define LOBYTE(W)  ((W) & 0xFF)
  497. X
  498. X
  499. XMETHODDEF void
  500. Xread_ems_store (backing_store_ptr info, void FAR * buffer_address,
  501. X        long file_offset, long byte_count)
  502. X{
  503. X  EMScontext ctx;
  504. X  EMSspec spec;
  505. X
  506. X  spec.length = byte_count;
  507. X  spec.src_type = 1;
  508. X  spec.src_handle = info->handle.ems_handle;
  509. X  spec.src.ems.page = (unsigned short) (file_offset / EMSPAGESIZE);
  510. X  spec.src.ems.offset = (unsigned short) (file_offset % EMSPAGESIZE);
  511. X  spec.dst_type = 0;
  512. X  spec.dst_handle = 0;
  513. X  spec.dst.ptr = buffer_address;
  514. X  
  515. X  ctx.ds_si = (void far *) & spec;
  516. X  ctx.ax = 0x5700;        /* move memory region */
  517. X  jems_calldriver((EMScontext far *) & ctx);
  518. X  if (HIBYTE(ctx.ax) != 0)
  519. X    ERREXIT(methods, "read from expanded memory failed");
  520. X}
  521. X
  522. X
  523. XMETHODDEF void
  524. Xwrite_ems_store (backing_store_ptr info, void FAR * buffer_address,
  525. X         long file_offset, long byte_count)
  526. X{
  527. X  EMScontext ctx;
  528. X  EMSspec spec;
  529. X
  530. X  spec.length = byte_count;
  531. X  spec.src_type = 0;
  532. X  spec.src_handle = 0;
  533. X  spec.src.ptr = buffer_address;
  534. X  spec.dst_type = 1;
  535. X  spec.dst_handle = info->handle.ems_handle;
  536. X  spec.dst.ems.page = (unsigned short) (file_offset / EMSPAGESIZE);
  537. X  spec.dst.ems.offset = (unsigned short) (file_offset % EMSPAGESIZE);
  538. X  
  539. X  ctx.ds_si = (void far *) & spec;
  540. X  ctx.ax = 0x5700;        /* move memory region */
  541. X  jems_calldriver((EMScontext far *) & ctx);
  542. X  if (HIBYTE(ctx.ax) != 0)
  543. X    ERREXIT(methods, "write to expanded memory failed");
  544. X}
  545. X
  546. X
  547. XMETHODDEF void
  548. Xclose_ems_store (backing_store_ptr info)
  549. X{
  550. X  EMScontext ctx;
  551. X
  552. X  ctx.ax = 0x4500;
  553. X  ctx.dx = info->handle.ems_handle;
  554. X  jems_calldriver((EMScontext far *) & ctx);
  555. X  TRACEMS1(methods, 1, "Freed EMS handle %u", info->handle.ems_handle);
  556. X  /* we ignore any error return from the driver */
  557. X}
  558. X
  559. X
  560. XLOCAL boolean
  561. Xopen_ems_store (backing_store_ptr info, long total_bytes_needed)
  562. X{
  563. X  EMScontext ctx;
  564. X
  565. X  /* Is EMS driver there? */
  566. X  if (! jems_available())
  567. X    return FALSE;
  568. X
  569. X  /* Get status, make sure EMS is OK */
  570. X  ctx.ax = 0x4000;
  571. X  jems_calldriver((EMScontext far *) & ctx);
  572. X  if (HIBYTE(ctx.ax) != 0)
  573. X    return FALSE;
  574. X
  575. X  /* Get version, must be >= 4.0 */
  576. X  ctx.ax = 0x4600;
  577. X  jems_calldriver((EMScontext far *) & ctx);
  578. X  if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
  579. X    return FALSE;
  580. X
  581. X  /* Try to allocate requested space */
  582. X  ctx.ax = 0x4300;
  583. X  ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
  584. X  jems_calldriver((EMScontext far *) & ctx);
  585. X  if (HIBYTE(ctx.ax) != 0)
  586. X    return FALSE;
  587. X
  588. X  /* Succeeded, save the handle and away we go */
  589. X  info->handle.ems_handle = ctx.dx;
  590. X  info->read_backing_store = read_ems_store;
  591. X  info->write_backing_store = write_ems_store;
  592. X  info->close_backing_store = close_ems_store;
  593. X  TRACEMS1(methods, 1, "Obtained EMS handle %u", ctx.dx);
  594. X  return TRUE;            /* succeeded */
  595. X}
  596. X
  597. X#endif /* EMS_SUPPORTED */
  598. X
  599. X
  600. X/*
  601. X * Initial opening of a backing-store object.
  602. X */
  603. X
  604. XGLOBAL void
  605. Xjopen_backing_store (backing_store_ptr info, long total_bytes_needed)
  606. X{
  607. X  /* Try extended memory, then expanded memory, then regular file. */
  608. X#if XMS_SUPPORTED
  609. X  if (open_xms_store(info, total_bytes_needed))
  610. X    return;
  611. X#endif
  612. X#if EMS_SUPPORTED
  613. X  if (open_ems_store(info, total_bytes_needed))
  614. X    return;
  615. X#endif
  616. X  if (open_file_store(info, total_bytes_needed))
  617. X    return;
  618. X  ERREXIT(methods, "Failed to create temporary file");
  619. X}
  620. X
  621. X
  622. X/*
  623. X * These routines take care of any system-dependent initialization and
  624. X * cleanup required.  Keep in mind that jmem_term may be called more than
  625. X * once.
  626. X */
  627. X
  628. XGLOBAL void
  629. Xjmem_init (external_methods_ptr emethods)
  630. X{
  631. X  methods = emethods;        /* save struct addr for error exit access */
  632. X  emethods->max_memory_to_use = DEFAULT_MAX_MEM;
  633. X  total_used = 0;
  634. X  next_file_num = 0;
  635. X}
  636. X
  637. XGLOBAL void
  638. Xjmem_term (void)
  639. X{
  640. X  /* no work */
  641. X}
  642. END_OF_FILE
  643.   if test 17557 -ne `wc -c <'jmemdos.c'`; then
  644.     echo shar: \"'jmemdos.c'\" unpacked with wrong size!
  645.   fi
  646.   # end of 'jmemdos.c'
  647. fi
  648. if test -f 'jmemmgr.c' -a "${1}" != "-c" ; then 
  649.   echo shar: Will not clobber existing file \"'jmemmgr.c'\"
  650. else
  651.   echo shar: Extracting \"'jmemmgr.c'\" \(37719 characters\)
  652.   sed "s/^X//" >'jmemmgr.c' <<'END_OF_FILE'
  653. X/*
  654. X * jmemmgr.c
  655. X *
  656. X * Copyright (C) 1991, 1992, Thomas G. Lane.
  657. X * This file is part of the Independent JPEG Group's software.
  658. X * For conditions of distribution and use, see the accompanying README file.
  659. X *
  660. X * This file provides the standard system-independent memory management
  661. X * routines.  This code is usable across a wide variety of machines; most
  662. X * of the system dependencies have been isolated in a separate file.
  663. X * The major functions provided here are:
  664. X *   * bookkeeping to allow all allocated memory to be freed upon exit;
  665. X *   * policy decisions about how to divide available memory among the
  666. X *     various large arrays;
  667. X *   * control logic for swapping virtual arrays between main memory and
  668. X *     backing storage.
  669. X * The separate system-dependent file provides the actual backing-storage
  670. X * access code, and it contains the policy decision about how much total
  671. X * main memory to use.
  672. X * This file is system-dependent in the sense that some of its functions
  673. X * are unnecessary in some systems.  For example, if there is enough virtual
  674. X * memory so that backing storage will never be used, much of the big-array
  675. X * control logic could be removed.  (Of course, if you have that much memory
  676. X * then you shouldn't care about a little bit of unused code...)
  677. X *
  678. X * These routines are invoked via the methods alloc_small, free_small,
  679. X * alloc_medium, free_medium, alloc_small_sarray, free_small_sarray,
  680. X * alloc_small_barray, free_small_barray, request_big_sarray,
  681. X * request_big_barray, alloc_big_arrays, access_big_sarray, access_big_barray,
  682. X * free_big_sarray, free_big_barray, and free_all.
  683. X */
  684. X
  685. X#define AM_MEMORY_MANAGER    /* we define big_Xarray_control structs */
  686. X
  687. X#include "jinclude.h"
  688. X#include "jmemsys.h"        /* import the system-dependent declarations */
  689. X
  690. X#ifndef NO_GETENV
  691. X#ifdef INCLUDES_ARE_ANSI
  692. X#include <stdlib.h>        /* to declare getenv() */
  693. X#else
  694. Xextern char * getenv PP((const char * name));
  695. X#endif
  696. X#endif
  697. X
  698. X
  699. X/*
  700. X * On many systems it is not necessary to distinguish alloc_small from
  701. X * alloc_medium; the main case where they must be distinguished is when
  702. X * FAR pointers are distinct from regular pointers.  However, you might
  703. X * want to keep them separate if you have different system-dependent logic
  704. X * for small and large memory requests (i.e., jget_small and jget_large
  705. X * do different things).
  706. X */
  707. X
  708. X#ifdef NEED_FAR_POINTERS
  709. X#define NEED_ALLOC_MEDIUM    /* flags alloc_medium really exists */
  710. X#endif
  711. X
  712. X
  713. X/*
  714. X * Many machines require storage alignment: longs must start on 4-byte
  715. X * boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()
  716. X * always returns pointers that are multiples of the worst-case alignment
  717. X * requirement, and we had better do so too.  This means the headers that
  718. X * we tack onto allocated structures had better have length a multiple of
  719. X * the alignment requirement.
  720. X * There isn't any really portable way to determine the worst-case alignment
  721. X * requirement.  In this code we assume that the alignment requirement is
  722. X * multiples of sizeof(align_type).  Here we define align_type as double;
  723. X * with this definition, the code will run on all machines known to me.
  724. X * If your machine has lesser alignment needs, you can save a few bytes
  725. X * by making align_type smaller.
  726. X */
  727. X
  728. Xtypedef double align_type;
  729. X
  730. X
  731. X/*
  732. X * Some important notes:
  733. X *   The allocation routines provided here must never return NULL.
  734. X *   They should exit to error_exit if unsuccessful.
  735. X *
  736. X *   It's not a good idea to try to merge the sarray and barray routines,
  737. X *   even though they are textually almost the same, because samples are
  738. X *   usually stored as bytes while coefficients are shorts.  Thus, in machines
  739. X *   where byte pointers have a different representation from word pointers,
  740. X *   the resulting machine code could not be the same.
  741. X */
  742. X
  743. X
  744. Xstatic external_methods_ptr methods; /* saved for access to error_exit */
  745. X
  746. X
  747. X#ifdef MEM_STATS        /* optional extra stuff for statistics */
  748. X
  749. X/* These macros are the assumed overhead per block for malloc().
  750. X * They don't have to be accurate, but the printed statistics will be
  751. X * off a little bit if they are not.
  752. X */
  753. X#define MALLOC_OVERHEAD  (SIZEOF(void *)) /* overhead for jget_small() */
  754. X#define MALLOC_FAR_OVERHEAD  (SIZEOF(void FAR *)) /* for jget_large() */
  755. X
  756. Xstatic long total_num_small = 0;    /* total # of small objects alloced */
  757. Xstatic long total_bytes_small = 0;    /* total bytes requested */
  758. Xstatic long cur_num_small = 0;        /* # currently alloced */
  759. Xstatic long max_num_small = 0;        /* max simultaneously alloced */
  760. X
  761. X#ifdef NEED_ALLOC_MEDIUM
  762. Xstatic long total_num_medium = 0;    /* total # of medium objects alloced */
  763. Xstatic long total_bytes_medium = 0;    /* total bytes requested */
  764. Xstatic long cur_num_medium = 0;        /* # currently alloced */
  765. Xstatic long max_num_medium = 0;        /* max simultaneously alloced */
  766. X#endif
  767. X
  768. Xstatic long total_num_sarray = 0;    /* total # of sarray objects alloced */
  769. Xstatic long total_bytes_sarray = 0;    /* total bytes requested */
  770. Xstatic long cur_num_sarray = 0;        /* # currently alloced */
  771. Xstatic long max_num_sarray = 0;        /* max simultaneously alloced */
  772. X
  773. Xstatic long total_num_barray = 0;    /* total # of barray objects alloced */
  774. Xstatic long total_bytes_barray = 0;    /* total bytes requested */
  775. Xstatic long cur_num_barray = 0;        /* # currently alloced */
  776. Xstatic long max_num_barray = 0;        /* max simultaneously alloced */
  777. X
  778. X
  779. XLOCAL void
  780. Xprint_mem_stats (void)
  781. X{
  782. X  /* since this is only a debugging stub, we can cheat a little on the
  783. X   * trace message mechanism... helpful 'cuz trace_message can't handle longs.
  784. X   */
  785. X  fprintf(stderr, "total_num_small = %ld\n", total_num_small);
  786. X  fprintf(stderr, "total_bytes_small = %ld\n", total_bytes_small);
  787. X  if (cur_num_small)
  788. X    fprintf(stderr, "cur_num_small = %ld\n", cur_num_small);
  789. X  fprintf(stderr, "max_num_small = %ld\n", max_num_small);
  790. X  
  791. X#ifdef NEED_ALLOC_MEDIUM
  792. X  fprintf(stderr, "total_num_medium = %ld\n", total_num_medium);
  793. X  fprintf(stderr, "total_bytes_medium = %ld\n", total_bytes_medium);
  794. X  if (cur_num_medium)
  795. X    fprintf(stderr, "cur_num_medium = %ld\n", cur_num_medium);
  796. X  fprintf(stderr, "max_num_medium = %ld\n", max_num_medium);
  797. X#endif
  798. X  
  799. X  fprintf(stderr, "total_num_sarray = %ld\n", total_num_sarray);
  800. X  fprintf(stderr, "total_bytes_sarray = %ld\n", total_bytes_sarray);
  801. X  if (cur_num_sarray)
  802. X    fprintf(stderr, "cur_num_sarray = %ld\n", cur_num_sarray);
  803. X  fprintf(stderr, "max_num_sarray = %ld\n", max_num_sarray);
  804. X  
  805. X  fprintf(stderr, "total_num_barray = %ld\n", total_num_barray);
  806. X  fprintf(stderr, "total_bytes_barray = %ld\n", total_bytes_barray);
  807. X  if (cur_num_barray)
  808. X    fprintf(stderr, "cur_num_barray = %ld\n", cur_num_barray);
  809. X  fprintf(stderr, "max_num_barray = %ld\n", max_num_barray);
  810. X}
  811. X
  812. X#endif /* MEM_STATS */
  813. X
  814. X
  815. XLOCAL void
  816. Xout_of_memory (int which)
  817. X/* Report an out-of-memory error and stop execution */
  818. X/* If we compiled MEM_STATS support, report alloc requests before dying */
  819. X{
  820. X#ifdef MEM_STATS
  821. X  if (methods->trace_level <= 0) /* don't do it if free_all() will */
  822. X    print_mem_stats();        /* print optional memory usage statistics */
  823. X#endif
  824. X  ERREXIT1(methods, "Insufficient memory (case %d)", which);
  825. X}
  826. X
  827. X
  828. X/*
  829. X * Management of "small" objects.
  830. X * These are all-in-memory, and are in near-heap space on an 80x86.
  831. X */
  832. X
  833. Xtypedef union small_struct * small_ptr;
  834. X
  835. Xtypedef union small_struct {
  836. X    small_ptr next;        /* next in list of allocated objects */
  837. X    align_type dummy;    /* ensures alignment of following storage */
  838. X      } small_hdr;
  839. X
  840. Xstatic small_ptr small_list;    /* head of list */
  841. X
  842. X
  843. XMETHODDEF void *
  844. Xalloc_small (size_t sizeofobject)
  845. X/* Allocate a "small" object */
  846. X{
  847. X  small_ptr result;
  848. X
  849. X  sizeofobject += SIZEOF(small_hdr); /* add space for header */
  850. X
  851. X#ifdef MEM_STATS
  852. X  total_num_small++;
  853. X  total_bytes_small += sizeofobject + MALLOC_OVERHEAD;
  854. X  cur_num_small++;
  855. X  if (cur_num_small > max_num_small) max_num_small = cur_num_small;
  856. X#endif
  857. X
  858. X  result = (small_ptr) jget_small(sizeofobject);
  859. X  if (result == NULL)
  860. X    out_of_memory(1);
  861. X
  862. X  result->next = small_list;
  863. X  small_list = result;
  864. X  result++;            /* advance past header */
  865. X
  866. X  return (void *) result;
  867. X}
  868. X
  869. X
  870. XMETHODDEF void
  871. Xfree_small (void *ptr)
  872. X/* Free a "small" object */
  873. X{
  874. X  small_ptr hdr;
  875. X  small_ptr * llink;
  876. X
  877. X  hdr = (small_ptr) ptr;
  878. X  hdr--;            /* point back to header */
  879. X
  880. X  /* Remove item from list -- linear search is fast enough */
  881. X  llink = &small_list;
  882. X  while (*llink != hdr) {
  883. X    if (*llink == NULL)
  884. X      ERREXIT(methods, "Bogus free_small request");
  885. X    llink = &( (*llink)->next );
  886. X  }
  887. X  *llink = hdr->next;
  888. X
  889. X  jfree_small((void *) hdr);
  890. X
  891. X#ifdef MEM_STATS
  892. X  cur_num_small--;
  893. X#endif
  894. X}
  895. X
  896. X
  897. X/*
  898. X * Management of "medium-size" objects.
  899. X * These are just like small objects except they are in the FAR heap.
  900. X */
  901. X
  902. X#ifdef NEED_ALLOC_MEDIUM
  903. X
  904. Xtypedef union medium_struct FAR * medium_ptr;
  905. X
  906. Xtypedef union medium_struct {
  907. X    medium_ptr next;    /* next in list of allocated objects */
  908. X    align_type dummy;    /* ensures alignment of following storage */
  909. X      } medium_hdr;
  910. X
  911. Xstatic medium_ptr medium_list;    /* head of list */
  912. X
  913. X
  914. XMETHODDEF void FAR *
  915. Xalloc_medium (size_t sizeofobject)
  916. X/* Allocate a "medium-size" object */
  917. X{
  918. X  medium_ptr result;
  919. X
  920. X  sizeofobject += SIZEOF(medium_hdr); /* add space for header */
  921. X
  922. X#ifdef MEM_STATS
  923. X  total_num_medium++;
  924. X  total_bytes_medium += sizeofobject + MALLOC_FAR_OVERHEAD;
  925. X  cur_num_medium++;
  926. X  if (cur_num_medium > max_num_medium) max_num_medium = cur_num_medium;
  927. X#endif
  928. X
  929. X  result = (medium_ptr) jget_large(sizeofobject);
  930. X  if (result == NULL)
  931. X    out_of_memory(2);
  932. X
  933. X  result->next = medium_list;
  934. X  medium_list = result;
  935. X  result++;            /* advance past header */
  936. X
  937. X  return (void FAR *) result;
  938. X}
  939. X
  940. X
  941. XMETHODDEF void
  942. Xfree_medium (void FAR *ptr)
  943. X/* Free a "medium-size" object */
  944. X{
  945. X  medium_ptr hdr;
  946. X  medium_ptr FAR * llink;
  947. X
  948. X  hdr = (medium_ptr) ptr;
  949. X  hdr--;            /* point back to header */
  950. X
  951. X  /* Remove item from list -- linear search is fast enough */
  952. X  llink = &medium_list;
  953. X  while (*llink != hdr) {
  954. X    if (*llink == NULL)
  955. X      ERREXIT(methods, "Bogus free_medium request");
  956. X    llink = &( (*llink)->next );
  957. X  }
  958. X  *llink = hdr->next;
  959. X
  960. X  jfree_large((void FAR *) hdr);
  961. X
  962. X#ifdef MEM_STATS
  963. X  cur_num_medium--;
  964. X#endif
  965. X}
  966. X
  967. X#endif /* NEED_ALLOC_MEDIUM */
  968. X
  969. X
  970. X/*
  971. X * Management of "small" (all-in-memory) 2-D sample arrays.
  972. X * The pointers are in near heap, the samples themselves in FAR heap.
  973. X * The header structure is adjacent to the row pointers.
  974. X * To minimize allocation overhead and to allow I/O of large contiguous
  975. X * blocks, we allocate the sample rows in groups of as many rows as possible
  976. X * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
  977. X * Note that the big-array control routines, later in this file, know about
  978. X * this chunking of rows ... and also how to get the rowsperchunk value!
  979. X */
  980. X
  981. Xtypedef struct small_sarray_struct * small_sarray_ptr;
  982. X
  983. Xtypedef struct small_sarray_struct {
  984. X    small_sarray_ptr next;    /* next in list of allocated sarrays */
  985. X    long numrows;        /* # of rows in this array */
  986. X    long rowsperchunk;    /* max # of rows per allocation chunk */
  987. X    JSAMPROW dummy;        /* ensures alignment of following storage */
  988. X      } small_sarray_hdr;
  989. X
  990. Xstatic small_sarray_ptr small_sarray_list; /* head of list */
  991. X
  992. X
  993. XMETHODDEF JSAMPARRAY
  994. Xalloc_small_sarray (long samplesperrow, long numrows)
  995. X/* Allocate a "small" (all-in-memory) 2-D sample array */
  996. X{
  997. X  small_sarray_ptr hdr;
  998. X  JSAMPARRAY result;
  999. X  JSAMPROW workspace;
  1000. X  long rowsperchunk, currow, i;
  1001. X
  1002. X#ifdef MEM_STATS
  1003. X  total_num_sarray++;
  1004. X  cur_num_sarray++;
  1005. X  if (cur_num_sarray > max_num_sarray) max_num_sarray = cur_num_sarray;
  1006. X#endif
  1007. X
  1008. X  /* Calculate max # of rows allowed in one allocation chunk */
  1009. X  rowsperchunk = MAX_ALLOC_CHUNK / (samplesperrow * SIZEOF(JSAMPLE));
  1010. X  if (rowsperchunk <= 0)
  1011. X      ERREXIT(methods, "Image too wide for this implementation");
  1012. X
  1013. X  /* Get space for header and row pointers; this is always "near" on 80x86 */
  1014. X  hdr = (small_sarray_ptr) alloc_small((size_t) (numrows * SIZEOF(JSAMPROW)
  1015. X                         + SIZEOF(small_sarray_hdr)));
  1016. X
  1017. X  result = (JSAMPARRAY) (hdr+1); /* advance past header */
  1018. X
  1019. X  /* Insert into list now so free_all does right thing if I fail */
  1020. X  /* after allocating only some of the rows... */
  1021. X  hdr->next = small_sarray_list;
  1022. X  hdr->numrows = 0;
  1023. X  hdr->rowsperchunk = rowsperchunk;
  1024. X  small_sarray_list = hdr;
  1025. X
  1026. X  /* Get the rows themselves; on 80x86 these are "far" */
  1027. X  currow = 0;
  1028. X  while (currow < numrows) {
  1029. X    rowsperchunk = MIN(rowsperchunk, numrows - currow);
  1030. X#ifdef MEM_STATS
  1031. X    total_bytes_sarray += rowsperchunk * samplesperrow * SIZEOF(JSAMPLE)
  1032. X              + MALLOC_FAR_OVERHEAD;
  1033. X#endif
  1034. X    workspace = (JSAMPROW) jget_large((size_t) (rowsperchunk * samplesperrow
  1035. X                        * SIZEOF(JSAMPLE)));
  1036. X    if (workspace == NULL)
  1037. X      out_of_memory(3);
  1038. X    for (i = rowsperchunk; i > 0; i--) {
  1039. X      result[currow++] = workspace;
  1040. X      workspace += samplesperrow;
  1041. X    }
  1042. X    hdr->numrows = currow;
  1043. X  }
  1044. X
  1045. X  return result;
  1046. X}
  1047. X
  1048. X
  1049. XMETHODDEF void
  1050. Xfree_small_sarray (JSAMPARRAY ptr)
  1051. X/* Free a "small" (all-in-memory) 2-D sample array */
  1052. X{
  1053. X  small_sarray_ptr hdr;
  1054. X  small_sarray_ptr * llink;
  1055. X  long i;
  1056. X
  1057. X  hdr = (small_sarray_ptr) ptr;
  1058. X  hdr--;            /* point back to header */
  1059. X
  1060. X  /* Remove item from list -- linear search is fast enough */
  1061. X  llink = &small_sarray_list;
  1062. X  while (*llink != hdr) {
  1063. X    if (*llink == NULL)
  1064. X      ERREXIT(methods, "Bogus free_small_sarray request");
  1065. X    llink = &( (*llink)->next );
  1066. X  }
  1067. X  *llink = hdr->next;
  1068. X
  1069. X  /* Free the rows themselves; on 80x86 these are "far" */
  1070. X  /* Note we only free the row-group headers! */
  1071. X  for (i = 0; i < hdr->numrows; i += hdr->rowsperchunk) {
  1072. X    jfree_large((void FAR *) ptr[i]);
  1073. X  }
  1074. X
  1075. X  /* Free header and row pointers */
  1076. X  free_small((void *) hdr);
  1077. X
  1078. X#ifdef MEM_STATS
  1079. X  cur_num_sarray--;
  1080. X#endif
  1081. X}
  1082. X
  1083. X
  1084. X/*
  1085. X * Management of "small" (all-in-memory) 2-D coefficient-block arrays.
  1086. X * This is essentially the same as the code for sample arrays, above.
  1087. X */
  1088. X
  1089. Xtypedef struct small_barray_struct * small_barray_ptr;
  1090. X
  1091. Xtypedef struct small_barray_struct {
  1092. X    small_barray_ptr next;    /* next in list of allocated barrays */
  1093. X    long numrows;        /* # of rows in this array */
  1094. X    long rowsperchunk;    /* max # of rows per allocation chunk */
  1095. X    JBLOCKROW dummy;    /* ensures alignment of following storage */
  1096. X      } small_barray_hdr;
  1097. X
  1098. Xstatic small_barray_ptr small_barray_list; /* head of list */
  1099. X
  1100. X
  1101. XMETHODDEF JBLOCKARRAY
  1102. Xalloc_small_barray (long blocksperrow, long numrows)
  1103. X/* Allocate a "small" (all-in-memory) 2-D coefficient-block array */
  1104. X{
  1105. X  small_barray_ptr hdr;
  1106. X  JBLOCKARRAY result;
  1107. X  JBLOCKROW workspace;
  1108. X  long rowsperchunk, currow, i;
  1109. X
  1110. X#ifdef MEM_STATS
  1111. X  total_num_barray++;
  1112. X  cur_num_barray++;
  1113. X  if (cur_num_barray > max_num_barray) max_num_barray = cur_num_barray;
  1114. X#endif
  1115. X
  1116. X  /* Calculate max # of rows allowed in one allocation chunk */
  1117. X  rowsperchunk = MAX_ALLOC_CHUNK / (blocksperrow * SIZEOF(JBLOCK));
  1118. X  if (rowsperchunk <= 0)
  1119. X      ERREXIT(methods, "Image too wide for this implementation");
  1120. X
  1121. X  /* Get space for header and row pointers; this is always "near" on 80x86 */
  1122. X  hdr = (small_barray_ptr) alloc_small((size_t) (numrows * SIZEOF(JBLOCKROW)
  1123. X                         + SIZEOF(small_barray_hdr)));
  1124. X
  1125. X  result = (JBLOCKARRAY) (hdr+1); /* advance past header */
  1126. X
  1127. X  /* Insert into list now so free_all does right thing if I fail */
  1128. X  /* after allocating only some of the rows... */
  1129. X  hdr->next = small_barray_list;
  1130. X  hdr->numrows = 0;
  1131. X  hdr->rowsperchunk = rowsperchunk;
  1132. X  small_barray_list = hdr;
  1133. X
  1134. X  /* Get the rows themselves; on 80x86 these are "far" */
  1135. X  currow = 0;
  1136. X  while (currow < numrows) {
  1137. X    rowsperchunk = MIN(rowsperchunk, numrows - currow);
  1138. X#ifdef MEM_STATS
  1139. X    total_bytes_barray += rowsperchunk * blocksperrow * SIZEOF(JBLOCK)
  1140. X              + MALLOC_FAR_OVERHEAD;
  1141. X#endif
  1142. X    workspace = (JBLOCKROW) jget_large((size_t) (rowsperchunk * blocksperrow
  1143. X                         * SIZEOF(JBLOCK)));
  1144. X    if (workspace == NULL)
  1145. X      out_of_memory(4);
  1146. X    for (i = rowsperchunk; i > 0; i--) {
  1147. X      result[currow++] = workspace;
  1148. X      workspace += blocksperrow;
  1149. X    }
  1150. X    hdr->numrows = currow;
  1151. X  }
  1152. X
  1153. X  return result;
  1154. X}
  1155. X
  1156. X
  1157. XMETHODDEF void
  1158. Xfree_small_barray (JBLOCKARRAY ptr)
  1159. X/* Free a "small" (all-in-memory) 2-D coefficient-block array */
  1160. X{
  1161. X  small_barray_ptr hdr;
  1162. X  small_barray_ptr * llink;
  1163. X  long i;
  1164. X
  1165. X  hdr = (small_barray_ptr) ptr;
  1166. X  hdr--;            /* point back to header */
  1167. X
  1168. X  /* Remove item from list -- linear search is fast enough */
  1169. X  llink = &small_barray_list;
  1170. X  while (*llink != hdr) {
  1171. X    if (*llink == NULL)
  1172. X      ERREXIT(methods, "Bogus free_small_barray request");
  1173. X    llink = &( (*llink)->next );
  1174. X  }
  1175. X  *llink = hdr->next;
  1176. X
  1177. X  /* Free the rows themselves; on 80x86 these are "far" */
  1178. X  /* Note we only free the row-group headers! */
  1179. X  for (i = 0; i < hdr->numrows; i += hdr->rowsperchunk) {
  1180. X    jfree_large((void FAR *) ptr[i]);
  1181. X  }
  1182. X
  1183. X  /* Free header and row pointers */
  1184. X  free_small((void *) hdr);
  1185. X
  1186. X#ifdef MEM_STATS
  1187. X  cur_num_barray--;
  1188. X#endif
  1189. X}
  1190. X
  1191. X
  1192. X
  1193. X/*
  1194. X * About "big" array management:
  1195. X *
  1196. X * To allow machines with limited memory to handle large images,
  1197. X * all processing in the JPEG system is done a few pixel or block rows
  1198. X * at a time.  The above "small" array routines are only used to allocate
  1199. X * strip buffers (as wide as the image, but just a few rows high).
  1200. X * In some cases multiple passes must be made over the data.  In these
  1201. X * cases the "big" array routines are used.  The array is still accessed
  1202. X * a strip at a time, but the memory manager must save the whole array
  1203. X * for repeated accesses.  The intended implementation is that there is
  1204. X * a strip buffer in memory (as high as is possible given the desired memory
  1205. X * limit), plus a backing file that holds the rest of the array.
  1206. X *
  1207. X * The request_big_array routines are told the total size of the image (in case
  1208. X * it is useful to know the total file size that will be needed).  They are
  1209. X * also given the unit height, which is the number of rows that will be
  1210. X * accessed at once; the in-memory buffer should be made a multiple of
  1211. X * this height for best efficiency.
  1212. X *
  1213. X * The request routines create control blocks (and may open backing files),
  1214. X * but they don't create the in-memory buffers.  This is postponed until
  1215. X * alloc_big_arrays is called.  At that time the total amount of space needed
  1216. X * is known (approximately, anyway), so free memory can be divided up fairly.
  1217. X *
  1218. X * The access_big_array routines are responsible for making a specific strip
  1219. X * area accessible (after reading or writing the backing file, if necessary).
  1220. X * Note that the access routines are told whether the caller intends to modify
  1221. X * the accessed strip; during a read-only pass this saves having to rewrite
  1222. X * data to disk.
  1223. X *
  1224. X * The typical access pattern is one top-to-bottom pass to write the data,
  1225. X * followed by one or more read-only top-to-bottom passes.  However, other
  1226. X * access patterns may occur while reading.  For example, translation of image
  1227. X * formats that use bottom-to-top scan order will require bottom-to-top read
  1228. X * passes.  The memory manager need not support multiple write passes nor
  1229. X * funny write orders (meaning that rearranging rows must be handled while
  1230. X * reading data out of the big array, not while putting it in).
  1231. X *
  1232. X * In current usage, the access requests are always for nonoverlapping strips;
  1233. X * that is, successive access start_row numbers always differ by exactly the
  1234. X * unitheight.  This allows fairly simple buffer dump/reload logic if the
  1235. X * in-memory buffer is made a multiple of the unitheight.  It would be
  1236. X * possible to keep downsampled rather than fullsize data in the "big" arrays,
  1237. X * thus reducing temp file size, if we supported overlapping strip access
  1238. X * (access requests differing by less than the unitheight).  At the moment
  1239. X * I don't believe this is worth the extra complexity.
  1240. X */
  1241. X
  1242. X
  1243. X
  1244. X/* The control blocks for virtual arrays.
  1245. X * System-dependent info for the associated backing store is hidden inside
  1246. X * the backing_store_info struct.
  1247. X */
  1248. X
  1249. Xstruct big_sarray_control {
  1250. X    long rows_in_array;    /* total virtual array height */
  1251. X    long samplesperrow;    /* width of array (and of memory buffer) */
  1252. X    long unitheight;    /* # of rows accessed by access_big_sarray() */
  1253. X    JSAMPARRAY mem_buffer;    /* the in-memory buffer */
  1254. X    long rows_in_mem;    /* height of memory buffer */
  1255. X    long rowsperchunk;    /* allocation chunk size in mem_buffer */
  1256. X    long cur_start_row;    /* first logical row # in the buffer */
  1257. X    boolean dirty;        /* do current buffer contents need written? */
  1258. X    boolean b_s_open;    /* is backing-store data valid? */
  1259. X    big_sarray_ptr next;    /* link to next big sarray control block */
  1260. X    backing_store_info b_s_info; /* System-dependent control info */
  1261. X};
  1262. X
  1263. Xstatic big_sarray_ptr big_sarray_list; /* head of list */
  1264. X
  1265. Xstruct big_barray_control {
  1266. X    long rows_in_array;    /* total virtual array height */
  1267. X    long blocksperrow;    /* width of array (and of memory buffer) */
  1268. X    long unitheight;    /* # of rows accessed by access_big_barray() */
  1269. X    JBLOCKARRAY mem_buffer;    /* the in-memory buffer */
  1270. X    long rows_in_mem;    /* height of memory buffer */
  1271. X    long rowsperchunk;    /* allocation chunk size in mem_buffer */
  1272. X    long cur_start_row;    /* first logical row # in the buffer */
  1273. X    boolean dirty;        /* do current buffer contents need written? */
  1274. X    boolean b_s_open;    /* is backing-store data valid? */
  1275. X    big_barray_ptr next;    /* link to next big barray control block */
  1276. X    backing_store_info b_s_info; /* System-dependent control info */
  1277. X};
  1278. X
  1279. Xstatic big_barray_ptr big_barray_list; /* head of list */
  1280. X
  1281. X
  1282. XMETHODDEF big_sarray_ptr
  1283. Xrequest_big_sarray (long samplesperrow, long numrows, long unitheight)
  1284. X/* Request a "big" (virtual-memory) 2-D sample array */
  1285. X{
  1286. X  big_sarray_ptr result;
  1287. X
  1288. X  /* get control block */
  1289. X  result = (big_sarray_ptr) alloc_small(SIZEOF(struct big_sarray_control));
  1290. X
  1291. X  result->rows_in_array = numrows;
  1292. X  result->samplesperrow = samplesperrow;
  1293. X  result->unitheight = unitheight;
  1294. X  result->mem_buffer = NULL;    /* marks array not yet realized */
  1295. X  result->b_s_open = FALSE;    /* no associated backing-store object */
  1296. X  result->next = big_sarray_list; /* add to list of big arrays */
  1297. X  big_sarray_list = result;
  1298. X
  1299. X  return result;
  1300. X}
  1301. X
  1302. X
  1303. XMETHODDEF big_barray_ptr
  1304. Xrequest_big_barray (long blocksperrow, long numrows, long unitheight)
  1305. X/* Request a "big" (virtual-memory) 2-D coefficient-block array */
  1306. X{
  1307. X  big_barray_ptr result;
  1308. X
  1309. X  /* get control block */
  1310. X  result = (big_barray_ptr) alloc_small(SIZEOF(struct big_barray_control));
  1311. X
  1312. X  result->rows_in_array = numrows;
  1313. X  result->blocksperrow = blocksperrow;
  1314. X  result->unitheight = unitheight;
  1315. X  result->mem_buffer = NULL;    /* marks array not yet realized */
  1316. X  result->b_s_open = FALSE;    /* no associated backing-store object */
  1317. X  result->next = big_barray_list; /* add to list of big arrays */
  1318. X  big_barray_list = result;
  1319. X
  1320. X  return result;
  1321. X}
  1322. X
  1323. X
  1324. XMETHODDEF void
  1325. Xalloc_big_arrays (long extra_small_samples, long extra_small_blocks,
  1326. X          long extra_medium_space)
  1327. X/* Allocate the in-memory buffers for any unrealized "big" arrays */
  1328. X/* 'extra' values are upper bounds for total future small-array requests */
  1329. X/* and far-heap requests */
  1330. X{
  1331. X  long total_extra_space = extra_small_samples * SIZEOF(JSAMPLE)
  1332. X               + extra_small_blocks * SIZEOF(JBLOCK)
  1333. X               + extra_medium_space;
  1334. X  long space_per_unitheight, maximum_space, avail_mem;
  1335. X  long unitheights, max_unitheights;
  1336. X  big_sarray_ptr sptr;
  1337. X  big_barray_ptr bptr;
  1338. X
  1339. X  /* Compute the minimum space needed (unitheight rows in each buffer)
  1340. X   * and the maximum space needed (full image height in each buffer).
  1341. X   * These may be of use to the system-dependent jmem_available routine.
  1342. X   */
  1343. X  space_per_unitheight = 0;
  1344. X  maximum_space = total_extra_space;
  1345. X  for (sptr = big_sarray_list; sptr != NULL; sptr = sptr->next) {
  1346. X    if (sptr->mem_buffer == NULL) { /* if not realized yet */
  1347. X      space_per_unitheight += sptr->unitheight *
  1348. X                  sptr->samplesperrow * SIZEOF(JSAMPLE);
  1349. X      maximum_space += sptr->rows_in_array *
  1350. X               sptr->samplesperrow * SIZEOF(JSAMPLE);
  1351. X    }
  1352. X  }
  1353. X  for (bptr = big_barray_list; bptr != NULL; bptr = bptr->next) {
  1354. X    if (bptr->mem_buffer == NULL) { /* if not realized yet */
  1355. X      space_per_unitheight += bptr->unitheight *
  1356. X                  bptr->blocksperrow * SIZEOF(JBLOCK);
  1357. X      maximum_space += bptr->rows_in_array *
  1358. X               bptr->blocksperrow * SIZEOF(JBLOCK);
  1359. X    }
  1360. X  }
  1361. X
  1362. X  if (space_per_unitheight <= 0)
  1363. X    return;            /* no unrealized arrays, no work */
  1364. X
  1365. X  /* Determine amount of memory to actually use; this is system-dependent. */
  1366. X  avail_mem = jmem_available(space_per_unitheight + total_extra_space,
  1367. X                 maximum_space);
  1368. X
  1369. X  /* If the maximum space needed is available, make all the buffers full
  1370. X   * height; otherwise parcel it out with the same number of unitheights
  1371. X   * in each buffer.
  1372. X   */
  1373. X  if (avail_mem >= maximum_space)
  1374. X    max_unitheights = 1000000000L;
  1375. X  else {
  1376. X    max_unitheights = (avail_mem - total_extra_space) / space_per_unitheight;
  1377. X    /* If there doesn't seem to be enough space, try to get the minimum
  1378. X     * anyway.  This allows a "stub" implementation of jmem_available().
  1379. X     */
  1380. X    if (max_unitheights <= 0)
  1381. X      max_unitheights = 1;
  1382. X  }
  1383. X
  1384. X  /* Allocate the in-memory buffers and initialize backing store as needed. */
  1385. X
  1386. X  for (sptr = big_sarray_list; sptr != NULL; sptr = sptr->next) {
  1387. X    if (sptr->mem_buffer == NULL) { /* if not realized yet */
  1388. X      unitheights = (sptr->rows_in_array + sptr->unitheight - 1L)
  1389. X            / sptr->unitheight;
  1390. X      if (unitheights <= max_unitheights) {
  1391. X    /* This buffer fits in memory */
  1392. X    sptr->rows_in_mem = sptr->rows_in_array;
  1393. X      } else {
  1394. X    /* It doesn't fit in memory, create backing store. */
  1395. X    sptr->rows_in_mem = max_unitheights * sptr->unitheight;
  1396. X    jopen_backing_store(& sptr->b_s_info,
  1397. X                (long) (sptr->rows_in_array *
  1398. X                    sptr->samplesperrow * SIZEOF(JSAMPLE)));
  1399. X    sptr->b_s_open = TRUE;
  1400. X      }
  1401. X      sptr->mem_buffer = alloc_small_sarray(sptr->samplesperrow,
  1402. X                        sptr->rows_in_mem);
  1403. X      /* Reach into the small_sarray header and get the rowsperchunk field.
  1404. X       * Yes, I know, this is horrible coding practice.
  1405. X       */
  1406. X      sptr->rowsperchunk =
  1407. X    ((small_sarray_ptr) sptr->mem_buffer)[-1].rowsperchunk;
  1408. X      sptr->cur_start_row = 0;
  1409. X      sptr->dirty = FALSE;
  1410. X    }
  1411. X  }
  1412. X
  1413. X  for (bptr = big_barray_list; bptr != NULL; bptr = bptr->next) {
  1414. X    if (bptr->mem_buffer == NULL) { /* if not realized yet */
  1415. X      unitheights = (bptr->rows_in_array + bptr->unitheight - 1L)
  1416. X            / bptr->unitheight;
  1417. X      if (unitheights <= max_unitheights) {
  1418. X    /* This buffer fits in memory */
  1419. X    bptr->rows_in_mem = bptr->rows_in_array;
  1420. X      } else {
  1421. X    /* It doesn't fit in memory, create backing store. */
  1422. X    bptr->rows_in_mem = max_unitheights * bptr->unitheight;
  1423. X    jopen_backing_store(& bptr->b_s_info,
  1424. X                (long) (bptr->rows_in_array *
  1425. X                    bptr->blocksperrow * SIZEOF(JBLOCK)));
  1426. X    bptr->b_s_open = TRUE;
  1427. X      }
  1428. X      bptr->mem_buffer = alloc_small_barray(bptr->blocksperrow,
  1429. X                        bptr->rows_in_mem);
  1430. X      /* Reach into the small_barray header and get the rowsperchunk field. */
  1431. X      bptr->rowsperchunk =
  1432. X    ((small_barray_ptr) bptr->mem_buffer)[-1].rowsperchunk;
  1433. X      bptr->cur_start_row = 0;
  1434. X      bptr->dirty = FALSE;
  1435. X    }
  1436. X  }
  1437. X}
  1438. X
  1439. X
  1440. XLOCAL void
  1441. Xdo_sarray_io (big_sarray_ptr ptr, boolean writing)
  1442. X/* Do backing store read or write of a "big" sample array */
  1443. X{
  1444. X  long bytesperrow, file_offset, byte_count, rows, i;
  1445. X
  1446. X  bytesperrow = ptr->samplesperrow * SIZEOF(JSAMPLE);
  1447. X  file_offset = ptr->cur_start_row * bytesperrow;
  1448. X  /* Loop to read or write each allocation chunk in mem_buffer */
  1449. X  for (i = 0; i < ptr->rows_in_mem; i += ptr->rowsperchunk) {
  1450. X    /* One chunk, but check for short chunk at end of buffer */
  1451. X    rows = MIN(ptr->rowsperchunk, ptr->rows_in_mem - i);
  1452. X    /* Transfer no more than fits in file */
  1453. X    rows = MIN(rows, ptr->rows_in_array - (ptr->cur_start_row + i));
  1454. X    if (rows <= 0)        /* this chunk might be past end of file! */
  1455. X      break;
  1456. X    byte_count = rows * bytesperrow;
  1457. X    if (writing)
  1458. X      (*ptr->b_s_info.write_backing_store) (& ptr->b_s_info,
  1459. X                        (void FAR *) ptr->mem_buffer[i],
  1460. X                        file_offset, byte_count);
  1461. X    else
  1462. X      (*ptr->b_s_info.read_backing_store) (& ptr->b_s_info,
  1463. X                       (void FAR *) ptr->mem_buffer[i],
  1464. X                       file_offset, byte_count);
  1465. X    file_offset += byte_count;
  1466. X  }
  1467. X}
  1468. X
  1469. X
  1470. XLOCAL void
  1471. Xdo_barray_io (big_barray_ptr ptr, boolean writing)
  1472. X/* Do backing store read or write of a "big" coefficient-block array */
  1473. X{
  1474. X  long bytesperrow, file_offset, byte_count, rows, i;
  1475. X
  1476. X  bytesperrow = ptr->blocksperrow * SIZEOF(JBLOCK);
  1477. X  file_offset = ptr->cur_start_row * bytesperrow;
  1478. X  /* Loop to read or write each allocation chunk in mem_buffer */
  1479. X  for (i = 0; i < ptr->rows_in_mem; i += ptr->rowsperchunk) {
  1480. X    /* One chunk, but check for short chunk at end of buffer */
  1481. X    rows = MIN(ptr->rowsperchunk, ptr->rows_in_mem - i);
  1482. X    /* Transfer no more than fits in file */
  1483. X    rows = MIN(rows, ptr->rows_in_array - (ptr->cur_start_row + i));
  1484. X    if (rows <= 0)        /* this chunk might be past end of file! */
  1485. X      break;
  1486. X    byte_count = rows * bytesperrow;
  1487. X    if (writing)
  1488. X      (*ptr->b_s_info.write_backing_store) (& ptr->b_s_info,
  1489. X                        (void FAR *) ptr->mem_buffer[i],
  1490. X                        file_offset, byte_count);
  1491. X    else
  1492. X      (*ptr->b_s_info.read_backing_store) (& ptr->b_s_info,
  1493. X                       (void FAR *) ptr->mem_buffer[i],
  1494. X                       file_offset, byte_count);
  1495. X    file_offset += byte_count;
  1496. X  }
  1497. X}
  1498. X
  1499. X
  1500. XMETHODDEF JSAMPARRAY
  1501. Xaccess_big_sarray (big_sarray_ptr ptr, long start_row, boolean writable)
  1502. X/* Access the part of a "big" sample array starting at start_row */
  1503. X/* and extending for ptr->unitheight rows.  writable is true if  */
  1504. X/* caller intends to modify the accessed area. */
  1505. X{
  1506. X  /* debugging check */
  1507. X  if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_array ||
  1508. X      ptr->mem_buffer == NULL)
  1509. X    ERREXIT(methods, "Bogus access_big_sarray request");
  1510. X
  1511. X  /* Make the desired part of the virtual array accessible */
  1512. X  if (start_row < ptr->cur_start_row ||
  1513. X      start_row+ptr->unitheight > ptr->cur_start_row+ptr->rows_in_mem) {
  1514. X    if (! ptr->b_s_open)
  1515. X      ERREXIT(methods, "Virtual array controller messed up");
  1516. X    /* Flush old buffer contents if necessary */
  1517. X    if (ptr->dirty) {
  1518. X      do_sarray_io(ptr, TRUE);
  1519. X      ptr->dirty = FALSE;
  1520. X    }
  1521. X    /* Decide what part of virtual array to access.
  1522. X     * Algorithm: if target address > current window, assume forward scan,
  1523. X     * load starting at target address.  If target address < current window,
  1524. X     * assume backward scan, load so that target address is top of window.
  1525. X     * Note that when switching from forward write to forward read, will have
  1526. X     * start_row = 0, so the limiting case applies and we load from 0 anyway.
  1527. X     */
  1528. X    if (start_row > ptr->cur_start_row) {
  1529. X      ptr->cur_start_row = start_row;
  1530. X    } else {
  1531. X      ptr->cur_start_row = start_row + ptr->unitheight - ptr->rows_in_mem;
  1532. X      if (ptr->cur_start_row < 0)
  1533. X    ptr->cur_start_row = 0;    /* don't fall off front end of file */
  1534. X    }
  1535. X    /* If reading, read in the selected part of the array. 
  1536. X     * If we are writing, we need not pre-read the selected portion,
  1537. X     * since the access sequence constraints ensure it would be garbage.
  1538. X     */
  1539. X    if (! writable) {
  1540. X      do_sarray_io(ptr, FALSE);
  1541. X    }
  1542. X  }
  1543. X  /* Flag the buffer dirty if caller will write in it */
  1544. X  if (writable)
  1545. X    ptr->dirty = TRUE;
  1546. X  /* Return address of proper part of the buffer */
  1547. X  return ptr->mem_buffer + (start_row - ptr->cur_start_row);
  1548. X}
  1549. X
  1550. X
  1551. XMETHODDEF JBLOCKARRAY
  1552. Xaccess_big_barray (big_barray_ptr ptr, long start_row, boolean writable)
  1553. X/* Access the part of a "big" coefficient-block array starting at start_row */
  1554. X/* and extending for ptr->unitheight rows.  writable is true if  */
  1555. X/* caller intends to modify the accessed area. */
  1556. X{
  1557. X  /* debugging check */
  1558. X  if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_array ||
  1559. X      ptr->mem_buffer == NULL)
  1560. X    ERREXIT(methods, "Bogus access_big_barray request");
  1561. X
  1562. X  /* Make the desired part of the virtual array accessible */
  1563. X  if (start_row < ptr->cur_start_row ||
  1564. X      start_row+ptr->unitheight > ptr->cur_start_row+ptr->rows_in_mem) {
  1565. X    if (! ptr->b_s_open)
  1566. X      ERREXIT(methods, "Virtual array controller messed up");
  1567. X    /* Flush old buffer contents if necessary */
  1568. X    if (ptr->dirty) {
  1569. X      do_barray_io(ptr, TRUE);
  1570. X      ptr->dirty = FALSE;
  1571. X    }
  1572. X    /* Decide what part of virtual array to access.
  1573. X     * Algorithm: if target address > current window, assume forward scan,
  1574. X     * load starting at target address.  If target address < current window,
  1575. X     * assume backward scan, load so that target address is top of window.
  1576. X     * Note that when switching from forward write to forward read, will have
  1577. X     * start_row = 0, so the limiting case applies and we load from 0 anyway.
  1578. X     */
  1579. X    if (start_row > ptr->cur_start_row) {
  1580. X      ptr->cur_start_row = start_row;
  1581. X    } else {
  1582. X      ptr->cur_start_row = start_row + ptr->unitheight - ptr->rows_in_mem;
  1583. X      if (ptr->cur_start_row < 0)
  1584. X    ptr->cur_start_row = 0;    /* don't fall off front end of file */
  1585. X    }
  1586. X    /* If reading, read in the selected part of the array. 
  1587. X     * If we are writing, we need not pre-read the selected portion,
  1588. X     * since the access sequence constraints ensure it would be garbage.
  1589. X     */
  1590. X    if (! writable) {
  1591. X      do_barray_io(ptr, FALSE);
  1592. X    }
  1593. X  }
  1594. X  /* Flag the buffer dirty if caller will write in it */
  1595. X  if (writable)
  1596. X    ptr->dirty = TRUE;
  1597. X  /* Return address of proper part of the buffer */
  1598. X  return ptr->mem_buffer + (start_row - ptr->cur_start_row);
  1599. X}
  1600. X
  1601. X
  1602. XMETHODDEF void
  1603. Xfree_big_sarray (big_sarray_ptr ptr)
  1604. X/* Free a "big" (virtual-memory) 2-D sample array */
  1605. X{
  1606. X  big_sarray_ptr * llink;
  1607. X
  1608. X  /* Remove item from list -- linear search is fast enough */
  1609. X  llink = &big_sarray_list;
  1610. X  while (*llink != ptr) {
  1611. X    if (*llink == NULL)
  1612. X      ERREXIT(methods, "Bogus free_big_sarray request");
  1613. X    llink = &( (*llink)->next );
  1614. X  }
  1615. X  *llink = ptr->next;
  1616. X
  1617. X  if (ptr->b_s_open)        /* there may be no backing store */
  1618. X    (*ptr->b_s_info.close_backing_store) (& ptr->b_s_info);
  1619. X
  1620. X  if (ptr->mem_buffer != NULL)    /* just in case never realized */
  1621. X    free_small_sarray(ptr->mem_buffer);
  1622. X
  1623. X  free_small((void *) ptr);    /* free the control block too */
  1624. X}
  1625. X
  1626. X
  1627. XMETHODDEF void
  1628. Xfree_big_barray (big_barray_ptr ptr)
  1629. X/* Free a "big" (virtual-memory) 2-D coefficient-block array */
  1630. X{
  1631. X  big_barray_ptr * llink;
  1632. X
  1633. X  /* Remove item from list -- linear search is fast enough */
  1634. X  llink = &big_barray_list;
  1635. X  while (*llink != ptr) {
  1636. X    if (*llink == NULL)
  1637. X      ERREXIT(methods, "Bogus free_big_barray request");
  1638. X    llink = &( (*llink)->next );
  1639. X  }
  1640. X  *llink = ptr->next;
  1641. X
  1642. X  if (ptr->b_s_open)        /* there may be no backing store */
  1643. X    (*ptr->b_s_info.close_backing_store) (& ptr->b_s_info);
  1644. X
  1645. X  if (ptr->mem_buffer != NULL)    /* just in case never realized */
  1646. X    free_small_barray(ptr->mem_buffer);
  1647. X
  1648. X  free_small((void *) ptr);    /* free the control block too */
  1649. X}
  1650. X
  1651. X
  1652. X/*
  1653. X * Cleanup: free anything that's been allocated since jselmemmgr().
  1654. X */
  1655. X
  1656. XMETHODDEF void
  1657. Xfree_all (void)
  1658. X{
  1659. X  /* First free any open "big" arrays -- these may release small arrays */
  1660. X  while (big_sarray_list != NULL)
  1661. X    free_big_sarray(big_sarray_list);
  1662. X  while (big_barray_list != NULL)
  1663. X    free_big_barray(big_barray_list);
  1664. X  /* Free any open small arrays -- these may release small objects */
  1665. X  /* +1's are because we must pass a pointer to the data, not the header */
  1666. X  while (small_sarray_list != NULL)
  1667. X    free_small_sarray((JSAMPARRAY) (small_sarray_list + 1));
  1668. X  while (small_barray_list != NULL)
  1669. X    free_small_barray((JBLOCKARRAY) (small_barray_list + 1));
  1670. X  /* Free any remaining small objects */
  1671. X  while (small_list != NULL)
  1672. X    free_small((void *) (small_list + 1));
  1673. X#ifdef NEED_ALLOC_MEDIUM
  1674. X  while (medium_list != NULL)
  1675. X    free_medium((void FAR *) (medium_list + 1));
  1676. X#endif
  1677. X
  1678. X  jmem_term();            /* system-dependent cleanup */
  1679. X
  1680. X#ifdef MEM_STATS
  1681. X  if (methods->trace_level > 0)
  1682. X    print_mem_stats();        /* print optional memory usage statistics */
  1683. X#endif
  1684. X}
  1685. X
  1686. X
  1687. X/*
  1688. X * The method selection routine for virtual memory systems.
  1689. X * The system-dependent setup routine should call this routine
  1690. X * to install the necessary method pointers in the supplied struct.
  1691. X */
  1692. X
  1693. XGLOBAL void
  1694. Xjselmemmgr (external_methods_ptr emethods)
  1695. X{
  1696. X  methods = emethods;        /* save struct addr for error exit access */
  1697. X
  1698. X  emethods->alloc_small = alloc_small;
  1699. X  emethods->free_small = free_small;
  1700. X#ifdef NEED_ALLOC_MEDIUM
  1701. X  emethods->alloc_medium = alloc_medium;
  1702. X  emethods->free_medium = free_medium;
  1703. X#else
  1704. X  emethods->alloc_medium = alloc_small;
  1705. X  emethods->free_medium = free_small;
  1706. X#endif
  1707. X  emethods->alloc_small_sarray = alloc_small_sarray;
  1708. X  emethods->free_small_sarray = free_small_sarray;
  1709. X  emethods->alloc_small_barray = alloc_small_barray;
  1710. X  emethods->free_small_barray = free_small_barray;
  1711. X  emethods->request_big_sarray = request_big_sarray;
  1712. X  emethods->request_big_barray = request_big_barray;
  1713. X  emethods->alloc_big_arrays = alloc_big_arrays;
  1714. X  emethods->access_big_sarray = access_big_sarray;
  1715. X  emethods->access_big_barray = access_big_barray;
  1716. X  emethods->free_big_sarray = free_big_sarray;
  1717. X  emethods->free_big_barray = free_big_barray;
  1718. X  emethods->free_all = free_all;
  1719. X
  1720. X  /* Initialize list headers to empty */
  1721. X  small_list = NULL;
  1722. X#ifdef NEED_ALLOC_MEDIUM
  1723. X  medium_list = NULL;
  1724. X#endif
  1725. X  small_sarray_list = NULL;
  1726. X  small_barray_list = NULL;
  1727. X  big_sarray_list = NULL;
  1728. X  big_barray_list = NULL;
  1729. X
  1730. X  jmem_init(emethods);        /* system-dependent initialization */
  1731. X
  1732. X  /* Check for an environment variable JPEGMEM; if found, override the
  1733. X   * default max_memory setting from jmem_init.  Note that a command line
  1734. X   * -m argument may again override this value.
  1735. X   * If your system doesn't support getenv(), define NO_GETENV to disable
  1736. X   * this feature.
  1737. X   */
  1738. X#ifndef NO_GETENV
  1739. X  { char * memenv;
  1740. X
  1741. X    if ((memenv = getenv("JPEGMEM")) != NULL) {
  1742. X      long lval;
  1743. X      char ch = 'x';
  1744. X
  1745. X      if (sscanf(memenv, "%ld%c", &lval, &ch) > 0) {
  1746. X    if (ch == 'm' || ch == 'M')
  1747. X      lval *= 1000L;
  1748. X    emethods->max_memory_to_use = lval * 1000L;
  1749. X      }
  1750. X    }
  1751. X  }
  1752. X#endif
  1753. X
  1754. X}
  1755. END_OF_FILE
  1756.   if test 37719 -ne `wc -c <'jmemmgr.c'`; then
  1757.     echo shar: \"'jmemmgr.c'\" unpacked with wrong size!
  1758.   fi
  1759.   # end of 'jmemmgr.c'
  1760. fi
  1761. echo shar: End of archive 6 \(of 18\).
  1762. cp /dev/null ark6isdone
  1763. MISSING=""
  1764. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
  1765.     if test ! -f ark${I}isdone ; then
  1766.     MISSING="${MISSING} ${I}"
  1767.     fi
  1768. done
  1769. if test "${MISSING}" = "" ; then
  1770.     echo You have unpacked all 18 archives.
  1771.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1772. else
  1773.     echo You still must unpack the following archives:
  1774.     echo "        " ${MISSING}
  1775. fi
  1776. exit 0
  1777. exit 0 # Just in case...
  1778.