@@ -150,6 +150,11 @@ static avifBool isAvifError(avifResult result, const char *msg) {
150150}
151151
152152
153+ typedef struct avifIOCtxReader {
154+ avifIO io ; // this must be the first member for easy casting to avifIO*
155+ avifROData rodata ;
156+ } avifIOCtxReader ;
157+
153158/*
154159 <readfromCtx> implements the avifIOReadFunc interface by calling the relevant functions
155160 in the gdIOCtx. Our logic is inspired by avifIOMemoryReaderRead() and avifIOFileReaderRead().
@@ -165,8 +170,8 @@ static avifBool isAvifError(avifResult result, const char *msg) {
165170*/
166171static avifResult readFromCtx (avifIO * io , uint32_t readFlags , uint64_t offset , size_t size , avifROData * out )
167172{
168- void * dataBuf = NULL ;
169173 gdIOCtx * ctx = (gdIOCtx * ) io -> data ;
174+ avifIOCtxReader * reader = (avifIOCtxReader * ) io ;
170175
171176 // readFlags is unsupported
172177 if (readFlags != 0 ) {
@@ -182,28 +187,34 @@ static avifResult readFromCtx(avifIO *io, uint32_t readFlags, uint64_t offset, s
182187 if (!ctx -> seek (ctx , (int ) offset ))
183188 return AVIF_RESULT_IO_ERROR ;
184189
185- dataBuf = avifAlloc (size );
186- if (!dataBuf ) {
190+ if (size > reader -> rodata .size ) {
191+ reader -> rodata .data = gdRealloc ((void * ) reader -> rodata .data , size );
192+ reader -> rodata .size = size ;
193+ }
194+ if (!reader -> rodata .data ) {
187195 gd_error ("avif error - couldn't allocate memory" );
188196 return AVIF_RESULT_UNKNOWN_ERROR ;
189197 }
190198
191199 // Read the number of bytes requested.
192200 // If getBuf() returns a negative value, that means there was an error.
193- int charsRead = ctx -> getBuf (ctx , dataBuf , (int ) size );
201+ int charsRead = ctx -> getBuf (ctx , ( void * ) reader -> rodata . data , (int ) size );
194202 if (charsRead < 0 ) {
195- avifFree (dataBuf );
196203 return AVIF_RESULT_IO_ERROR ;
197204 }
198205
199- out -> data = dataBuf ;
206+ out -> data = reader -> rodata . data ;
200207 out -> size = charsRead ;
201208 return AVIF_RESULT_OK ;
202209}
203210
204211// avif.h says this is optional, but it seemed easy to implement.
205212static void destroyAvifIO (struct avifIO * io ) {
206- gdFree (io );
213+ avifIOCtxReader * reader = (avifIOCtxReader * ) io ;
214+ if (reader -> rodata .data != NULL ) {
215+ gdFree ((void * ) reader -> rodata .data );
216+ }
217+ gdFree (reader );
207218}
208219
209220/* Set up an avifIO object.
@@ -217,21 +228,23 @@ static void destroyAvifIO(struct avifIO *io) {
217228
218229// TODO: can we get sizeHint somehow?
219230static avifIO * createAvifIOFromCtx (gdIOCtx * ctx ) {
220- avifIO * io ;
231+ struct avifIOCtxReader * reader ;
221232
222- io = gdMalloc (sizeof (* io ));
223- if (io == NULL )
233+ reader = gdMalloc (sizeof (* reader ));
234+ if (reader == NULL )
224235 return NULL ;
225236
226237 // TODO: setting persistent=FALSE is safe, but it's less efficient. Is it necessary?
227- io -> persistent = AVIF_FALSE ;
228- io -> read = readFromCtx ;
229- io -> write = NULL ; // this function is currently unused; see avif.h
230- io -> destroy = destroyAvifIO ;
231- io -> sizeHint = 0 ; // sadly, we don't get this information from the gdIOCtx.
232- io -> data = ctx ;
233-
234- return io ;
238+ reader -> io .persistent = AVIF_FALSE ;
239+ reader -> io .read = readFromCtx ;
240+ reader -> io .write = NULL ; // this function is currently unused; see avif.h
241+ reader -> io .destroy = destroyAvifIO ;
242+ reader -> io .sizeHint = 0 ; // sadly, we don't get this information from the gdIOCtx.
243+ reader -> io .data = ctx ;
244+ reader -> rodata .data = NULL ;
245+ reader -> rodata .size = 0 ;
246+
247+ return (avifIO * ) reader ;
235248}
236249
237250
@@ -576,6 +589,9 @@ void gdImageAvifCtx(gdImagePtr im, gdIOCtx *outfile, int quality, int speed)
576589
577590 if (avifOutput .data )
578591 avifRWDataFree (& avifOutput );
592+
593+ if (avifIm )
594+ avifImageDestroy (avifIm );
579595}
580596
581597void gdImageAvifEx (gdImagePtr im , FILE * outFile , int quality , int speed )
0 commit comments