/src/libjpeg-turbo.2.1.x/jdatadst-tj.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * jdatadst-tj.c  | 
3  |  |  *  | 
4  |  |  * This file was part of the Independent JPEG Group's software:  | 
5  |  |  * Copyright (C) 1994-1996, Thomas G. Lane.  | 
6  |  |  * Modified 2009-2012 by Guido Vollbeding.  | 
7  |  |  * libjpeg-turbo Modifications:  | 
8  |  |  * Copyright (C) 2011, 2014, 2016, 2019, 2022, D. R. Commander.  | 
9  |  |  * For conditions of distribution and use, see the accompanying README.ijg  | 
10  |  |  * file.  | 
11  |  |  *  | 
12  |  |  * This file contains compression data destination routines for the case of  | 
13  |  |  * emitting JPEG data to memory or to a file (or any stdio stream).  | 
14  |  |  * While these routines are sufficient for most applications,  | 
15  |  |  * some will want to use a different destination manager.  | 
16  |  |  * IMPORTANT: we assume that fwrite() will correctly transcribe an array of  | 
17  |  |  * JOCTETs into 8-bit-wide elements on external storage.  If char is wider  | 
18  |  |  * than 8 bits on your machine, you may need to do some tweaking.  | 
19  |  |  */  | 
20  |  |  | 
21  |  | /* this is not a core library module, so it doesn't define JPEG_INTERNALS */  | 
22  |  | #include "jinclude.h"  | 
23  |  | #include "jpeglib.h"  | 
24  |  | #include "jerror.h"  | 
25  |  |  | 
26  |  | void jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,  | 
27  |  |                       unsigned long *outsize, boolean alloc);  | 
28  |  |  | 
29  |  |  | 
30  | 34.5k  | #define OUTPUT_BUF_SIZE  4096   /* choose an efficiently fwrite'able size */  | 
31  |  |  | 
32  |  |  | 
33  |  | /* Expanded data destination object for memory output */  | 
34  |  |  | 
35  |  | typedef struct { | 
36  |  |   struct jpeg_destination_mgr pub; /* public fields */  | 
37  |  |  | 
38  |  |   unsigned char **outbuffer;    /* target buffer */  | 
39  |  |   unsigned long *outsize;  | 
40  |  |   unsigned char *newbuffer;     /* newly allocated buffer */  | 
41  |  |   JOCTET *buffer;               /* start of buffer */  | 
42  |  |   size_t bufsize;  | 
43  |  |   boolean alloc;  | 
44  |  | } my_mem_destination_mgr;  | 
45  |  |  | 
46  |  | typedef my_mem_destination_mgr *my_mem_dest_ptr;  | 
47  |  |  | 
48  |  |  | 
49  |  | /*  | 
50  |  |  * Initialize destination --- called by jpeg_start_compress  | 
51  |  |  * before any data is actually written.  | 
52  |  |  */  | 
53  |  |  | 
54  |  | METHODDEF(void)  | 
55  |  | init_mem_destination(j_compress_ptr cinfo)  | 
56  | 110k  | { | 
57  |  |   /* no work necessary here */  | 
58  | 110k  | }  | 
59  |  |  | 
60  |  |  | 
61  |  | /*  | 
62  |  |  * Empty the output buffer --- called whenever buffer fills up.  | 
63  |  |  *  | 
64  |  |  * In typical applications, this should write the entire output buffer  | 
65  |  |  * (ignoring the current state of next_output_byte & free_in_buffer),  | 
66  |  |  * reset the pointer & count to the start of the buffer, and return TRUE  | 
67  |  |  * indicating that the buffer has been dumped.  | 
68  |  |  *  | 
69  |  |  * In applications that need to be able to suspend compression due to output  | 
70  |  |  * overrun, a FALSE return indicates that the buffer cannot be emptied now.  | 
71  |  |  * In this situation, the compressor will return to its caller (possibly with  | 
72  |  |  * an indication that it has not accepted all the supplied scanlines).  The  | 
73  |  |  * application should resume compression after it has made more room in the  | 
74  |  |  * output buffer.  Note that there are substantial restrictions on the use of  | 
75  |  |  * suspension --- see the documentation.  | 
76  |  |  *  | 
77  |  |  * When suspending, the compressor will back up to a convenient restart point  | 
78  |  |  * (typically the start of the current MCU). next_output_byte & free_in_buffer  | 
79  |  |  * indicate where the restart point will be if the current call returns FALSE.  | 
80  |  |  * Data beyond this point will be regenerated after resumption, so do not  | 
81  |  |  * write it out when emptying the buffer externally.  | 
82  |  |  */  | 
83  |  |  | 
84  |  | METHODDEF(boolean)  | 
85  |  | empty_mem_output_buffer(j_compress_ptr cinfo)  | 
86  | 10.8k  | { | 
87  | 10.8k  |   size_t nextsize;  | 
88  | 10.8k  |   JOCTET *nextbuffer;  | 
89  | 10.8k  |   my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;  | 
90  |  |  | 
91  | 10.8k  |   if (!dest->alloc) ERREXIT(cinfo, JERR_BUFFER_SIZE);  | 
92  |  |  | 
93  |  |   /* Try to allocate new buffer with double size */  | 
94  | 10.8k  |   nextsize = dest->bufsize * 2;  | 
95  | 10.8k  |   nextbuffer = (JOCTET *)malloc(nextsize);  | 
96  |  |  | 
97  | 10.8k  |   if (nextbuffer == NULL)  | 
98  | 0  |     ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);  | 
99  |  |  | 
100  | 10.8k  |   memcpy(nextbuffer, dest->buffer, dest->bufsize);  | 
101  |  |  | 
102  | 10.8k  |   free(dest->newbuffer);  | 
103  |  |  | 
104  | 10.8k  |   dest->newbuffer = nextbuffer;  | 
105  |  |  | 
106  | 10.8k  |   dest->pub.next_output_byte = nextbuffer + dest->bufsize;  | 
107  | 10.8k  |   dest->pub.free_in_buffer = dest->bufsize;  | 
108  |  |  | 
109  | 10.8k  |   dest->buffer = nextbuffer;  | 
110  | 10.8k  |   dest->bufsize = nextsize;  | 
111  |  |  | 
112  | 10.8k  |   return TRUE;  | 
113  | 10.8k  | }  | 
114  |  |  | 
115  |  |  | 
116  |  | /*  | 
117  |  |  * Terminate destination --- called by jpeg_finish_compress  | 
118  |  |  * after all data has been written.  Usually needs to flush buffer.  | 
119  |  |  *  | 
120  |  |  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding  | 
121  |  |  * application must deal with any cleanup that should happen even  | 
122  |  |  * for error exit.  | 
123  |  |  */  | 
124  |  |  | 
125  |  | METHODDEF(void)  | 
126  |  | term_mem_destination(j_compress_ptr cinfo)  | 
127  | 109k  | { | 
128  | 109k  |   my_mem_dest_ptr dest = (my_mem_dest_ptr)cinfo->dest;  | 
129  |  |  | 
130  | 109k  |   if (dest->alloc) *dest->outbuffer = dest->buffer;  | 
131  | 109k  |   *dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);  | 
132  | 109k  | }  | 
133  |  |  | 
134  |  |  | 
135  |  | /*  | 
136  |  |  * Prepare for output to a memory buffer.  | 
137  |  |  * The caller may supply an own initial buffer with appropriate size.  | 
138  |  |  * Otherwise, or when the actual data output exceeds the given size,  | 
139  |  |  * the library adapts the buffer size as necessary.  | 
140  |  |  * The standard library functions malloc/free are used for allocating  | 
141  |  |  * larger memory, so the buffer is available to the application after  | 
142  |  |  * finishing compression, and then the application is responsible for  | 
143  |  |  * freeing the requested memory.  | 
144  |  |  */  | 
145  |  |  | 
146  |  | GLOBAL(void)  | 
147  |  | jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer,  | 
148  |  |                  unsigned long *outsize, boolean alloc)  | 
149  | 356k  | { | 
150  | 356k  |   boolean reused = FALSE;  | 
151  | 356k  |   my_mem_dest_ptr dest;  | 
152  |  |  | 
153  | 356k  |   if (outbuffer == NULL || outsize == NULL)     /* sanity check */  | 
154  | 0  |     ERREXIT(cinfo, JERR_BUFFER_SIZE);  | 
155  |  |  | 
156  |  |   /* The destination object is made permanent so that multiple JPEG images  | 
157  |  |    * can be written to the same buffer without re-executing jpeg_mem_dest.  | 
158  |  |    */  | 
159  | 356k  |   if (cinfo->dest == NULL) {    /* first time for this JPEG object? */ | 
160  | 243k  |     cinfo->dest = (struct jpeg_destination_mgr *)  | 
161  | 243k  |       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,  | 
162  | 243k  |                                   sizeof(my_mem_destination_mgr));  | 
163  | 243k  |     dest = (my_mem_dest_ptr)cinfo->dest;  | 
164  | 243k  |     dest->newbuffer = NULL;  | 
165  | 243k  |     dest->buffer = NULL;  | 
166  | 243k  |   } else if (cinfo->dest->init_destination != init_mem_destination) { | 
167  |  |     /* It is unsafe to reuse the existing destination manager unless it was  | 
168  |  |      * created by this function.  | 
169  |  |      */  | 
170  | 0  |     ERREXIT(cinfo, JERR_BUFFER_SIZE);  | 
171  | 0  |   }  | 
172  |  |  | 
173  | 356k  |   dest = (my_mem_dest_ptr)cinfo->dest;  | 
174  | 356k  |   dest->pub.init_destination = init_mem_destination;  | 
175  | 356k  |   dest->pub.empty_output_buffer = empty_mem_output_buffer;  | 
176  | 356k  |   dest->pub.term_destination = term_mem_destination;  | 
177  | 356k  |   if (dest->buffer == *outbuffer && *outbuffer != NULL && alloc)  | 
178  | 0  |     reused = TRUE;  | 
179  | 356k  |   dest->outbuffer = outbuffer;  | 
180  | 356k  |   dest->outsize = outsize;  | 
181  | 356k  |   dest->alloc = alloc;  | 
182  |  |  | 
183  | 356k  |   if (*outbuffer == NULL || *outsize == 0) { | 
184  | 17.2k  |     if (alloc) { | 
185  |  |       /* Allocate initial buffer */  | 
186  | 17.2k  |       dest->newbuffer = *outbuffer = (unsigned char *)malloc(OUTPUT_BUF_SIZE);  | 
187  | 17.2k  |       if (dest->newbuffer == NULL)  | 
188  | 0  |         ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);  | 
189  | 17.2k  |       *outsize = OUTPUT_BUF_SIZE;  | 
190  | 17.2k  |     } else  | 
191  | 0  |       ERREXIT(cinfo, JERR_BUFFER_SIZE);  | 
192  | 17.2k  |   }  | 
193  |  |  | 
194  | 356k  |   dest->pub.next_output_byte = dest->buffer = *outbuffer;  | 
195  | 356k  |   if (!reused)  | 
196  | 356k  |     dest->bufsize = *outsize;  | 
197  | 356k  |   dest->pub.free_in_buffer = dest->bufsize;  | 
198  | 356k  | }  |