Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * jmemdos.c
  3.  *
  4.  * Copyright (C) 1992-1997, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file provides an MS-DOS-compatible implementation of the system-
  9.  * dependent portion of the JPEG memory manager.  Temporary data can be
  10.  * stored in extended or expanded memory as well as in regular DOS files.
  11.  *
  12.  * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
  13.  * if you compile in a small-data memory model; it should NOT be defined if
  14.  * you use a large-data memory model.  This file is not recommended if you
  15.  * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
  16.  * Also, this code will NOT work if struct fields are aligned on greater than
  17.  * 2-byte boundaries.
  18.  *
  19.  * Based on code contributed by Ge' Weijers.
  20.  */
  21.  
  22. /*
  23.  * If you have both extended and expanded memory, you may want to change the
  24.  * order in which they are tried in jopen_backing_store.  On a 286 machine
  25.  * expanded memory is usually faster, since extended memory access involves
  26.  * an expensive protected-mode-and-back switch.  On 386 and better, extended
  27.  * memory is usually faster.  As distributed, the code tries extended memory
  28.  * first (what? not everyone has a 386? :-).
  29.  *
  30.  * You can disable use of extended/expanded memory entirely by altering these
  31.  * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
  32.  */
  33.  
  34. #ifndef XMS_SUPPORTED
  35. #define XMS_SUPPORTED  1
  36. #endif
  37. #ifndef EMS_SUPPORTED
  38. #define EMS_SUPPORTED  1
  39. #endif
  40.  
  41.  
  42. #define JPEG_INTERNALS
  43. #include "jinclude.h"
  44. #include "jpeglib.h"
  45. #include "jmemsys.h"            /* import the system-dependent declarations */
  46.  
  47. #ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare these */
  48. extern void * malloc JPP((size_t size));
  49. extern void free JPP((void *ptr));
  50. extern char * getenv JPP((const char * name));
  51. #endif
  52.  
  53. #ifdef NEED_FAR_POINTERS
  54.  
  55. #ifdef __TURBOC__
  56. /* These definitions work for Borland C (Turbo C) */
  57. #include <alloc.h>              /* need farmalloc(), farfree() */
  58. #define far_malloc(x)   farmalloc(x)
  59. #define far_free(x)     farfree(x)
  60. #else
  61. /* These definitions work for Microsoft C and compatible compilers */
  62. #include <malloc.h>             /* need _fmalloc(), _ffree() */
  63. #define far_malloc(x)   _fmalloc(x)
  64. #define far_free(x)     _ffree(x)
  65. #endif
  66.  
  67. #else /* not NEED_FAR_POINTERS */
  68.  
  69. #define far_malloc(x)   malloc(x)
  70. #define far_free(x)     free(x)
  71.  
  72. #endif /* NEED_FAR_POINTERS */
  73.  
  74. #ifdef DONT_USE_B_MODE          /* define mode parameters for fopen() */
  75. #define READ_BINARY     "r"
  76. #else
  77. #define READ_BINARY     "rb"
  78. #endif
  79.  
  80. #ifndef USE_MSDOS_MEMMGR        /* make sure user got configuration right */
  81.   You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */
  82. #endif
  83.  
  84. #if MAX_ALLOC_CHUNK >= 65535L   /* make sure jconfig.h got this right */
  85.   MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
  86. #endif
  87.  
  88.  
  89. /*
  90.  * Declarations for assembly-language support routines (see jmemdosa.asm).
  91.  *
  92.  * The functions are declared "far" as are all their pointer arguments;
  93.  * this ensures the assembly source code will work regardless of the
  94.  * compiler memory model.  We assume "short" is 16 bits, "long" is 32.
  95.  */
  96.  
  97. typedef void far * XMSDRIVER;   /* actually a pointer to code */
  98. typedef struct {                /* registers for calling XMS driver */
  99.         unsigned short ax, dx, bx;
  100.         void far * ds_si;
  101.       } XMScontext;
  102. typedef struct {                /* registers for calling EMS driver */
  103.         unsigned short ax, dx, bx;
  104.         void far * ds_si;
  105.       } EMScontext;
  106.  
  107. extern short far jdos_open JPP((short far * handle, char far * filename));
  108. extern short far jdos_close JPP((short handle));
  109. extern short far jdos_seek JPP((short handle, long offset));
  110. extern short far jdos_read JPP((short handle, void far * buffer,
  111.                                 unsigned short count));
  112. extern short far jdos_write JPP((short handle, void far * buffer,
  113.                                  unsigned short count));
  114. extern void far jxms_getdriver JPP((XMSDRIVER far *));
  115. extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
  116. extern short far jems_available JPP((void));
  117. extern void far jems_calldriver JPP((EMScontext far *));
  118.  
  119.  
  120. /*
  121.  * Selection of a file name for a temporary file.
  122.  * This is highly system-dependent, and you may want to customize it.
  123.  */
  124.  
  125. static int next_file_num;       /* to distinguish among several temp files */
  126.  
  127. LOCAL(void)
  128. select_file_name (char * fname)
  129. {
  130.   const char * env;
  131.   char * ptr;
  132.   FILE * tfile;
  133.  
  134.   /* Keep generating file names till we find one that's not in use */
  135.   for (;;) {
  136.     /* Get temp directory name from environment TMP or TEMP variable;
  137.      * if none, use "."
  138.      */
  139.     if ((env = (const char *) getenv("TMP")) == NULL)
  140.       if ((env = (const char *) getenv("TEMP")) == NULL)
  141.         env = ".";
  142.     if (*env == '\0')           /* null string means "." */
  143.       env = ".";
  144.     ptr = fname;                /* copy name to fname */
  145.     while (*env != '\0')
  146.       *ptr++ = *env++;
  147.     if (ptr[-1] != '\\' && ptr[-1] != '/')
  148.       *ptr++ = '\\';            /* append backslash if not in env variable */
  149.     /* Append a suitable file name */
  150.     next_file_num++;            /* advance counter */
  151.     sprintf(ptr, "JPG%03d.TMP", next_file_num);
  152.     /* Probe to see if file name is already in use */
  153.     if ((tfile = fopen(fname, READ_BINARY)) == NULL)
  154.       break;
  155.     fclose(tfile);              /* oops, it's there; close tfile & try again */
  156.   }
  157. }
  158.  
  159.  
  160. /*
  161.  * Near-memory allocation and freeing are controlled by the regular library
  162.  * routines malloc() and free().
  163.  */
  164.  
  165. GLOBAL(void *)
  166. jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
  167. {
  168.   return (void *) malloc(sizeofobject);
  169. }
  170.  
  171. GLOBAL(void)
  172. jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
  173. {
  174.   free(object);
  175. }
  176.  
  177.  
  178. /*
  179.  * "Large" objects are allocated in far memory, if possible
  180.  */
  181.  
  182. GLOBAL(void FAR *)
  183. jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
  184. {
  185.   return (void FAR *) far_malloc(sizeofobject);
  186. }
  187.  
  188. GLOBAL(void)
  189. jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
  190. {
  191.   far_free(object);
  192. }
  193.  
  194.  
  195. /*
  196.  * This routine computes the total memory space available for allocation.
  197.  * It's impossible to do this in a portable way; our current solution is
  198.  * to make the user tell us (with a default value set at compile time).
  199.  * If you can actually get the available space, it's a good idea to subtract
  200.  * a slop factor of 5% or so.
  201.  */
  202.  
  203. #ifndef DEFAULT_MAX_MEM         /* so can override from makefile */
  204. #define DEFAULT_MAX_MEM         300000L /* for total usage about 450K */
  205. #endif
  206.  
  207. GLOBAL(long)
  208. jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
  209.                     long max_bytes_needed, long already_allocated)
  210. {
  211.   return cinfo->mem->max_memory_to_use - already_allocated;
  212. }
  213.  
  214.  
  215. /*
  216.  * Backing store (temporary file) management.
  217.  * Backing store objects are only used when the value returned by
  218.  * jpeg_mem_available is less than the total space needed.  You can dispense
  219.  * with these routines if you have plenty of virtual memory; see jmemnobs.c.
  220.  */
  221.  
  222. /*
  223.  * For MS-DOS we support three types of backing storage:
  224.  *   1. Conventional DOS files.  We access these by direct DOS calls rather
  225.  *      than via the stdio package.  This provides a bit better performance,
  226.  *      but the real reason is that the buffers to be read or written are FAR.
  227.  *      The stdio library for small-data memory models can't cope with that.
  228.  *   2. Extended memory, accessed per the XMS V2.0 specification.
  229.  *   3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
  230.  * You'll need copies of those specs to make sense of the related code.
  231.  * The specs are available by Internet FTP from the SIMTEL archives
  232.  * (oak.oakland.edu and its various mirror sites).  See files
  233.  * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
  234.  */
  235.  
  236.  
  237. /*
  238.  * Access methods for a DOS file.
  239.  */
  240.  
  241.  
  242. METHODDEF(void)
  243. read_file_store (j_common_ptr cinfo, backing_store_ptr info,
  244.                  void FAR * buffer_address,
  245.                  long file_offset, long byte_count)
  246. {
  247.   if (jdos_seek(info->handle.file_handle, file_offset))
  248.     ERREXIT(cinfo, JERR_TFILE_SEEK);
  249.   /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  250.   if (byte_count > 65535L)      /* safety check */
  251.     ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
  252.   if (jdos_read(info->handle.file_handle, buffer_address,
  253.                 (unsigned short) byte_count))
  254.     ERREXIT(cinfo, JERR_TFILE_READ);
  255. }
  256.  
  257.  
  258. METHODDEF(void)
  259. write_file_store (j_common_ptr cinfo, backing_store_ptr info,
  260.                   void FAR * buffer_address,
  261.                   long file_offset, long byte_count)
  262. {
  263.   if (jdos_seek(info->handle.file_handle, file_offset))
  264.     ERREXIT(cinfo, JERR_TFILE_SEEK);
  265.   /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  266.   if (byte_count > 65535L)      /* safety check */
  267.     ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
  268.   if (jdos_write(info->handle.file_handle, buffer_address,
  269.                  (unsigned short) byte_count))
  270.     ERREXIT(cinfo, JERR_TFILE_WRITE);
  271. }
  272.  
  273.  
  274. METHODDEF(void)
  275. close_file_store (j_common_ptr cinfo, backing_store_ptr info)
  276. {
  277.   jdos_close(info->handle.file_handle); /* close the file */
  278.   remove(info->temp_name);      /* delete the file */
  279. /* If your system doesn't have remove(), try unlink() instead.
  280.  * remove() is the ANSI-standard name for this function, but
  281.  * unlink() was more common in pre-ANSI systems.
  282.  */
  283.   TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
  284. }
  285.  
  286.  
  287. LOCAL(boolean)
  288. open_file_store (j_common_ptr cinfo, backing_store_ptr info,
  289.                  long total_bytes_needed)
  290. {
  291.   short handle;
  292.  
  293.   select_file_name(info->temp_name);
  294.   if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
  295.     /* might as well exit since jpeg_open_backing_store will fail anyway */
  296.     ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
  297.     return FALSE;
  298.   }
  299.   info->handle.file_handle = handle;
  300.   info->read_backing_store = read_file_store;
  301.   info->write_backing_store = write_file_store;
  302.   info->close_backing_store = close_file_store;
  303.   TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
  304.   return TRUE;                  /* succeeded */
  305. }
  306.  
  307.  
  308. /*
  309.  * Access methods for extended memory.
  310.  */
  311.  
  312. #if XMS_SUPPORTED
  313.  
  314. static XMSDRIVER xms_driver;    /* saved address of XMS driver */
  315.  
  316. typedef union {                 /* either long offset or real-mode pointer */
  317.         long offset;
  318.         void far * ptr;
  319.       } XMSPTR;
  320.  
  321. typedef struct {                /* XMS move specification structure */
  322.         long length;
  323.         XMSH src_handle;
  324.         XMSPTR src;
  325.         XMSH dst_handle;
  326.         XMSPTR dst;
  327.       } XMSspec;
  328.  
  329. #define ODD(X)  (((X) & 1L) != 0)
  330.  
  331.  
  332. METHODDEF(void)
  333. read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
  334.                 void FAR * buffer_address,
  335.                 long file_offset, long byte_count)
  336. {
  337.   XMScontext ctx;
  338.   XMSspec spec;
  339.   char endbuffer[2];
  340.  
  341.   /* The XMS driver can't cope with an odd length, so handle the last byte
  342.    * specially if byte_count is odd.  We don't expect this to be common.
  343.    */
  344.  
  345.   spec.length = byte_count & (~ 1L);
  346.   spec.src_handle = info->handle.xms_handle;
  347.   spec.src.offset = file_offset;
  348.   spec.dst_handle = 0;
  349.   spec.dst.ptr = buffer_address;
  350.  
  351.   ctx.ds_si = (void far *) & spec;
  352.   ctx.ax = 0x0b00;              /* EMB move */
  353.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  354.   if (ctx.ax != 1)
  355.     ERREXIT(cinfo, JERR_XMS_READ);
  356.  
  357.   if (ODD(byte_count)) {
  358.     read_xms_store(cinfo, info, (void FAR *) endbuffer,
  359.                    file_offset + byte_count - 1L, 2L);
  360.     ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
  361.   }
  362. }
  363.  
  364.  
  365. METHODDEF(void)
  366. write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
  367.                  void FAR * buffer_address,
  368.                  long file_offset, long byte_count)
  369. {
  370.   XMScontext ctx;
  371.   XMSspec spec;
  372.   char endbuffer[2];
  373.  
  374.   /* The XMS driver can't cope with an odd length, so handle the last byte
  375.    * specially if byte_count is odd.  We don't expect this to be common.
  376.    */
  377.  
  378.   spec.length = byte_count & (~ 1L);
  379.   spec.src_handle = 0;
  380.   spec.src.ptr = buffer_address;
  381.   spec.dst_handle = info->handle.xms_handle;
  382.   spec.dst.offset = file_offset;
  383.  
  384.   ctx.ds_si = (void far *) & spec;
  385.   ctx.ax = 0x0b00;              /* EMB move */
  386.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  387.   if (ctx.ax != 1)
  388.     ERREXIT(cinfo, JERR_XMS_WRITE);
  389.  
  390.   if (ODD(byte_count)) {
  391.     read_xms_store(cinfo, info, (void FAR *) endbuffer,
  392.                    file_offset + byte_count - 1L, 2L);
  393.     endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
  394.     write_xms_store(cinfo, info, (void FAR *) endbuffer,
  395.                     file_offset + byte_count - 1L, 2L);
  396.   }
  397. }
  398.  
  399.  
  400. METHODDEF(void)
  401. close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
  402. {
  403.   XMScontext ctx;
  404.  
  405.   ctx.dx = info->handle.xms_handle;
  406.   ctx.ax = 0x0a00;
  407.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  408.   TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
  409.   /* we ignore any error return from the driver */
  410. }
  411.  
  412.  
  413. LOCAL(boolean)
  414. open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
  415.                 long total_bytes_needed)
  416. {
  417.   XMScontext ctx;
  418.  
  419.   /* Get address of XMS driver */
  420.   jxms_getdriver((XMSDRIVER far *) & xms_driver);
  421.   if (xms_driver == NULL)
  422.     return FALSE;               /* no driver to be had */
  423.  
  424.   /* Get version number, must be >= 2.00 */
  425.   ctx.ax = 0x0000;
  426.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  427.   if (ctx.ax < (unsigned short) 0x0200)
  428.     return FALSE;
  429.  
  430.   /* Try to get space (expressed in kilobytes) */
  431.   ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
  432.   ctx.ax = 0x0900;
  433.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  434.   if (ctx.ax != 1)
  435.     return FALSE;
  436.  
  437.   /* Succeeded, save the handle and away we go */
  438.   info->handle.xms_handle = ctx.dx;
  439.   info->read_backing_store = read_xms_store;
  440.   info->write_backing_store = write_xms_store;
  441.   info->close_backing_store = close_xms_store;
  442.   TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
  443.   return TRUE;                  /* succeeded */
  444. }
  445.  
  446. #endif /* XMS_SUPPORTED */
  447.  
  448.  
  449. /*
  450.  * Access methods for expanded memory.
  451.  */
  452.  
  453. #if EMS_SUPPORTED
  454.  
  455. /* The EMS move specification structure requires word and long fields aligned
  456.  * at odd byte boundaries.  Some compilers will align struct fields at even
  457.  * byte boundaries.  While it's usually possible to force byte alignment,
  458.  * that causes an overall performance penalty and may pose problems in merging
  459.  * JPEG into a larger application.  Instead we accept some rather dirty code
  460.  * here.  Note this code would fail if the hardware did not allow odd-byte
  461.  * word & long accesses, but all 80x86 CPUs do.
  462.  */
  463.  
  464. typedef void far * EMSPTR;
  465.  
  466. typedef union {                 /* EMS move specification structure */
  467.         long length;            /* It's easy to access first 4 bytes */
  468.         char bytes[18];         /* Misaligned fields in here! */
  469.       } EMSspec;
  470.  
  471. /* Macros for accessing misaligned fields */
  472. #define FIELD_AT(spec,offset,type)  (*((type *) &(spec.bytes[offset])))
  473. #define SRC_TYPE(spec)          FIELD_AT(spec,4,char)
  474. #define SRC_HANDLE(spec)        FIELD_AT(spec,5,EMSH)
  475. #define SRC_OFFSET(spec)        FIELD_AT(spec,7,unsigned short)
  476. #define SRC_PAGE(spec)          FIELD_AT(spec,9,unsigned short)
  477. #define SRC_PTR(spec)           FIELD_AT(spec,7,EMSPTR)
  478. #define DST_TYPE(spec)          FIELD_AT(spec,11,char)
  479. #define DST_HANDLE(spec)        FIELD_AT(spec,12,EMSH)
  480. #define DST_OFFSET(spec)        FIELD_AT(spec,14,unsigned short)
  481. #define DST_PAGE(spec)          FIELD_AT(spec,16,unsigned short)
  482. #define DST_PTR(spec)           FIELD_AT(spec,14,EMSPTR)
  483.  
  484. #define EMSPAGESIZE     16384L  /* gospel, see the EMS specs */
  485.  
  486. #define HIBYTE(W)  (((W) >> 8) & 0xFF)
  487. #define LOBYTE(W)  ((W) & 0xFF)
  488.  
  489.  
  490. METHODDEF(void)
  491. read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
  492.                 void FAR * buffer_address,
  493.                 long file_offset, long byte_count)
  494. {
  495.   EMScontext ctx;
  496.   EMSspec spec;
  497.  
  498.   spec.length = byte_count;
  499.   SRC_TYPE(spec) = 1;
  500.   SRC_HANDLE(spec) = info->handle.ems_handle;
  501.   SRC_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
  502.   SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
  503.   DST_TYPE(spec) = 0;
  504.   DST_HANDLE(spec) = 0;
  505.   DST_PTR(spec)    = buffer_address;
  506.  
  507.   ctx.ds_si = (void far *) & spec;
  508.   ctx.ax = 0x5700;              /* move memory region */
  509.   jems_calldriver((EMScontext far *) & ctx);
  510.   if (HIBYTE(ctx.ax) != 0)
  511.     ERREXIT(cinfo, JERR_EMS_READ);
  512. }
  513.  
  514.  
  515. METHODDEF(void)
  516. write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
  517.                  void FAR * buffer_address,
  518.                  long file_offset, long byte_count)
  519. {
  520.   EMScontext ctx;
  521.   EMSspec spec;
  522.  
  523.   spec.length = byte_count;
  524.   SRC_TYPE(spec) = 0;
  525.   SRC_HANDLE(spec) = 0;
  526.   SRC_PTR(spec)    = buffer_address;
  527.   DST_TYPE(spec) = 1;
  528.   DST_HANDLE(spec) = info->handle.ems_handle;
  529.   DST_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
  530.   DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
  531.  
  532.   ctx.ds_si = (void far *) & spec;
  533.   ctx.ax = 0x5700;              /* move memory region */
  534.   jems_calldriver((EMScontext far *) & ctx);
  535.   if (HIBYTE(ctx.ax) != 0)
  536.     ERREXIT(cinfo, JERR_EMS_WRITE);
  537. }
  538.  
  539.  
  540. METHODDEF(void)
  541. close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
  542. {
  543.   EMScontext ctx;
  544.  
  545.   ctx.ax = 0x4500;
  546.   ctx.dx = info->handle.ems_handle;
  547.   jems_calldriver((EMScontext far *) & ctx);
  548.   TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
  549.   /* we ignore any error return from the driver */
  550. }
  551.  
  552.  
  553. LOCAL(boolean)
  554. open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
  555.                 long total_bytes_needed)
  556. {
  557.   EMScontext ctx;
  558.  
  559.   /* Is EMS driver there? */
  560.   if (! jems_available())
  561.     return FALSE;
  562.  
  563.   /* Get status, make sure EMS is OK */
  564.   ctx.ax = 0x4000;
  565.   jems_calldriver((EMScontext far *) & ctx);
  566.   if (HIBYTE(ctx.ax) != 0)
  567.     return FALSE;
  568.  
  569.   /* Get version, must be >= 4.0 */
  570.   ctx.ax = 0x4600;
  571.   jems_calldriver((EMScontext far *) & ctx);
  572.   if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
  573.     return FALSE;
  574.  
  575.   /* Try to allocate requested space */
  576.   ctx.ax = 0x4300;
  577.   ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
  578.   jems_calldriver((EMScontext far *) & ctx);
  579.   if (HIBYTE(ctx.ax) != 0)
  580.     return FALSE;
  581.  
  582.   /* Succeeded, save the handle and away we go */
  583.   info->handle.ems_handle = ctx.dx;
  584.   info->read_backing_store = read_ems_store;
  585.   info->write_backing_store = write_ems_store;
  586.   info->close_backing_store = close_ems_store;
  587.   TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
  588.   return TRUE;                  /* succeeded */
  589. }
  590.  
  591. #endif /* EMS_SUPPORTED */
  592.  
  593.  
  594. /*
  595.  * Initial opening of a backing-store object.
  596.  */
  597.  
  598. GLOBAL(void)
  599. jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
  600.                          long total_bytes_needed)
  601. {
  602.   /* Try extended memory, then expanded memory, then regular file. */
  603. #if XMS_SUPPORTED
  604.   if (open_xms_store(cinfo, info, total_bytes_needed))
  605.     return;
  606. #endif
  607. #if EMS_SUPPORTED
  608.   if (open_ems_store(cinfo, info, total_bytes_needed))
  609.     return;
  610. #endif
  611.   if (open_file_store(cinfo, info, total_bytes_needed))
  612.     return;
  613.   ERREXITS(cinfo, JERR_TFILE_CREATE, "");
  614. }
  615.  
  616.  
  617. /*
  618.  * These routines take care of any system-dependent initialization and
  619.  * cleanup required.
  620.  */
  621.  
  622. GLOBAL(long)
  623. jpeg_mem_init (j_common_ptr cinfo)
  624. {
  625.   next_file_num = 0;            /* initialize temp file name generator */
  626.   return DEFAULT_MAX_MEM;       /* default for max_memory_to_use */
  627. }
  628.  
  629. GLOBAL(void)
  630. jpeg_mem_term (j_common_ptr cinfo)
  631. {
  632.   /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
  633.    * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
  634.    */
  635. #ifdef NEED_FHEAPMIN
  636.   _fheapmin();
  637. #endif
  638. }
  639.