src/3rdparty/libjpeg/jmemdos.c
changeset 30 5dc02b23752f
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     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 }