]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/jpeg6/jmemmgr.cpp
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / libs / jpeg6 / jmemmgr.cpp
1 /*\r
2 \r
3  * jmemmgr.c\r
4 \r
5  *\r
6 \r
7  * Copyright (C) 1991-1995, Thomas G. Lane.\r
8 \r
9  * This file is part of the Independent JPEG Group's software.\r
10 \r
11  * For conditions of distribution and use, see the accompanying README file.\r
12 \r
13  *\r
14 \r
15  * This file contains the JPEG system-independent memory management\r
16 \r
17  * routines.  This code is usable across a wide variety of machines; most\r
18 \r
19  * of the system dependencies have been isolated in a separate file.\r
20 \r
21  * The major functions provided here are:\r
22 \r
23  *   * pool-based allocation and freeing of memory;\r
24 \r
25  *   * policy decisions about how to divide available memory among the\r
26 \r
27  *     virtual arrays;\r
28 \r
29  *   * control logic for swapping virtual arrays between main memory and\r
30 \r
31  *     backing storage.\r
32 \r
33  * The separate system-dependent file provides the actual backing-storage\r
34 \r
35  * access code, and it contains the policy decision about how much total\r
36 \r
37  * main memory to use.\r
38 \r
39  * This file is system-dependent in the sense that some of its functions\r
40 \r
41  * are unnecessary in some systems.  For example, if there is enough virtual\r
42 \r
43  * memory so that backing storage will never be used, much of the virtual\r
44 \r
45  * array control logic could be removed.  (Of course, if you have that much\r
46 \r
47  * memory then you shouldn't care about a little bit of unused code...)\r
48 \r
49  */\r
50 \r
51 \r
52 \r
53 #define JPEG_INTERNALS\r
54 \r
55 #define AM_MEMORY_MANAGER       /* we define jvirt_Xarray_control structs */\r
56 \r
57 #include "jinclude.h"\r
58 \r
59 #include "radiant_jpeglib.h"\r
60 \r
61 #include "jmemsys.h"            /* import the system-dependent declarations */\r
62 \r
63 \r
64 \r
65 #ifndef NO_GETENV\r
66 \r
67 #ifndef HAVE_STDLIB_H           /* <stdlib.h> should declare getenv() */\r
68 \r
69 extern char * getenv JPP((const char * name));\r
70 \r
71 #endif\r
72 \r
73 #endif\r
74 \r
75 \r
76 \r
77 \r
78 \r
79 /*\r
80 \r
81  * Some important notes:\r
82 \r
83  *   The allocation routines provided here must never return NULL.\r
84 \r
85  *   They should exit to error_exit if unsuccessful.\r
86 \r
87  *\r
88 \r
89  *   It's not a good idea to try to merge the sarray and barray routines,\r
90 \r
91  *   even though they are textually almost the same, because samples are\r
92 \r
93  *   usually stored as bytes while coefficients are shorts or ints.  Thus,\r
94 \r
95  *   in machines where byte pointers have a different representation from\r
96 \r
97  *   word pointers, the resulting machine code could not be the same.\r
98 \r
99  */\r
100 \r
101 \r
102 \r
103 \r
104 \r
105 /*\r
106 \r
107  * Many machines require storage alignment: longs must start on 4-byte\r
108 \r
109  * boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()\r
110 \r
111  * always returns pointers that are multiples of the worst-case alignment\r
112 \r
113  * requirement, and we had better do so too.\r
114 \r
115  * There isn't any really portable way to determine the worst-case alignment\r
116 \r
117  * requirement.  This module assumes that the alignment requirement is\r
118 \r
119  * multiples of sizeof(ALIGN_TYPE).\r
120 \r
121  * By default, we define ALIGN_TYPE as double.  This is necessary on some\r
122 \r
123  * workstations (where doubles really do need 8-byte alignment) and will work\r
124 \r
125  * fine on nearly everything.  If your machine has lesser alignment needs,\r
126 \r
127  * you can save a few bytes by making ALIGN_TYPE smaller.\r
128 \r
129  * The only place I know of where this will NOT work is certain Macintosh\r
130 \r
131  * 680x0 compilers that define double as a 10-byte IEEE extended float.\r
132 \r
133  * Doing 10-byte alignment is counterproductive because longwords won't be\r
134 \r
135  * aligned well.  Put "#define ALIGN_TYPE long" in jconfig.h if you have\r
136 \r
137  * such a compiler.\r
138 \r
139  */\r
140 \r
141 \r
142 \r
143 #ifndef ALIGN_TYPE              /* so can override from jconfig.h */\r
144 \r
145 #define ALIGN_TYPE  double\r
146 \r
147 #endif\r
148 \r
149 \r
150 \r
151 \r
152 \r
153 /*\r
154 \r
155  * We allocate objects from "pools", where each pool is gotten with a single\r
156 \r
157  * request to jpeg_get_small() or jpeg_get_large().  There is no per-object\r
158 \r
159  * overhead within a pool, except for alignment padding.  Each pool has a\r
160 \r
161  * header with a link to the next pool of the same class.\r
162 \r
163  * Small and large pool headers are identical except that the latter's\r
164 \r
165  * link pointer must be FAR on 80x86 machines.\r
166 \r
167  * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE\r
168 \r
169  * field.  This forces the compiler to make SIZEOF(small_pool_hdr) a multiple\r
170 \r
171  * of the alignment requirement of ALIGN_TYPE.\r
172 \r
173  */\r
174 \r
175 \r
176 \r
177 typedef union small_pool_struct * small_pool_ptr;\r
178 \r
179 \r
180 \r
181 typedef union small_pool_struct {\r
182 \r
183   struct {\r
184 \r
185     small_pool_ptr next;        /* next in list of pools */\r
186 \r
187     size_t bytes_used;          /* how many bytes already used within pool */\r
188 \r
189     size_t bytes_left;          /* bytes still available in this pool */\r
190 \r
191   } hdr;\r
192 \r
193   ALIGN_TYPE dummy;             /* included in union to ensure alignment */\r
194 \r
195 } small_pool_hdr;\r
196 \r
197 \r
198 \r
199 typedef union large_pool_struct FAR * large_pool_ptr;\r
200 \r
201 \r
202 \r
203 typedef union large_pool_struct {\r
204 \r
205   struct {\r
206 \r
207     large_pool_ptr next;        /* next in list of pools */\r
208 \r
209     size_t bytes_used;          /* how many bytes already used within pool */\r
210 \r
211     size_t bytes_left;          /* bytes still available in this pool */\r
212 \r
213   } hdr;\r
214 \r
215   ALIGN_TYPE dummy;             /* included in union to ensure alignment */\r
216 \r
217 } large_pool_hdr;\r
218 \r
219 \r
220 \r
221 \r
222 \r
223 /*\r
224 \r
225  * Here is the full definition of a memory manager object.\r
226 \r
227  */\r
228 \r
229 \r
230 \r
231 typedef struct {\r
232 \r
233   struct jpeg_memory_mgr pub;   /* public fields */\r
234 \r
235 \r
236 \r
237   /* Each pool identifier (lifetime class) names a linked list of pools. */\r
238 \r
239   small_pool_ptr small_list[JPOOL_NUMPOOLS];\r
240 \r
241   large_pool_ptr large_list[JPOOL_NUMPOOLS];\r
242 \r
243 \r
244 \r
245   /* Since we only have one lifetime class of virtual arrays, only one\r
246 \r
247    * linked list is necessary (for each datatype).  Note that the virtual\r
248 \r
249    * array control blocks being linked together are actually stored somewhere\r
250 \r
251    * in the small-pool list.\r
252 \r
253    */\r
254 \r
255   jvirt_sarray_ptr virt_sarray_list;\r
256 \r
257   jvirt_barray_ptr virt_barray_list;\r
258 \r
259 \r
260 \r
261   /* This counts total space obtained from jpeg_get_small/large */\r
262 \r
263   long total_space_allocated;\r
264 \r
265 \r
266 \r
267   /* alloc_sarray and alloc_barray set this value for use by virtual\r
268 \r
269    * array routines.\r
270 \r
271    */\r
272 \r
273   JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */\r
274 \r
275 } my_memory_mgr;\r
276 \r
277 \r
278 \r
279 typedef my_memory_mgr * my_mem_ptr;\r
280 \r
281 \r
282 \r
283 \r
284 \r
285 /*\r
286 \r
287  * The control blocks for virtual arrays.\r
288 \r
289  * Note that these blocks are allocated in the "small" pool area.\r
290 \r
291  * System-dependent info for the associated backing store (if any) is hidden\r
292 \r
293  * inside the backing_store_info struct.\r
294 \r
295  */\r
296 \r
297 \r
298 \r
299 struct jvirt_sarray_control {\r
300 \r
301   JSAMPARRAY mem_buffer;        /* => the in-memory buffer */\r
302 \r
303   JDIMENSION rows_in_array;     /* total virtual array height */\r
304 \r
305   JDIMENSION samplesperrow;     /* width of array (and of memory buffer) */\r
306 \r
307   JDIMENSION maxaccess;         /* max rows accessed by access_virt_sarray */\r
308 \r
309   JDIMENSION rows_in_mem;       /* height of memory buffer */\r
310 \r
311   JDIMENSION rowsperchunk;      /* allocation chunk size in mem_buffer */\r
312 \r
313   JDIMENSION cur_start_row;     /* first logical row # in the buffer */\r
314 \r
315   JDIMENSION first_undef_row;   /* row # of first uninitialized row */\r
316 \r
317   boolean pre_zero;             /* pre-zero mode requested? */\r
318 \r
319   boolean dirty;                /* do current buffer contents need written? */\r
320 \r
321   boolean b_s_open;             /* is backing-store data valid? */\r
322 \r
323   jvirt_sarray_ptr next;        /* link to next virtual sarray control block */\r
324 \r
325   backing_store_info b_s_info;  /* System-dependent control info */\r
326 \r
327 };\r
328 \r
329 \r
330 \r
331 struct jvirt_barray_control {\r
332 \r
333   JBLOCKARRAY mem_buffer;       /* => the in-memory buffer */\r
334 \r
335   JDIMENSION rows_in_array;     /* total virtual array height */\r
336 \r
337   JDIMENSION blocksperrow;      /* width of array (and of memory buffer) */\r
338 \r
339   JDIMENSION maxaccess;         /* max rows accessed by access_virt_barray */\r
340 \r
341   JDIMENSION rows_in_mem;       /* height of memory buffer */\r
342 \r
343   JDIMENSION rowsperchunk;      /* allocation chunk size in mem_buffer */\r
344 \r
345   JDIMENSION cur_start_row;     /* first logical row # in the buffer */\r
346 \r
347   JDIMENSION first_undef_row;   /* row # of first uninitialized row */\r
348 \r
349   boolean pre_zero;             /* pre-zero mode requested? */\r
350 \r
351   boolean dirty;                /* do current buffer contents need written? */\r
352 \r
353   boolean b_s_open;             /* is backing-store data valid? */\r
354 \r
355   jvirt_barray_ptr next;        /* link to next virtual barray control block */\r
356 \r
357   backing_store_info b_s_info;  /* System-dependent control info */\r
358 \r
359 };\r
360 \r
361 \r
362 \r
363 \r
364 \r
365 #ifdef MEM_STATS                /* optional extra stuff for statistics */\r
366 \r
367 \r
368 \r
369 LOCAL void\r
370 \r
371 print_mem_stats (j_common_ptr cinfo, int pool_id)\r
372 \r
373 {\r
374 \r
375   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
376 \r
377   small_pool_ptr shdr_ptr;\r
378 \r
379   large_pool_ptr lhdr_ptr;\r
380 \r
381 \r
382 \r
383   /* Since this is only a debugging stub, we can cheat a little by using\r
384 \r
385    * fprintf directly rather than going through the trace message code.\r
386 \r
387    * This is helpful because message parm array can't handle longs.\r
388 \r
389    */\r
390 \r
391   fprintf(stderr, "Freeing pool %d, total space = %ld\n",\r
392 \r
393           pool_id, mem->total_space_allocated);\r
394 \r
395 \r
396 \r
397   for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;\r
398 \r
399        lhdr_ptr = lhdr_ptr->hdr.next) {\r
400 \r
401     fprintf(stderr, "  Large chunk used %ld\n",\r
402 \r
403             (long) lhdr_ptr->hdr.bytes_used);\r
404 \r
405   }\r
406 \r
407 \r
408 \r
409   for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;\r
410 \r
411        shdr_ptr = shdr_ptr->hdr.next) {\r
412 \r
413     fprintf(stderr, "  Small chunk used %ld free %ld\n",\r
414 \r
415             (long) shdr_ptr->hdr.bytes_used,\r
416 \r
417             (long) shdr_ptr->hdr.bytes_left);\r
418 \r
419   }\r
420 \r
421 }\r
422 \r
423 \r
424 \r
425 #endif /* MEM_STATS */\r
426 \r
427 \r
428 \r
429 \r
430 \r
431 LOCAL void\r
432 \r
433 out_of_memory (j_common_ptr cinfo, int which)\r
434 \r
435 /* Report an out-of-memory error and stop execution */\r
436 \r
437 /* If we compiled MEM_STATS support, report alloc requests before dying */\r
438 \r
439 {\r
440 \r
441 #ifdef MEM_STATS\r
442 \r
443   cinfo->err->trace_level = 2;  /* force self_destruct to report stats */\r
444 \r
445 #endif\r
446 \r
447   ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);\r
448 \r
449 }\r
450 \r
451 \r
452 \r
453 \r
454 \r
455 /*\r
456 \r
457  * Allocation of "small" objects.\r
458 \r
459  *\r
460 \r
461  * For these, we use pooled storage.  When a new pool must be created,\r
462 \r
463  * we try to get enough space for the current request plus a "slop" factor,\r
464 \r
465  * where the slop will be the amount of leftover space in the new pool.\r
466 \r
467  * The speed vs. space tradeoff is largely determined by the slop values.\r
468 \r
469  * A different slop value is provided for each pool class (lifetime),\r
470 \r
471  * and we also distinguish the first pool of a class from later ones.\r
472 \r
473  * NOTE: the values given work fairly well on both 16- and 32-bit-int\r
474 \r
475  * machines, but may be too small if longs are 64 bits or more.\r
476 \r
477  */\r
478 \r
479 \r
480 \r
481 static const size_t first_pool_slop[JPOOL_NUMPOOLS] = \r
482 \r
483 {\r
484 \r
485         1600,                   /* first PERMANENT pool */\r
486 \r
487         16000                   /* first IMAGE pool */\r
488 \r
489 };\r
490 \r
491 \r
492 \r
493 static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = \r
494 \r
495 {\r
496 \r
497         0,                      /* additional PERMANENT pools */\r
498 \r
499         5000                    /* additional IMAGE pools */\r
500 \r
501 };\r
502 \r
503 \r
504 \r
505 #define MIN_SLOP  50            /* greater than 0 to avoid futile looping */\r
506 \r
507 \r
508 \r
509 \r
510 \r
511 METHODDEF void *\r
512 \r
513 alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)\r
514 \r
515 /* Allocate a "small" object */\r
516 \r
517 {\r
518 \r
519   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
520 \r
521   small_pool_ptr hdr_ptr, prev_hdr_ptr;\r
522 \r
523   char * data_ptr;\r
524 \r
525   size_t odd_bytes, min_request, slop;\r
526 \r
527 \r
528 \r
529   /* Check for unsatisfiable request (do now to ensure no overflow below) */\r
530 \r
531   if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))\r
532 \r
533     out_of_memory(cinfo, 1);    /* request exceeds malloc's ability */\r
534 \r
535 \r
536 \r
537   /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */\r
538 \r
539   odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);\r
540 \r
541   if (odd_bytes > 0)\r
542 \r
543     sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;\r
544 \r
545 \r
546 \r
547   /* See if space is available in any existing pool */\r
548 \r
549   if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)\r
550 \r
551     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */\r
552 \r
553   prev_hdr_ptr = NULL;\r
554 \r
555   hdr_ptr = mem->small_list[pool_id];\r
556 \r
557   while (hdr_ptr != NULL) {\r
558 \r
559     if (hdr_ptr->hdr.bytes_left >= sizeofobject)\r
560 \r
561       break;                    /* found pool with enough space */\r
562 \r
563     prev_hdr_ptr = hdr_ptr;\r
564 \r
565     hdr_ptr = hdr_ptr->hdr.next;\r
566 \r
567   }\r
568 \r
569 \r
570 \r
571   /* Time to make a new pool? */\r
572 \r
573   if (hdr_ptr == NULL) {\r
574 \r
575     /* min_request is what we need now, slop is what will be leftover */\r
576 \r
577     min_request = sizeofobject + SIZEOF(small_pool_hdr);\r
578 \r
579     if (prev_hdr_ptr == NULL)   /* first pool in class? */\r
580 \r
581       slop = first_pool_slop[pool_id];\r
582 \r
583     else\r
584 \r
585       slop = extra_pool_slop[pool_id];\r
586 \r
587     /* Don't ask for more than MAX_ALLOC_CHUNK */\r
588 \r
589     if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))\r
590 \r
591       slop = (size_t) (MAX_ALLOC_CHUNK-min_request);\r
592 \r
593     /* Try to get space, if fail reduce slop and try again */\r
594 \r
595     for (;;) {\r
596 \r
597       hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);\r
598 \r
599       if (hdr_ptr != NULL)\r
600 \r
601         break;\r
602 \r
603       slop /= 2;\r
604 \r
605       if (slop < MIN_SLOP)      /* give up when it gets real small */\r
606 \r
607         out_of_memory(cinfo, 2); /* jpeg_get_small failed */\r
608 \r
609     }\r
610 \r
611     mem->total_space_allocated += min_request + slop;\r
612 \r
613     /* Success, initialize the new pool header and add to end of list */\r
614 \r
615     hdr_ptr->hdr.next = NULL;\r
616 \r
617     hdr_ptr->hdr.bytes_used = 0;\r
618 \r
619     hdr_ptr->hdr.bytes_left = sizeofobject + slop;\r
620 \r
621     if (prev_hdr_ptr == NULL)   /* first pool in class? */\r
622 \r
623       mem->small_list[pool_id] = hdr_ptr;\r
624 \r
625     else\r
626 \r
627       prev_hdr_ptr->hdr.next = hdr_ptr;\r
628 \r
629   }\r
630 \r
631 \r
632 \r
633   /* OK, allocate the object from the current pool */\r
634 \r
635   data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */\r
636 \r
637   data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */\r
638 \r
639   hdr_ptr->hdr.bytes_used += sizeofobject;\r
640 \r
641   hdr_ptr->hdr.bytes_left -= sizeofobject;\r
642 \r
643 \r
644 \r
645   return (void *) data_ptr;\r
646 \r
647 }\r
648 \r
649 \r
650 \r
651 \r
652 \r
653 /*\r
654 \r
655  * Allocation of "large" objects.\r
656 \r
657  *\r
658 \r
659  * The external semantics of these are the same as "small" objects,\r
660 \r
661  * except that FAR pointers are used on 80x86.  However the pool\r
662 \r
663  * management heuristics are quite different.  We assume that each\r
664 \r
665  * request is large enough that it may as well be passed directly to\r
666 \r
667  * jpeg_get_large; the pool management just links everything together\r
668 \r
669  * so that we can free it all on demand.\r
670 \r
671  * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY\r
672 \r
673  * structures.  The routines that create these structures (see below)\r
674 \r
675  * deliberately bunch rows together to ensure a large request size.\r
676 \r
677  */\r
678 \r
679 \r
680 \r
681 METHODDEF void FAR *\r
682 \r
683 alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)\r
684 \r
685 /* Allocate a "large" object */\r
686 \r
687 {\r
688 \r
689   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
690 \r
691   large_pool_ptr hdr_ptr;\r
692 \r
693   size_t odd_bytes;\r
694 \r
695 \r
696 \r
697   /* Check for unsatisfiable request (do now to ensure no overflow below) */\r
698 \r
699   if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))\r
700 \r
701     out_of_memory(cinfo, 3);    /* request exceeds malloc's ability */\r
702 \r
703 \r
704 \r
705   /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */\r
706 \r
707   odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);\r
708 \r
709   if (odd_bytes > 0)\r
710 \r
711     sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;\r
712 \r
713 \r
714 \r
715   /* Always make a new pool */\r
716 \r
717   if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)\r
718 \r
719     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */\r
720 \r
721 \r
722 \r
723   hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +\r
724 \r
725                                             SIZEOF(large_pool_hdr));\r
726 \r
727   if (hdr_ptr == NULL)\r
728 \r
729     out_of_memory(cinfo, 4);    /* jpeg_get_large failed */\r
730 \r
731   mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);\r
732 \r
733 \r
734 \r
735   /* Success, initialize the new pool header and add to list */\r
736 \r
737   hdr_ptr->hdr.next = mem->large_list[pool_id];\r
738 \r
739   /* We maintain space counts in each pool header for statistical purposes,\r
740 \r
741    * even though they are not needed for allocation.\r
742 \r
743    */\r
744 \r
745   hdr_ptr->hdr.bytes_used = sizeofobject;\r
746 \r
747   hdr_ptr->hdr.bytes_left = 0;\r
748 \r
749   mem->large_list[pool_id] = hdr_ptr;\r
750 \r
751 \r
752 \r
753   return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */\r
754 \r
755 }\r
756 \r
757 \r
758 \r
759 \r
760 \r
761 /*\r
762 \r
763  * Creation of 2-D sample arrays.\r
764 \r
765  * The pointers are in near heap, the samples themselves in FAR heap.\r
766 \r
767  *\r
768 \r
769  * To minimize allocation overhead and to allow I/O of large contiguous\r
770 \r
771  * blocks, we allocate the sample rows in groups of as many rows as possible\r
772 \r
773  * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.\r
774 \r
775  * NB: the virtual array control routines, later in this file, know about\r
776 \r
777  * this chunking of rows.  The rowsperchunk value is left in the mem manager\r
778 \r
779  * object so that it can be saved away if this sarray is the workspace for\r
780 \r
781  * a virtual array.\r
782 \r
783  */\r
784 \r
785 \r
786 \r
787 METHODDEF JSAMPARRAY\r
788 \r
789 alloc_sarray (j_common_ptr cinfo, int pool_id,\r
790 \r
791               JDIMENSION samplesperrow, JDIMENSION numrows)\r
792 \r
793 /* Allocate a 2-D sample array */\r
794 \r
795 {\r
796 \r
797   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
798 \r
799   JSAMPARRAY result;\r
800 \r
801   JSAMPROW workspace;\r
802 \r
803   JDIMENSION rowsperchunk, currow, i;\r
804 \r
805   long ltemp;\r
806 \r
807 \r
808 \r
809   /* Calculate max # of rows allowed in one allocation chunk */\r
810 \r
811   ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /\r
812 \r
813           ((long) samplesperrow * SIZEOF(JSAMPLE));\r
814 \r
815   if (ltemp <= 0)\r
816 \r
817     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);\r
818 \r
819   if (ltemp < (long) numrows)\r
820 \r
821     rowsperchunk = (JDIMENSION) ltemp;\r
822 \r
823   else\r
824 \r
825     rowsperchunk = numrows;\r
826 \r
827   mem->last_rowsperchunk = rowsperchunk;\r
828 \r
829 \r
830 \r
831   /* Get space for row pointers (small object) */\r
832 \r
833   result = (JSAMPARRAY) alloc_small(cinfo, pool_id,\r
834 \r
835                                     (size_t) (numrows * SIZEOF(JSAMPROW)));\r
836 \r
837 \r
838 \r
839   /* Get the rows themselves (large objects) */\r
840 \r
841   currow = 0;\r
842 \r
843   while (currow < numrows) {\r
844 \r
845     rowsperchunk = MIN(rowsperchunk, numrows - currow);\r
846 \r
847     workspace = (JSAMPROW) alloc_large(cinfo, pool_id,\r
848 \r
849         (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow\r
850 \r
851                   * SIZEOF(JSAMPLE)));\r
852 \r
853     for (i = rowsperchunk; i > 0; i--) {\r
854 \r
855       result[currow++] = workspace;\r
856 \r
857       workspace += samplesperrow;\r
858 \r
859     }\r
860 \r
861   }\r
862 \r
863 \r
864 \r
865   return result;\r
866 \r
867 }\r
868 \r
869 \r
870 \r
871 \r
872 \r
873 /*\r
874 \r
875  * Creation of 2-D coefficient-block arrays.\r
876 \r
877  * This is essentially the same as the code for sample arrays, above.\r
878 \r
879  */\r
880 \r
881 \r
882 \r
883 METHODDEF JBLOCKARRAY\r
884 \r
885 alloc_barray (j_common_ptr cinfo, int pool_id,\r
886 \r
887               JDIMENSION blocksperrow, JDIMENSION numrows)\r
888 \r
889 /* Allocate a 2-D coefficient-block array */\r
890 \r
891 {\r
892 \r
893   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
894 \r
895   JBLOCKARRAY result;\r
896 \r
897   JBLOCKROW workspace;\r
898 \r
899   JDIMENSION rowsperchunk, currow, i;\r
900 \r
901   long ltemp;\r
902 \r
903 \r
904 \r
905   /* Calculate max # of rows allowed in one allocation chunk */\r
906 \r
907   ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /\r
908 \r
909           ((long) blocksperrow * SIZEOF(JBLOCK));\r
910 \r
911   if (ltemp <= 0)\r
912 \r
913     ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);\r
914 \r
915   if (ltemp < (long) numrows)\r
916 \r
917     rowsperchunk = (JDIMENSION) ltemp;\r
918 \r
919   else\r
920 \r
921     rowsperchunk = numrows;\r
922 \r
923   mem->last_rowsperchunk = rowsperchunk;\r
924 \r
925 \r
926 \r
927   /* Get space for row pointers (small object) */\r
928 \r
929   result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,\r
930 \r
931                                      (size_t) (numrows * SIZEOF(JBLOCKROW)));\r
932 \r
933 \r
934 \r
935   /* Get the rows themselves (large objects) */\r
936 \r
937   currow = 0;\r
938 \r
939   while (currow < numrows) {\r
940 \r
941     rowsperchunk = MIN(rowsperchunk, numrows - currow);\r
942 \r
943     workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,\r
944 \r
945         (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow\r
946 \r
947                   * SIZEOF(JBLOCK)));\r
948 \r
949     for (i = rowsperchunk; i > 0; i--) {\r
950 \r
951       result[currow++] = workspace;\r
952 \r
953       workspace += blocksperrow;\r
954 \r
955     }\r
956 \r
957   }\r
958 \r
959 \r
960 \r
961   return result;\r
962 \r
963 }\r
964 \r
965 \r
966 \r
967 \r
968 \r
969 /*\r
970 \r
971  * About virtual array management:\r
972 \r
973  *\r
974 \r
975  * The above "normal" array routines are only used to allocate strip buffers\r
976 \r
977  * (as wide as the image, but just a few rows high).  Full-image-sized buffers\r
978 \r
979  * are handled as "virtual" arrays.  The array is still accessed a strip at a\r
980 \r
981  * time, but the memory manager must save the whole array for repeated\r
982 \r
983  * accesses.  The intended implementation is that there is a strip buffer in\r
984 \r
985  * memory (as high as is possible given the desired memory limit), plus a\r
986 \r
987  * backing file that holds the rest of the array.\r
988 \r
989  *\r
990 \r
991  * The request_virt_array routines are told the total size of the image and\r
992 \r
993  * the maximum number of rows that will be accessed at once.  The in-memory\r
994 \r
995  * buffer must be at least as large as the maxaccess value.\r
996 \r
997  *\r
998 \r
999  * The request routines create control blocks but not the in-memory buffers.\r
1000 \r
1001  * That is postponed until realize_virt_arrays is called.  At that time the\r
1002 \r
1003  * total amount of space needed is known (approximately, anyway), so free\r
1004 \r
1005  * memory can be divided up fairly.\r
1006 \r
1007  *\r
1008 \r
1009  * The access_virt_array routines are responsible for making a specific strip\r
1010 \r
1011  * area accessible (after reading or writing the backing file, if necessary).\r
1012 \r
1013  * Note that the access routines are told whether the caller intends to modify\r
1014 \r
1015  * the accessed strip; during a read-only pass this saves having to rewrite\r
1016 \r
1017  * data to disk.  The access routines are also responsible for pre-zeroing\r
1018 \r
1019  * any newly accessed rows, if pre-zeroing was requested.\r
1020 \r
1021  *\r
1022 \r
1023  * In current usage, the access requests are usually for nonoverlapping\r
1024 \r
1025  * strips; that is, successive access start_row numbers differ by exactly\r
1026 \r
1027  * num_rows = maxaccess.  This means we can get good performance with simple\r
1028 \r
1029  * buffer dump/reload logic, by making the in-memory buffer be a multiple\r
1030 \r
1031  * of the access height; then there will never be accesses across bufferload\r
1032 \r
1033  * boundaries.  The code will still work with overlapping access requests,\r
1034 \r
1035  * but it doesn't handle bufferload overlaps very efficiently.\r
1036 \r
1037  */\r
1038 \r
1039 \r
1040 \r
1041 \r
1042 \r
1043 METHODDEF jvirt_sarray_ptr\r
1044 \r
1045 request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,\r
1046 \r
1047                      JDIMENSION samplesperrow, JDIMENSION numrows,\r
1048 \r
1049                      JDIMENSION maxaccess)\r
1050 \r
1051 /* Request a virtual 2-D sample array */\r
1052 \r
1053 {\r
1054 \r
1055   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
1056 \r
1057   jvirt_sarray_ptr result;\r
1058 \r
1059 \r
1060 \r
1061   /* Only IMAGE-lifetime virtual arrays are currently supported */\r
1062 \r
1063   if (pool_id != JPOOL_IMAGE)\r
1064 \r
1065     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */\r
1066 \r
1067 \r
1068 \r
1069   /* get control block */\r
1070 \r
1071   result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,\r
1072 \r
1073                                           SIZEOF(struct jvirt_sarray_control));\r
1074 \r
1075 \r
1076 \r
1077   result->mem_buffer = NULL;    /* marks array not yet realized */\r
1078 \r
1079   result->rows_in_array = numrows;\r
1080 \r
1081   result->samplesperrow = samplesperrow;\r
1082 \r
1083   result->maxaccess = maxaccess;\r
1084 \r
1085   result->pre_zero = pre_zero;\r
1086 \r
1087   result->b_s_open = FALSE;     /* no associated backing-store object */\r
1088 \r
1089   result->next = mem->virt_sarray_list; /* add to list of virtual arrays */\r
1090 \r
1091   mem->virt_sarray_list = result;\r
1092 \r
1093 \r
1094 \r
1095   return result;\r
1096 \r
1097 }\r
1098 \r
1099 \r
1100 \r
1101 \r
1102 \r
1103 METHODDEF jvirt_barray_ptr\r
1104 \r
1105 request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,\r
1106 \r
1107                      JDIMENSION blocksperrow, JDIMENSION numrows,\r
1108 \r
1109                      JDIMENSION maxaccess)\r
1110 \r
1111 /* Request a virtual 2-D coefficient-block array */\r
1112 \r
1113 {\r
1114 \r
1115   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
1116 \r
1117   jvirt_barray_ptr result;\r
1118 \r
1119 \r
1120 \r
1121   /* Only IMAGE-lifetime virtual arrays are currently supported */\r
1122 \r
1123   if (pool_id != JPOOL_IMAGE)\r
1124 \r
1125     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */\r
1126 \r
1127 \r
1128 \r
1129   /* get control block */\r
1130 \r
1131   result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,\r
1132 \r
1133                                           SIZEOF(struct jvirt_barray_control));\r
1134 \r
1135 \r
1136 \r
1137   result->mem_buffer = NULL;    /* marks array not yet realized */\r
1138 \r
1139   result->rows_in_array = numrows;\r
1140 \r
1141   result->blocksperrow = blocksperrow;\r
1142 \r
1143   result->maxaccess = maxaccess;\r
1144 \r
1145   result->pre_zero = pre_zero;\r
1146 \r
1147   result->b_s_open = FALSE;     /* no associated backing-store object */\r
1148 \r
1149   result->next = mem->virt_barray_list; /* add to list of virtual arrays */\r
1150 \r
1151   mem->virt_barray_list = result;\r
1152 \r
1153 \r
1154 \r
1155   return result;\r
1156 \r
1157 }\r
1158 \r
1159 \r
1160 \r
1161 \r
1162 \r
1163 METHODDEF void\r
1164 \r
1165 realize_virt_arrays (j_common_ptr cinfo)\r
1166 \r
1167 /* Allocate the in-memory buffers for any unrealized virtual arrays */\r
1168 \r
1169 {\r
1170 \r
1171   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
1172 \r
1173   long space_per_minheight, maximum_space, avail_mem;\r
1174 \r
1175   long minheights, max_minheights;\r
1176 \r
1177   jvirt_sarray_ptr sptr;\r
1178 \r
1179   jvirt_barray_ptr bptr;\r
1180 \r
1181 \r
1182 \r
1183   /* Compute the minimum space needed (maxaccess rows in each buffer)\r
1184 \r
1185    * and the maximum space needed (full image height in each buffer).\r
1186 \r
1187    * These may be of use to the system-dependent jpeg_mem_available routine.\r
1188 \r
1189    */\r
1190 \r
1191   space_per_minheight = 0;\r
1192 \r
1193   maximum_space = 0;\r
1194 \r
1195   for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {\r
1196 \r
1197     if (sptr->mem_buffer == NULL) { /* if not realized yet */\r
1198 \r
1199       space_per_minheight += (long) sptr->maxaccess *\r
1200 \r
1201                              (long) sptr->samplesperrow * SIZEOF(JSAMPLE);\r
1202 \r
1203       maximum_space += (long) sptr->rows_in_array *\r
1204 \r
1205                        (long) sptr->samplesperrow * SIZEOF(JSAMPLE);\r
1206 \r
1207     }\r
1208 \r
1209   }\r
1210 \r
1211   for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {\r
1212 \r
1213     if (bptr->mem_buffer == NULL) { /* if not realized yet */\r
1214 \r
1215       space_per_minheight += (long) bptr->maxaccess *\r
1216 \r
1217                              (long) bptr->blocksperrow * SIZEOF(JBLOCK);\r
1218 \r
1219       maximum_space += (long) bptr->rows_in_array *\r
1220 \r
1221                        (long) bptr->blocksperrow * SIZEOF(JBLOCK);\r
1222 \r
1223     }\r
1224 \r
1225   }\r
1226 \r
1227 \r
1228 \r
1229   if (space_per_minheight <= 0)\r
1230 \r
1231     return;                     /* no unrealized arrays, no work */\r
1232 \r
1233 \r
1234 \r
1235   /* Determine amount of memory to actually use; this is system-dependent. */\r
1236 \r
1237   avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,\r
1238 \r
1239                                  mem->total_space_allocated);\r
1240 \r
1241 \r
1242 \r
1243   /* If the maximum space needed is available, make all the buffers full\r
1244 \r
1245    * height; otherwise parcel it out with the same number of minheights\r
1246 \r
1247    * in each buffer.\r
1248 \r
1249    */\r
1250 \r
1251   if (avail_mem >= maximum_space)\r
1252 \r
1253     max_minheights = 1000000000L;\r
1254 \r
1255   else {\r
1256 \r
1257     max_minheights = avail_mem / space_per_minheight;\r
1258 \r
1259     /* If there doesn't seem to be enough space, try to get the minimum\r
1260 \r
1261      * anyway.  This allows a "stub" implementation of jpeg_mem_available().\r
1262 \r
1263      */\r
1264 \r
1265     if (max_minheights <= 0)\r
1266 \r
1267       max_minheights = 1;\r
1268 \r
1269   }\r
1270 \r
1271 \r
1272 \r
1273   /* Allocate the in-memory buffers and initialize backing store as needed. */\r
1274 \r
1275 \r
1276 \r
1277   for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {\r
1278 \r
1279     if (sptr->mem_buffer == NULL) { /* if not realized yet */\r
1280 \r
1281       minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;\r
1282 \r
1283       if (minheights <= max_minheights) {\r
1284 \r
1285         /* This buffer fits in memory */\r
1286 \r
1287         sptr->rows_in_mem = sptr->rows_in_array;\r
1288 \r
1289       } else {\r
1290 \r
1291         /* It doesn't fit in memory, create backing store. */\r
1292 \r
1293         sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);\r
1294 \r
1295         jpeg_open_backing_store(cinfo, & sptr->b_s_info,\r
1296 \r
1297                                 (long) sptr->rows_in_array *\r
1298 \r
1299                                 (long) sptr->samplesperrow *\r
1300 \r
1301                                 (long) SIZEOF(JSAMPLE));\r
1302 \r
1303         sptr->b_s_open = TRUE;\r
1304 \r
1305       }\r
1306 \r
1307       sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,\r
1308 \r
1309                                       sptr->samplesperrow, sptr->rows_in_mem);\r
1310 \r
1311       sptr->rowsperchunk = mem->last_rowsperchunk;\r
1312 \r
1313       sptr->cur_start_row = 0;\r
1314 \r
1315       sptr->first_undef_row = 0;\r
1316 \r
1317       sptr->dirty = FALSE;\r
1318 \r
1319     }\r
1320 \r
1321   }\r
1322 \r
1323 \r
1324 \r
1325   for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {\r
1326 \r
1327     if (bptr->mem_buffer == NULL) { /* if not realized yet */\r
1328 \r
1329       minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;\r
1330 \r
1331       if (minheights <= max_minheights) {\r
1332 \r
1333         /* This buffer fits in memory */\r
1334 \r
1335         bptr->rows_in_mem = bptr->rows_in_array;\r
1336 \r
1337       } else {\r
1338 \r
1339         /* It doesn't fit in memory, create backing store. */\r
1340 \r
1341         bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);\r
1342 \r
1343         jpeg_open_backing_store(cinfo, & bptr->b_s_info,\r
1344 \r
1345                                 (long) bptr->rows_in_array *\r
1346 \r
1347                                 (long) bptr->blocksperrow *\r
1348 \r
1349                                 (long) SIZEOF(JBLOCK));\r
1350 \r
1351         bptr->b_s_open = TRUE;\r
1352 \r
1353       }\r
1354 \r
1355       bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,\r
1356 \r
1357                                       bptr->blocksperrow, bptr->rows_in_mem);\r
1358 \r
1359       bptr->rowsperchunk = mem->last_rowsperchunk;\r
1360 \r
1361       bptr->cur_start_row = 0;\r
1362 \r
1363       bptr->first_undef_row = 0;\r
1364 \r
1365       bptr->dirty = FALSE;\r
1366 \r
1367     }\r
1368 \r
1369   }\r
1370 \r
1371 }\r
1372 \r
1373 \r
1374 \r
1375 \r
1376 \r
1377 LOCAL void\r
1378 \r
1379 do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)\r
1380 \r
1381 /* Do backing store read or write of a virtual sample array */\r
1382 \r
1383 {\r
1384 \r
1385   long bytesperrow, file_offset, byte_count, rows, thisrow, i;\r
1386 \r
1387 \r
1388 \r
1389   bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);\r
1390 \r
1391   file_offset = ptr->cur_start_row * bytesperrow;\r
1392 \r
1393   /* Loop to read or write each allocation chunk in mem_buffer */\r
1394 \r
1395   for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {\r
1396 \r
1397     /* One chunk, but check for short chunk at end of buffer */\r
1398 \r
1399     rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);\r
1400 \r
1401     /* Transfer no more than is currently defined */\r
1402 \r
1403     thisrow = (long) ptr->cur_start_row + i;\r
1404 \r
1405     rows = MIN(rows, (long) ptr->first_undef_row - thisrow);\r
1406 \r
1407     /* Transfer no more than fits in file */\r
1408 \r
1409     rows = MIN(rows, (long) ptr->rows_in_array - thisrow);\r
1410 \r
1411     if (rows <= 0)              /* this chunk might be past end of file! */\r
1412 \r
1413       break;\r
1414 \r
1415     byte_count = rows * bytesperrow;\r
1416 \r
1417     if (writing)\r
1418 \r
1419       (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,\r
1420 \r
1421                                             (void FAR *) ptr->mem_buffer[i],\r
1422 \r
1423                                             file_offset, byte_count);\r
1424 \r
1425     else\r
1426 \r
1427       (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,\r
1428 \r
1429                                            (void FAR *) ptr->mem_buffer[i],\r
1430 \r
1431                                            file_offset, byte_count);\r
1432 \r
1433     file_offset += byte_count;\r
1434 \r
1435   }\r
1436 \r
1437 }\r
1438 \r
1439 \r
1440 \r
1441 \r
1442 \r
1443 LOCAL void\r
1444 \r
1445 do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)\r
1446 \r
1447 /* Do backing store read or write of a virtual coefficient-block array */\r
1448 \r
1449 {\r
1450 \r
1451   long bytesperrow, file_offset, byte_count, rows, thisrow, i;\r
1452 \r
1453 \r
1454 \r
1455   bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);\r
1456 \r
1457   file_offset = ptr->cur_start_row * bytesperrow;\r
1458 \r
1459   /* Loop to read or write each allocation chunk in mem_buffer */\r
1460 \r
1461   for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {\r
1462 \r
1463     /* One chunk, but check for short chunk at end of buffer */\r
1464 \r
1465     rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);\r
1466 \r
1467     /* Transfer no more than is currently defined */\r
1468 \r
1469     thisrow = (long) ptr->cur_start_row + i;\r
1470 \r
1471     rows = MIN(rows, (long) ptr->first_undef_row - thisrow);\r
1472 \r
1473     /* Transfer no more than fits in file */\r
1474 \r
1475     rows = MIN(rows, (long) ptr->rows_in_array - thisrow);\r
1476 \r
1477     if (rows <= 0)              /* this chunk might be past end of file! */\r
1478 \r
1479       break;\r
1480 \r
1481     byte_count = rows * bytesperrow;\r
1482 \r
1483     if (writing)\r
1484 \r
1485       (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,\r
1486 \r
1487                                             (void FAR *) ptr->mem_buffer[i],\r
1488 \r
1489                                             file_offset, byte_count);\r
1490 \r
1491     else\r
1492 \r
1493       (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,\r
1494 \r
1495                                            (void FAR *) ptr->mem_buffer[i],\r
1496 \r
1497                                            file_offset, byte_count);\r
1498 \r
1499     file_offset += byte_count;\r
1500 \r
1501   }\r
1502 \r
1503 }\r
1504 \r
1505 \r
1506 \r
1507 \r
1508 \r
1509 METHODDEF JSAMPARRAY\r
1510 \r
1511 access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,\r
1512 \r
1513                     JDIMENSION start_row, JDIMENSION num_rows,\r
1514 \r
1515                     boolean writable)\r
1516 \r
1517 /* Access the part of a virtual sample array starting at start_row */\r
1518 \r
1519 /* and extending for num_rows rows.  writable is true if  */\r
1520 \r
1521 /* caller intends to modify the accessed area. */\r
1522 \r
1523 {\r
1524 \r
1525   JDIMENSION end_row = start_row + num_rows;\r
1526 \r
1527   JDIMENSION undef_row;\r
1528 \r
1529 \r
1530 \r
1531   /* debugging check */\r
1532 \r
1533   if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||\r
1534 \r
1535       ptr->mem_buffer == NULL)\r
1536 \r
1537     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\r
1538 \r
1539 \r
1540 \r
1541   /* Make the desired part of the virtual array accessible */\r
1542 \r
1543   if (start_row < ptr->cur_start_row ||\r
1544 \r
1545       end_row > ptr->cur_start_row+ptr->rows_in_mem) {\r
1546 \r
1547     if (! ptr->b_s_open)\r
1548 \r
1549       ERREXIT(cinfo, JERR_VIRTUAL_BUG);\r
1550 \r
1551     /* Flush old buffer contents if necessary */\r
1552 \r
1553     if (ptr->dirty) {\r
1554 \r
1555       do_sarray_io(cinfo, ptr, TRUE);\r
1556 \r
1557       ptr->dirty = FALSE;\r
1558 \r
1559     }\r
1560 \r
1561     /* Decide what part of virtual array to access.\r
1562 \r
1563      * Algorithm: if target address > current window, assume forward scan,\r
1564 \r
1565      * load starting at target address.  If target address < current window,\r
1566 \r
1567      * assume backward scan, load so that target area is top of window.\r
1568 \r
1569      * Note that when switching from forward write to forward read, will have\r
1570 \r
1571      * start_row = 0, so the limiting case applies and we load from 0 anyway.\r
1572 \r
1573      */\r
1574 \r
1575     if (start_row > ptr->cur_start_row) {\r
1576 \r
1577       ptr->cur_start_row = start_row;\r
1578 \r
1579     } else {\r
1580 \r
1581       /* use long arithmetic here to avoid overflow & unsigned problems */\r
1582 \r
1583       long ltemp;\r
1584 \r
1585 \r
1586 \r
1587       ltemp = (long) end_row - (long) ptr->rows_in_mem;\r
1588 \r
1589       if (ltemp < 0)\r
1590 \r
1591         ltemp = 0;              /* don't fall off front end of file */\r
1592 \r
1593       ptr->cur_start_row = (JDIMENSION) ltemp;\r
1594 \r
1595     }\r
1596 \r
1597     /* Read in the selected part of the array.\r
1598 \r
1599      * During the initial write pass, we will do no actual read\r
1600 \r
1601      * because the selected part is all undefined.\r
1602 \r
1603      */\r
1604 \r
1605     do_sarray_io(cinfo, ptr, FALSE);\r
1606 \r
1607   }\r
1608 \r
1609   /* Ensure the accessed part of the array is defined; prezero if needed.\r
1610 \r
1611    * To improve locality of access, we only prezero the part of the array\r
1612 \r
1613    * that the caller is about to access, not the entire in-memory array.\r
1614 \r
1615    */\r
1616 \r
1617   if (ptr->first_undef_row < end_row) {\r
1618 \r
1619     if (ptr->first_undef_row < start_row) {\r
1620 \r
1621       if (writable)             /* writer skipped over a section of array */\r
1622 \r
1623         ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\r
1624 \r
1625       undef_row = start_row;    /* but reader is allowed to read ahead */\r
1626 \r
1627     } else {\r
1628 \r
1629       undef_row = ptr->first_undef_row;\r
1630 \r
1631     }\r
1632 \r
1633     if (writable)\r
1634 \r
1635       ptr->first_undef_row = end_row;\r
1636 \r
1637     if (ptr->pre_zero) {\r
1638 \r
1639       size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);\r
1640 \r
1641       undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */\r
1642 \r
1643       end_row -= ptr->cur_start_row;\r
1644 \r
1645       while (undef_row < end_row) {\r
1646 \r
1647         jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);\r
1648 \r
1649         undef_row++;\r
1650 \r
1651       }\r
1652 \r
1653     } else {\r
1654 \r
1655       if (! writable)           /* reader looking at undefined data */\r
1656 \r
1657         ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\r
1658 \r
1659     }\r
1660 \r
1661   }\r
1662 \r
1663   /* Flag the buffer dirty if caller will write in it */\r
1664 \r
1665   if (writable)\r
1666 \r
1667     ptr->dirty = TRUE;\r
1668 \r
1669   /* Return address of proper part of the buffer */\r
1670 \r
1671   return ptr->mem_buffer + (start_row - ptr->cur_start_row);\r
1672 \r
1673 }\r
1674 \r
1675 \r
1676 \r
1677 \r
1678 \r
1679 METHODDEF JBLOCKARRAY\r
1680 \r
1681 access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,\r
1682 \r
1683                     JDIMENSION start_row, JDIMENSION num_rows,\r
1684 \r
1685                     boolean writable)\r
1686 \r
1687 /* Access the part of a virtual block array starting at start_row */\r
1688 \r
1689 /* and extending for num_rows rows.  writable is true if  */\r
1690 \r
1691 /* caller intends to modify the accessed area. */\r
1692 \r
1693 {\r
1694 \r
1695   JDIMENSION end_row = start_row + num_rows;\r
1696 \r
1697   JDIMENSION undef_row;\r
1698 \r
1699 \r
1700 \r
1701   /* debugging check */\r
1702 \r
1703   if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||\r
1704 \r
1705       ptr->mem_buffer == NULL)\r
1706 \r
1707     ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\r
1708 \r
1709 \r
1710 \r
1711   /* Make the desired part of the virtual array accessible */\r
1712 \r
1713   if (start_row < ptr->cur_start_row ||\r
1714 \r
1715       end_row > ptr->cur_start_row+ptr->rows_in_mem) {\r
1716 \r
1717     if (! ptr->b_s_open)\r
1718 \r
1719       ERREXIT(cinfo, JERR_VIRTUAL_BUG);\r
1720 \r
1721     /* Flush old buffer contents if necessary */\r
1722 \r
1723     if (ptr->dirty) {\r
1724 \r
1725       do_barray_io(cinfo, ptr, TRUE);\r
1726 \r
1727       ptr->dirty = FALSE;\r
1728 \r
1729     }\r
1730 \r
1731     /* Decide what part of virtual array to access.\r
1732 \r
1733      * Algorithm: if target address > current window, assume forward scan,\r
1734 \r
1735      * load starting at target address.  If target address < current window,\r
1736 \r
1737      * assume backward scan, load so that target area is top of window.\r
1738 \r
1739      * Note that when switching from forward write to forward read, will have\r
1740 \r
1741      * start_row = 0, so the limiting case applies and we load from 0 anyway.\r
1742 \r
1743      */\r
1744 \r
1745     if (start_row > ptr->cur_start_row) {\r
1746 \r
1747       ptr->cur_start_row = start_row;\r
1748 \r
1749     } else {\r
1750 \r
1751       /* use long arithmetic here to avoid overflow & unsigned problems */\r
1752 \r
1753       long ltemp;\r
1754 \r
1755 \r
1756 \r
1757       ltemp = (long) end_row - (long) ptr->rows_in_mem;\r
1758 \r
1759       if (ltemp < 0)\r
1760 \r
1761         ltemp = 0;              /* don't fall off front end of file */\r
1762 \r
1763       ptr->cur_start_row = (JDIMENSION) ltemp;\r
1764 \r
1765     }\r
1766 \r
1767     /* Read in the selected part of the array.\r
1768 \r
1769      * During the initial write pass, we will do no actual read\r
1770 \r
1771      * because the selected part is all undefined.\r
1772 \r
1773      */\r
1774 \r
1775     do_barray_io(cinfo, ptr, FALSE);\r
1776 \r
1777   }\r
1778 \r
1779   /* Ensure the accessed part of the array is defined; prezero if needed.\r
1780 \r
1781    * To improve locality of access, we only prezero the part of the array\r
1782 \r
1783    * that the caller is about to access, not the entire in-memory array.\r
1784 \r
1785    */\r
1786 \r
1787   if (ptr->first_undef_row < end_row) {\r
1788 \r
1789     if (ptr->first_undef_row < start_row) {\r
1790 \r
1791       if (writable)             /* writer skipped over a section of array */\r
1792 \r
1793         ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\r
1794 \r
1795       undef_row = start_row;    /* but reader is allowed to read ahead */\r
1796 \r
1797     } else {\r
1798 \r
1799       undef_row = ptr->first_undef_row;\r
1800 \r
1801     }\r
1802 \r
1803     if (writable)\r
1804 \r
1805       ptr->first_undef_row = end_row;\r
1806 \r
1807     if (ptr->pre_zero) {\r
1808 \r
1809       size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);\r
1810 \r
1811       undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */\r
1812 \r
1813       end_row -= ptr->cur_start_row;\r
1814 \r
1815       while (undef_row < end_row) {\r
1816 \r
1817         jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);\r
1818 \r
1819         undef_row++;\r
1820 \r
1821       }\r
1822 \r
1823     } else {\r
1824 \r
1825       if (! writable)           /* reader looking at undefined data */\r
1826 \r
1827         ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\r
1828 \r
1829     }\r
1830 \r
1831   }\r
1832 \r
1833   /* Flag the buffer dirty if caller will write in it */\r
1834 \r
1835   if (writable)\r
1836 \r
1837     ptr->dirty = TRUE;\r
1838 \r
1839   /* Return address of proper part of the buffer */\r
1840 \r
1841   return ptr->mem_buffer + (start_row - ptr->cur_start_row);\r
1842 \r
1843 }\r
1844 \r
1845 \r
1846 \r
1847 \r
1848 \r
1849 /*\r
1850 \r
1851  * Release all objects belonging to a specified pool.\r
1852 \r
1853  */\r
1854 \r
1855 \r
1856 \r
1857 METHODDEF void\r
1858 \r
1859 free_pool (j_common_ptr cinfo, int pool_id)\r
1860 \r
1861 {\r
1862 \r
1863   my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\r
1864 \r
1865   small_pool_ptr shdr_ptr;\r
1866 \r
1867   large_pool_ptr lhdr_ptr;\r
1868 \r
1869   size_t space_freed;\r
1870 \r
1871 \r
1872 \r
1873   if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)\r
1874 \r
1875     ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */\r
1876 \r
1877 \r
1878 \r
1879 #ifdef MEM_STATS\r
1880 \r
1881   if (cinfo->err->trace_level > 1)\r
1882 \r
1883     print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */\r
1884 \r
1885 #endif\r
1886 \r
1887 \r
1888 \r
1889   /* If freeing IMAGE pool, close any virtual arrays first */\r
1890 \r
1891   if (pool_id == JPOOL_IMAGE) {\r
1892 \r
1893     jvirt_sarray_ptr sptr;\r
1894 \r
1895     jvirt_barray_ptr bptr;\r
1896 \r
1897 \r
1898 \r
1899     for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {\r
1900 \r
1901       if (sptr->b_s_open) {     /* there may be no backing store */\r
1902 \r
1903         sptr->b_s_open = FALSE; /* prevent recursive close if error */\r
1904 \r
1905         (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);\r
1906 \r
1907       }\r
1908 \r
1909     }\r
1910 \r
1911     mem->virt_sarray_list = NULL;\r
1912 \r
1913     for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {\r
1914 \r
1915       if (bptr->b_s_open) {     /* there may be no backing store */\r
1916 \r
1917         bptr->b_s_open = FALSE; /* prevent recursive close if error */\r
1918 \r
1919         (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);\r
1920 \r
1921       }\r
1922 \r
1923     }\r
1924 \r
1925     mem->virt_barray_list = NULL;\r
1926 \r
1927   }\r
1928 \r
1929 \r
1930 \r
1931   /* Release large objects */\r
1932 \r
1933   lhdr_ptr = mem->large_list[pool_id];\r
1934 \r
1935   mem->large_list[pool_id] = NULL;\r
1936 \r
1937 \r
1938 \r
1939   while (lhdr_ptr != NULL) {\r
1940 \r
1941     large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;\r
1942 \r
1943     space_freed = lhdr_ptr->hdr.bytes_used +\r
1944 \r
1945                   lhdr_ptr->hdr.bytes_left +\r
1946 \r
1947                   SIZEOF(large_pool_hdr);\r
1948 \r
1949     jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);\r
1950 \r
1951     mem->total_space_allocated -= space_freed;\r
1952 \r
1953     lhdr_ptr = next_lhdr_ptr;\r
1954 \r
1955   }\r
1956 \r
1957 \r
1958 \r
1959   /* Release small objects */\r
1960 \r
1961   shdr_ptr = mem->small_list[pool_id];\r
1962 \r
1963   mem->small_list[pool_id] = NULL;\r
1964 \r
1965 \r
1966 \r
1967   while (shdr_ptr != NULL) {\r
1968 \r
1969     small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;\r
1970 \r
1971     space_freed = shdr_ptr->hdr.bytes_used +\r
1972 \r
1973                   shdr_ptr->hdr.bytes_left +\r
1974 \r
1975                   SIZEOF(small_pool_hdr);\r
1976 \r
1977     jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);\r
1978 \r
1979     mem->total_space_allocated -= space_freed;\r
1980 \r
1981     shdr_ptr = next_shdr_ptr;\r
1982 \r
1983   }\r
1984 \r
1985 }\r
1986 \r
1987 \r
1988 \r
1989 \r
1990 \r
1991 /*\r
1992 \r
1993  * Close up shop entirely.\r
1994 \r
1995  * Note that this cannot be called unless cinfo->mem is non-NULL.\r
1996 \r
1997  */\r
1998 \r
1999 \r
2000 \r
2001 METHODDEF void\r
2002 \r
2003 self_destruct (j_common_ptr cinfo)\r
2004 \r
2005 {\r
2006 \r
2007   int pool;\r
2008 \r
2009 \r
2010 \r
2011   /* Close all backing store, release all memory.\r
2012 \r
2013    * Releasing pools in reverse order might help avoid fragmentation\r
2014 \r
2015    * with some (brain-damaged) malloc libraries.\r
2016 \r
2017    */\r
2018 \r
2019   for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {\r
2020 \r
2021     free_pool(cinfo, pool);\r
2022 \r
2023   }\r
2024 \r
2025 \r
2026 \r
2027   /* Release the memory manager control block too. */\r
2028 \r
2029   jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));\r
2030 \r
2031   cinfo->mem = NULL;            /* ensures I will be called only once */\r
2032 \r
2033 \r
2034 \r
2035   jpeg_mem_term(cinfo);         /* system-dependent cleanup */\r
2036 \r
2037 }\r
2038 \r
2039 \r
2040 \r
2041 \r
2042 \r
2043 /*\r
2044 \r
2045  * Memory manager initialization.\r
2046 \r
2047  * When this is called, only the error manager pointer is valid in cinfo!\r
2048 \r
2049  */\r
2050 \r
2051 \r
2052 \r
2053 GLOBAL void\r
2054 \r
2055 jinit_memory_mgr (j_common_ptr cinfo)\r
2056 \r
2057 {\r
2058 \r
2059   my_mem_ptr mem;\r
2060 \r
2061   long max_to_use;\r
2062 \r
2063   int pool;\r
2064 \r
2065   size_t test_mac;\r
2066 \r
2067 \r
2068 \r
2069   cinfo->mem = NULL;            /* for safety if init fails */\r
2070 \r
2071 \r
2072 \r
2073   /* Check for configuration errors.\r
2074 \r
2075    * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably\r
2076 \r
2077    * doesn't reflect any real hardware alignment requirement.\r
2078 \r
2079    * The test is a little tricky: for X>0, X and X-1 have no one-bits\r
2080 \r
2081    * in common if and only if X is a power of 2, ie has only one one-bit.\r
2082 \r
2083    * Some compilers may give an "unreachable code" warning here; ignore it.\r
2084 \r
2085    */\r
2086 \r
2087   if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)\r
2088 \r
2089     ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);\r
2090 \r
2091   /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be\r
2092 \r
2093    * a multiple of SIZEOF(ALIGN_TYPE).\r
2094 \r
2095    * Again, an "unreachable code" warning may be ignored here.\r
2096 \r
2097    * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.\r
2098 \r
2099    */\r
2100 \r
2101   test_mac = (size_t) MAX_ALLOC_CHUNK;\r
2102 \r
2103   if ((long) test_mac != MAX_ALLOC_CHUNK ||\r
2104 \r
2105       (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)\r
2106 \r
2107     ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);\r
2108 \r
2109 \r
2110 \r
2111   max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */\r
2112 \r
2113 \r
2114 \r
2115   /* Attempt to allocate memory manager's control block */\r
2116 \r
2117   mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));\r
2118 \r
2119 \r
2120 \r
2121   if (mem == NULL) {\r
2122 \r
2123     jpeg_mem_term(cinfo);       /* system-dependent cleanup */\r
2124 \r
2125     ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);\r
2126 \r
2127   }\r
2128 \r
2129 \r
2130 \r
2131   /* OK, fill in the method pointers */\r
2132 \r
2133   mem->pub.alloc_small = alloc_small;\r
2134 \r
2135   mem->pub.alloc_large = alloc_large;\r
2136 \r
2137   mem->pub.alloc_sarray = alloc_sarray;\r
2138 \r
2139   mem->pub.alloc_barray = alloc_barray;\r
2140 \r
2141   mem->pub.request_virt_sarray = request_virt_sarray;\r
2142 \r
2143   mem->pub.request_virt_barray = request_virt_barray;\r
2144 \r
2145   mem->pub.realize_virt_arrays = realize_virt_arrays;\r
2146 \r
2147   mem->pub.access_virt_sarray = access_virt_sarray;\r
2148 \r
2149   mem->pub.access_virt_barray = access_virt_barray;\r
2150 \r
2151   mem->pub.free_pool = free_pool;\r
2152 \r
2153   mem->pub.self_destruct = self_destruct;\r
2154 \r
2155 \r
2156 \r
2157   /* Initialize working state */\r
2158 \r
2159   mem->pub.max_memory_to_use = max_to_use;\r
2160 \r
2161 \r
2162 \r
2163   for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {\r
2164 \r
2165     mem->small_list[pool] = NULL;\r
2166 \r
2167     mem->large_list[pool] = NULL;\r
2168 \r
2169   }\r
2170 \r
2171   mem->virt_sarray_list = NULL;\r
2172 \r
2173   mem->virt_barray_list = NULL;\r
2174 \r
2175 \r
2176 \r
2177   mem->total_space_allocated = SIZEOF(my_memory_mgr);\r
2178 \r
2179 \r
2180 \r
2181   /* Declare ourselves open for business */\r
2182 \r
2183   cinfo->mem = & mem->pub;\r
2184 \r
2185 \r
2186 \r
2187   /* Check for an environment variable JPEGMEM; if found, override the\r
2188 \r
2189    * default max_memory setting from jpeg_mem_init.  Note that the\r
2190 \r
2191    * surrounding application may again override this value.\r
2192 \r
2193    * If your system doesn't support getenv(), define NO_GETENV to disable\r
2194 \r
2195    * this feature.\r
2196 \r
2197    */\r
2198 \r
2199 #ifndef NO_GETENV\r
2200 \r
2201   { char * memenv;\r
2202 \r
2203 \r
2204 \r
2205     if ((memenv = getenv("JPEGMEM")) != NULL) {\r
2206 \r
2207       char ch = 'x';\r
2208 \r
2209 \r
2210 \r
2211       if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {\r
2212 \r
2213         if (ch == 'm' || ch == 'M')\r
2214 \r
2215           max_to_use *= 1000L;\r
2216 \r
2217         mem->pub.max_memory_to_use = max_to_use * 1000L;\r
2218 \r
2219       }\r
2220 \r
2221     }\r
2222 \r
2223   }\r
2224 \r
2225 #endif\r
2226 \r
2227 \r
2228 \r
2229 }\r
2230 \r