Home | History | Annotate | Download | only in jpeg
      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