xref: /plan9/sys/src/cmd/gs/jpeg/jmemmac.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * jmemmac.c
37dd7cddfSDavid du Colombier  *
4*593dc095SDavid du Colombier  * Copyright (C) 1992-1997, Thomas G. Lane.
57dd7cddfSDavid du Colombier  * This file is part of the Independent JPEG Group's software.
67dd7cddfSDavid du Colombier  * For conditions of distribution and use, see the accompanying README file.
77dd7cddfSDavid du Colombier  *
87dd7cddfSDavid du Colombier  * jmemmac.c provides an Apple Macintosh implementation of the system-
97dd7cddfSDavid du Colombier  * dependent portion of the JPEG memory manager.
107dd7cddfSDavid du Colombier  *
11*593dc095SDavid du Colombier  * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the
12*593dc095SDavid du Colombier  * JPEG_INTERNALS part of jconfig.h.
13*593dc095SDavid du Colombier  *
147dd7cddfSDavid du Colombier  * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
157dd7cddfSDavid du Colombier  * instead of malloc and free.  It accurately determines the amount of
167dd7cddfSDavid du Colombier  * memory available by using CompactMem.  Notice that if left to its
177dd7cddfSDavid du Colombier  * own devices, this code can chew up all available space in the
187dd7cddfSDavid du Colombier  * application's zone, with the exception of the rather small "slop"
197dd7cddfSDavid du Colombier  * factor computed in jpeg_mem_available().  The application can ensure
207dd7cddfSDavid du Colombier  * that more space is left over by reducing max_memory_to_use.
217dd7cddfSDavid du Colombier  *
22*593dc095SDavid du Colombier  * Large images are swapped to disk using temporary files and System 7.0+'s
23*593dc095SDavid du Colombier  * temporary folder functionality.
247dd7cddfSDavid du Colombier  *
25*593dc095SDavid du Colombier  * Note that jmemmac.c depends on two features of MacOS that were first
26*593dc095SDavid du Colombier  * introduced in System 7: FindFolder and the FSSpec-based calls.
27*593dc095SDavid du Colombier  * If your application uses jmemmac.c and is run under System 6 or earlier,
28*593dc095SDavid du Colombier  * and the jpeg library decides it needs a temporary file, it will abort,
29*593dc095SDavid du Colombier  * printing error messages about requiring System 7.  (If no temporary files
30*593dc095SDavid du Colombier  * are created, it will run fine.)
31*593dc095SDavid du Colombier  *
32*593dc095SDavid du Colombier  * If you want to use jmemmac.c in an application that might be used with
33*593dc095SDavid du Colombier  * System 6 or earlier, then you should remove dependencies on FindFolder
34*593dc095SDavid du Colombier  * and the FSSpec calls.  You will need to replace FindFolder with some
35*593dc095SDavid du Colombier  * other mechanism for finding a place to put temporary files, and you
36*593dc095SDavid du Colombier  * should replace the FSSpec calls with their HFS equivalents:
37*593dc095SDavid du Colombier  *
38*593dc095SDavid du Colombier  *     FSpDelete     ->  HDelete
39*593dc095SDavid du Colombier  *     FSpGetFInfo   ->  HGetFInfo
40*593dc095SDavid du Colombier  *     FSpCreate     ->  HCreate
41*593dc095SDavid du Colombier  *     FSpOpenDF     ->  HOpen      *** Note: not HOpenDF ***
42*593dc095SDavid du Colombier  *     FSMakeFSSpec  ->  (fill in spec by hand.)
43*593dc095SDavid du Colombier  *
44*593dc095SDavid du Colombier  * (Use HOpen instead of HOpenDF.  HOpen is just a glue-interface to PBHOpen,
45*593dc095SDavid du Colombier  * which is on all HFS macs.  HOpenDF is a System 7 addition which avoids the
46*593dc095SDavid du Colombier  * ages-old problem of names starting with a period.)
47*593dc095SDavid du Colombier  *
48*593dc095SDavid du Colombier  * Contributed by Sam Bushell (jsam@iagu.on.net) and
49*593dc095SDavid du Colombier  * Dan Gildor (gyld@in-touch.com).
507dd7cddfSDavid du Colombier  */
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier #define JPEG_INTERNALS
537dd7cddfSDavid du Colombier #include "jinclude.h"
547dd7cddfSDavid du Colombier #include "jpeglib.h"
557dd7cddfSDavid du Colombier #include "jmemsys.h"    /* import the system-dependent declarations */
567dd7cddfSDavid du Colombier 
57*593dc095SDavid du Colombier #ifndef USE_MAC_MEMMGR	/* make sure user got configuration right */
58*593dc095SDavid du Colombier   You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */
597dd7cddfSDavid du Colombier #endif
607dd7cddfSDavid du Colombier 
61*593dc095SDavid du Colombier #include <Memory.h>     /* we use the MacOS memory manager */
62*593dc095SDavid du Colombier #include <Files.h>      /* we use the MacOS File stuff */
63*593dc095SDavid du Colombier #include <Folders.h>    /* we use the MacOS HFS stuff */
64*593dc095SDavid du Colombier #include <Script.h>     /* for smSystemScript */
65*593dc095SDavid du Colombier #include <Gestalt.h>    /* we use Gestalt to test for specific functionality */
66*593dc095SDavid du Colombier 
67*593dc095SDavid du Colombier #ifndef TEMP_FILE_NAME		/* can override from jconfig.h or Makefile */
68*593dc095SDavid du Colombier #define TEMP_FILE_NAME  "JPG%03d.TMP"
69*593dc095SDavid du Colombier #endif
70*593dc095SDavid du Colombier 
71*593dc095SDavid du Colombier static int next_file_num;	/* to distinguish among several temp files */
72*593dc095SDavid du Colombier 
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier /*
757dd7cddfSDavid du Colombier  * Memory allocation and freeing are controlled by the MacOS library
767dd7cddfSDavid du Colombier  * routines NewPtr() and DisposePtr(), which allocate fixed-address
777dd7cddfSDavid du Colombier  * storage.  Unfortunately, the IJG library isn't smart enough to cope
787dd7cddfSDavid du Colombier  * with relocatable storage.
797dd7cddfSDavid du Colombier  */
807dd7cddfSDavid du Colombier 
817dd7cddfSDavid du Colombier GLOBAL(void *)
jpeg_get_small(j_common_ptr cinfo,size_t sizeofobject)827dd7cddfSDavid du Colombier jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier   return (void *) NewPtr(sizeofobject);
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier 
877dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_free_small(j_common_ptr cinfo,void * object,size_t sizeofobject)887dd7cddfSDavid du Colombier jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
897dd7cddfSDavid du Colombier {
907dd7cddfSDavid du Colombier   DisposePtr((Ptr) object);
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier /*
957dd7cddfSDavid du Colombier  * "Large" objects are treated the same as "small" ones.
967dd7cddfSDavid du Colombier  * NB: we include FAR keywords in the routine declarations simply for
977dd7cddfSDavid du Colombier  * consistency with the rest of the IJG code; FAR should expand to empty
987dd7cddfSDavid du Colombier  * on rational architectures like the Mac.
997dd7cddfSDavid du Colombier  */
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier GLOBAL(void FAR *)
jpeg_get_large(j_common_ptr cinfo,size_t sizeofobject)1027dd7cddfSDavid du Colombier jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier   return (void FAR *) NewPtr(sizeofobject);
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier 
1077dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_free_large(j_common_ptr cinfo,void FAR * object,size_t sizeofobject)1087dd7cddfSDavid du Colombier jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
1097dd7cddfSDavid du Colombier {
1107dd7cddfSDavid du Colombier   DisposePtr((Ptr) object);
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier /*
1157dd7cddfSDavid du Colombier  * This routine computes the total memory space available for allocation.
1167dd7cddfSDavid du Colombier  */
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier GLOBAL(long)
jpeg_mem_available(j_common_ptr cinfo,long min_bytes_needed,long max_bytes_needed,long already_allocated)1197dd7cddfSDavid du Colombier jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
1207dd7cddfSDavid du Colombier 		    long max_bytes_needed, long already_allocated)
1217dd7cddfSDavid du Colombier {
1227dd7cddfSDavid du Colombier   long limit = cinfo->mem->max_memory_to_use - already_allocated;
1237dd7cddfSDavid du Colombier   long slop, mem;
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier   /* Don't ask for more than what application has told us we may use */
1267dd7cddfSDavid du Colombier   if (max_bytes_needed > limit && limit > 0)
1277dd7cddfSDavid du Colombier     max_bytes_needed = limit;
1287dd7cddfSDavid du Colombier   /* Find whether there's a big enough free block in the heap.
1297dd7cddfSDavid du Colombier    * CompactMem tries to create a contiguous block of the requested size,
1307dd7cddfSDavid du Colombier    * and then returns the size of the largest free block (which could be
1317dd7cddfSDavid du Colombier    * much more or much less than we asked for).
1327dd7cddfSDavid du Colombier    * We add some slop to ensure we don't use up all available memory.
1337dd7cddfSDavid du Colombier    */
1347dd7cddfSDavid du Colombier   slop = max_bytes_needed / 16 + 32768L;
1357dd7cddfSDavid du Colombier   mem = CompactMem(max_bytes_needed + slop) - slop;
1367dd7cddfSDavid du Colombier   if (mem < 0)
1377dd7cddfSDavid du Colombier     mem = 0;			/* sigh, couldn't even get the slop */
1387dd7cddfSDavid du Colombier   /* Don't take more than the application says we can have */
1397dd7cddfSDavid du Colombier   if (mem > limit && limit > 0)
1407dd7cddfSDavid du Colombier     mem = limit;
1417dd7cddfSDavid du Colombier   return mem;
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier /*
1467dd7cddfSDavid du Colombier  * Backing store (temporary file) management.
1477dd7cddfSDavid du Colombier  * Backing store objects are only used when the value returned by
1487dd7cddfSDavid du Colombier  * jpeg_mem_available is less than the total space needed.  You can dispense
1497dd7cddfSDavid du Colombier  * with these routines if you have plenty of virtual memory; see jmemnobs.c.
1507dd7cddfSDavid du Colombier  */
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier METHODDEF(void)
read_backing_store(j_common_ptr cinfo,backing_store_ptr info,void FAR * buffer_address,long file_offset,long byte_count)1547dd7cddfSDavid du Colombier read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
1557dd7cddfSDavid du Colombier 		    void FAR * buffer_address,
1567dd7cddfSDavid du Colombier 		    long file_offset, long byte_count)
1577dd7cddfSDavid du Colombier {
158*593dc095SDavid du Colombier   long bytes = byte_count;
159*593dc095SDavid du Colombier   long retVal;
160*593dc095SDavid du Colombier 
161*593dc095SDavid du Colombier   if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
1627dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_TFILE_SEEK);
163*593dc095SDavid du Colombier 
164*593dc095SDavid du Colombier   retVal = FSRead ( info->temp_file, &bytes,
165*593dc095SDavid du Colombier 		    (unsigned char *) buffer_address );
166*593dc095SDavid du Colombier   if ( retVal != noErr || bytes != byte_count )
1677dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_TFILE_READ);
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier METHODDEF(void)
write_backing_store(j_common_ptr cinfo,backing_store_ptr info,void FAR * buffer_address,long file_offset,long byte_count)1727dd7cddfSDavid du Colombier write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
1737dd7cddfSDavid du Colombier 		     void FAR * buffer_address,
1747dd7cddfSDavid du Colombier 		     long file_offset, long byte_count)
1757dd7cddfSDavid du Colombier {
176*593dc095SDavid du Colombier   long bytes = byte_count;
177*593dc095SDavid du Colombier   long retVal;
178*593dc095SDavid du Colombier 
179*593dc095SDavid du Colombier   if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
1807dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_TFILE_SEEK);
181*593dc095SDavid du Colombier 
182*593dc095SDavid du Colombier   retVal = FSWrite ( info->temp_file, &bytes,
183*593dc095SDavid du Colombier 		     (unsigned char *) buffer_address );
184*593dc095SDavid du Colombier   if ( retVal != noErr || bytes != byte_count )
1857dd7cddfSDavid du Colombier     ERREXIT(cinfo, JERR_TFILE_WRITE);
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier METHODDEF(void)
close_backing_store(j_common_ptr cinfo,backing_store_ptr info)1907dd7cddfSDavid du Colombier close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
1917dd7cddfSDavid du Colombier {
192*593dc095SDavid du Colombier   FSClose ( info->temp_file );
193*593dc095SDavid du Colombier   FSpDelete ( &(info->tempSpec) );
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier /*
1987dd7cddfSDavid du Colombier  * Initial opening of a backing-store object.
1997dd7cddfSDavid du Colombier  *
200*593dc095SDavid du Colombier  * This version uses FindFolder to find the Temporary Items folder,
201*593dc095SDavid du Colombier  * and puts the temporary file in there.
2027dd7cddfSDavid du Colombier  */
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_open_backing_store(j_common_ptr cinfo,backing_store_ptr info,long total_bytes_needed)2057dd7cddfSDavid du Colombier jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
2067dd7cddfSDavid du Colombier 			 long total_bytes_needed)
2077dd7cddfSDavid du Colombier {
208*593dc095SDavid du Colombier   short         tmpRef, vRefNum;
209*593dc095SDavid du Colombier   long          dirID;
210*593dc095SDavid du Colombier   FInfo         finderInfo;
211*593dc095SDavid du Colombier   FSSpec        theSpec;
212*593dc095SDavid du Colombier   Str255        fName;
213*593dc095SDavid du Colombier   OSErr         osErr;
214*593dc095SDavid du Colombier   long          gestaltResponse = 0;
215*593dc095SDavid du Colombier 
216*593dc095SDavid du Colombier   /* Check that FSSpec calls are available. */
217*593dc095SDavid du Colombier   osErr = Gestalt( gestaltFSAttr, &gestaltResponse );
218*593dc095SDavid du Colombier   if ( ( osErr != noErr )
219*593dc095SDavid du Colombier        || !( gestaltResponse & (1<<gestaltHasFSSpecCalls) ) )
220*593dc095SDavid du Colombier     ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required");
221*593dc095SDavid du Colombier   /* TO DO: add a proper error message to jerror.h. */
222*593dc095SDavid du Colombier 
223*593dc095SDavid du Colombier   /* Check that FindFolder is available. */
224*593dc095SDavid du Colombier   osErr = Gestalt( gestaltFindFolderAttr, &gestaltResponse );
225*593dc095SDavid du Colombier   if ( ( osErr != noErr )
226*593dc095SDavid du Colombier        || !( gestaltResponse & (1<<gestaltFindFolderPresent) ) )
227*593dc095SDavid du Colombier     ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required.");
228*593dc095SDavid du Colombier   /* TO DO: add a proper error message to jerror.h. */
229*593dc095SDavid du Colombier 
230*593dc095SDavid du Colombier   osErr = FindFolder ( kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
231*593dc095SDavid du Colombier                        &vRefNum, &dirID );
232*593dc095SDavid du Colombier   if ( osErr != noErr )
233*593dc095SDavid du Colombier     ERREXITS(cinfo, JERR_TFILE_CREATE, "- temporary items folder unavailable");
234*593dc095SDavid du Colombier   /* TO DO: Try putting the temp files somewhere else. */
235*593dc095SDavid du Colombier 
236*593dc095SDavid du Colombier   /* Keep generating file names till we find one that's not in use */
237*593dc095SDavid du Colombier   for (;;) {
238*593dc095SDavid du Colombier     next_file_num++;		/* advance counter */
239*593dc095SDavid du Colombier 
240*593dc095SDavid du Colombier     sprintf(info->temp_name, TEMP_FILE_NAME, next_file_num);
241*593dc095SDavid du Colombier     strcpy ( (Ptr)fName+1, info->temp_name );
242*593dc095SDavid du Colombier     *fName = strlen (info->temp_name);
243*593dc095SDavid du Colombier     osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec );
244*593dc095SDavid du Colombier 
245*593dc095SDavid du Colombier     if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr )
246*593dc095SDavid du Colombier       break;
247*593dc095SDavid du Colombier   }
248*593dc095SDavid du Colombier 
249*593dc095SDavid du Colombier   osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript );
250*593dc095SDavid du Colombier   if ( osErr != noErr )
251*593dc095SDavid du Colombier     ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
252*593dc095SDavid du Colombier 
253*593dc095SDavid du Colombier   osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) );
254*593dc095SDavid du Colombier   if ( osErr != noErr )
255*593dc095SDavid du Colombier     ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
256*593dc095SDavid du Colombier 
257*593dc095SDavid du Colombier   info->tempSpec = theSpec;
258*593dc095SDavid du Colombier 
2597dd7cddfSDavid du Colombier   info->read_backing_store = read_backing_store;
2607dd7cddfSDavid du Colombier   info->write_backing_store = write_backing_store;
2617dd7cddfSDavid du Colombier   info->close_backing_store = close_backing_store;
262*593dc095SDavid du Colombier   TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier 
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier /*
2677dd7cddfSDavid du Colombier  * These routines take care of any system-dependent initialization and
2687dd7cddfSDavid du Colombier  * cleanup required.
2697dd7cddfSDavid du Colombier  */
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier GLOBAL(long)
jpeg_mem_init(j_common_ptr cinfo)2727dd7cddfSDavid du Colombier jpeg_mem_init (j_common_ptr cinfo)
2737dd7cddfSDavid du Colombier {
274*593dc095SDavid du Colombier   next_file_num = 0;
275*593dc095SDavid du Colombier 
2767dd7cddfSDavid du Colombier   /* max_memory_to_use will be initialized to FreeMem()'s result;
2777dd7cddfSDavid du Colombier    * the calling application might later reduce it, for example
2787dd7cddfSDavid du Colombier    * to leave room to invoke multiple JPEG objects.
2797dd7cddfSDavid du Colombier    * Note that FreeMem returns the total number of free bytes;
2807dd7cddfSDavid du Colombier    * it may not be possible to allocate a single block of this size.
2817dd7cddfSDavid du Colombier    */
2827dd7cddfSDavid du Colombier   return FreeMem();
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier 
2857dd7cddfSDavid du Colombier GLOBAL(void)
jpeg_mem_term(j_common_ptr cinfo)2867dd7cddfSDavid du Colombier jpeg_mem_term (j_common_ptr cinfo)
2877dd7cddfSDavid du Colombier {
2887dd7cddfSDavid du Colombier   /* no work */
2897dd7cddfSDavid du Colombier }
290