1 /******************************************************************************
2  *
3  * Project:  JPEG-2000
4  * Purpose:  Return a stream for a VSIL file
5  * Author:   Even Rouault, even dot rouault at spatialys.com
6  *
7  ******************************************************************************/
8 
9 /* Following code is mostly derived from jas_stream.c, which is licensed */
10 /* under the below terms */
11 
12 /*
13  * Copyright (c) 1999-2000 Image Power, Inc. and the University of
14  *   British Columbia.
15  * Copyright (c) 2001-2003 Michael David Adams.
16  * All rights reserved.
17  * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
18  */
19 
20 /* __START_OF_JASPER_LICENSE__
21  *
22  * JasPer License Version 2.0
23  *
24  * Copyright (c) 2001-2006 Michael David Adams
25  * Copyright (c) 1999-2000 Image Power, Inc.
26  * Copyright (c) 1999-2000 The University of British Columbia
27  *
28  * All rights reserved.
29  *
30  * Permission is hereby granted, free of charge, to any person (the
31  * "User") obtaining a copy of this software and associated documentation
32  * files (the "Software"), to deal in the Software without restriction,
33  * including without limitation the rights to use, copy, modify, merge,
34  * publish, distribute, and/or sell copies of the Software, and to permit
35  * persons to whom the Software is furnished to do so, subject to the
36  * following conditions:
37  *
38  * 1.  The above copyright notices and this permission notice (which
39  * includes the disclaimer below) shall be included in all copies or
40  * substantial portions of the Software.
41  *
42  * 2.  The name of a copyright holder shall not be used to endorse or
43  * promote products derived from the Software without specific prior
44  * written permission.
45  *
46  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
47  * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
48  * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
49  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
50  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
51  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
52  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
53  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
54  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
55  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
56  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
57  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
58  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
59  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
60  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
61  * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
62  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
63  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
64  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
65  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
66  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
67  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
68  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
69  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
70  * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
71  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
72  *
73  * __END_OF_JASPER_LICENSE__
74  */
75 
76 #ifndef __STDC_LIMIT_MACROS
77 // Needed on RHEL 6 for SIZE_MAX availability, needed by Jasper
78 #define __STDC_LIMIT_MACROS 1
79 #endif
80 
81 #include "jpeg2000_vsil_io.h"
82 #include "cpl_vsi.h"
83 
84 CPL_CVSID("$Id: jpeg2000_vsil_io.cpp 9ef8e16e27c5fc4c491debe50bf2b7f3e94ed334 2020-10-05 12:11:52 +0200 Even Rouault $")
85 
86 /*
87  * File descriptor file object.
88  */
89 typedef struct {
90     VSILFILE* fp;
91 } jas_stream_VSIFL_t;
92 
93 /******************************************************************************\
94 * File stream object.
95 \******************************************************************************/
96 
97 #if defined(PRIjas_seqent)
98 // PRIjas_seqent macro is defined since Jasper 2.0.17
JPEG2000_VSIL_read(jas_stream_obj_t * obj,char * buf,unsigned cnt)99 static int JPEG2000_VSIL_read(jas_stream_obj_t *obj, char *buf, unsigned cnt)
100 #else
101 static int JPEG2000_VSIL_read(jas_stream_obj_t *obj, char *buf, int cnt)
102 #endif
103 {
104     jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj);
105     return static_cast<int>(VSIFReadL(buf, 1, cnt, fileobj->fp));
106 }
107 
108 #if defined(JAS_INCLUDE_JP2_CODEC)
109 // Jasper 2.0.21
JPEG2000_VSIL_write(jas_stream_obj_t * obj,const char * buf,unsigned int cnt)110 static int JPEG2000_VSIL_write(jas_stream_obj_t *obj, const char *buf, unsigned int cnt)
111 #elif defined(PRIjas_seqent)
112 static int JPEG2000_VSIL_write(jas_stream_obj_t *obj, char *buf, unsigned int cnt)
113 #else
114 static int JPEG2000_VSIL_write(jas_stream_obj_t *obj, char *buf, int cnt)
115 #endif
116 {
117     jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj);
118     return static_cast<int>(VSIFWriteL(buf, 1, cnt, fileobj->fp));
119 }
120 
JPEG2000_VSIL_seek(jas_stream_obj_t * obj,long offset,int origin)121 static long JPEG2000_VSIL_seek(jas_stream_obj_t *obj, long offset, int origin)
122 {
123     jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj);
124     if (offset < 0 && origin == SEEK_CUR)
125     {
126         origin = SEEK_SET;
127         offset += VSIFTellL(fileobj->fp);
128     }
129     else if (offset < 0 && origin == SEEK_END)
130     {
131         origin = SEEK_SET;
132         VSIFSeekL(fileobj->fp, 0, SEEK_END);
133         offset += VSIFTellL(fileobj->fp);
134     }
135     VSIFSeekL(fileobj->fp, offset, origin);
136     return VSIFTellL(fileobj->fp);
137 }
138 
JPEG2000_VSIL_close(jas_stream_obj_t * obj)139 static int JPEG2000_VSIL_close(jas_stream_obj_t *obj)
140 {
141     jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj);
142     if( fileobj->fp != nullptr )
143     {
144         VSIFCloseL(fileobj->fp);
145         fileobj->fp = nullptr;
146     }
147     jas_free(fileobj);
148     return 0;
149 }
150 
151 static const jas_stream_ops_t JPEG2000_VSIL_stream_fileops = {
152     JPEG2000_VSIL_read,
153     JPEG2000_VSIL_write,
154     JPEG2000_VSIL_seek,
155     JPEG2000_VSIL_close
156 };
157 
158 /******************************************************************************\
159 * Code for opening and closing streams.
160 \******************************************************************************/
161 
JPEG2000_VSIL_jas_stream_create()162 static jas_stream_t *JPEG2000_VSIL_jas_stream_create()
163 {
164     jas_stream_t *stream;
165 
166     if (!(stream = (jas_stream_t*) jas_malloc(sizeof(jas_stream_t)))) {
167         return nullptr;
168     }
169     stream->openmode_ = 0;
170     stream->bufmode_ = 0;
171     stream->flags_ = 0;
172     stream->bufbase_ = nullptr;
173     stream->bufstart_ = nullptr;
174     stream->bufsize_ = 0;
175     stream->ptr_ = nullptr;
176     stream->cnt_ = 0;
177     stream->ops_ = nullptr;
178     stream->obj_ = nullptr;
179     stream->rwcnt_ = 0;
180     stream->rwlimit_ = -1;
181 
182     return stream;
183 }
184 
JPEG2000_VSIL_jas_stream_destroy(jas_stream_t * stream)185 static void JPEG2000_VSIL_jas_stream_destroy(jas_stream_t *stream)
186 {
187     /* If the memory for the buffer was allocated with malloc, free
188        this memory. */
189     if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) {
190         jas_free(stream->bufbase_);
191         stream->bufbase_ = nullptr;
192     }
193     jas_free(stream);
194 }
195 
196 /******************************************************************************\
197 * Buffer initialization code.
198 \******************************************************************************/
199 
JPEG2000_VSIL_jas_stream_initbuf(jas_stream_t * stream,int bufmode,char * buf,int bufsize)200 static void JPEG2000_VSIL_jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
201   int bufsize)
202 {
203     /* If this function is being called, the buffer should not have been
204        initialized yet. */
205     assert(!stream->bufbase_);
206 
207     if (bufmode != JAS_STREAM_UNBUF) {
208         /* The full- or line-buffered mode is being employed. */
209         if (!buf) {
210             /* The caller has not specified a buffer to employ, so allocate
211                one. */
212             if ((stream->bufbase_ = (unsigned char*)jas_malloc(JAS_STREAM_BUFSIZE +
213                                                                JAS_STREAM_MAXPUTBACK))) {
214                 stream->bufmode_ |= JAS_STREAM_FREEBUF;
215                 stream->bufsize_ = JAS_STREAM_BUFSIZE;
216             } else {
217                 /* The buffer allocation has failed.  Resort to unbuffered
218                    operation. */
219                 stream->bufbase_ = stream->tinybuf_;
220                 stream->bufsize_ = 1;
221             }
222         } else {
223             /* The caller has specified a buffer to employ. */
224             /* The buffer must be large enough to accommodate maximum
225                putback. */
226             assert(bufsize > JAS_STREAM_MAXPUTBACK);
227             stream->bufbase_ = JAS_CAST(unsigned char *, buf);
228             stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
229         }
230     } else {
231         /* The unbuffered mode is being employed. */
232         /* A buffer should not have been supplied by the caller. */
233         assert(!buf);
234         /* Use a trivial one-character buffer. */
235         stream->bufbase_ = stream->tinybuf_;
236         stream->bufsize_ = 1;
237     }
238     stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
239     stream->ptr_ = stream->bufstart_;
240     stream->cnt_ = 0;
241     stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
242 }
243 
JPEG2000_VSIL_jas_strtoopenmode(const char * s)244 static int JPEG2000_VSIL_jas_strtoopenmode(const char *s)
245 {
246     int openmode = 0;
247     while (*s != '\0') {
248         switch (*s) {
249           case 'r':
250               openmode |= JAS_STREAM_READ;
251               break;
252           case 'w':
253               openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE;
254               break;
255           case 'b':
256               openmode |= JAS_STREAM_BINARY;
257               break;
258           case 'a':
259               openmode |= JAS_STREAM_APPEND;
260               break;
261           case '+':
262               openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE;
263               break;
264           default:
265               break;
266         }
267         ++s;
268     }
269     return openmode;
270 }
271 
JPEG2000_VSIL_fopen(const char * filename,const char * mode)272 jas_stream_t *JPEG2000_VSIL_fopen(const char *filename, const char *mode)
273 {
274     jas_stream_t *stream;
275     jas_stream_VSIFL_t *obj;
276 
277     /* Allocate a stream object. */
278     if (!(stream = JPEG2000_VSIL_jas_stream_create())) {
279         return nullptr;
280     }
281 
282     /* Parse the mode string. */
283     stream->openmode_ = JPEG2000_VSIL_jas_strtoopenmode(mode);
284 
285     /* Allocate space for the underlying file stream object. */
286     if (!(obj = (jas_stream_VSIFL_t*) jas_malloc(sizeof(jas_stream_VSIFL_t)))) {
287         JPEG2000_VSIL_jas_stream_destroy(stream);
288         return nullptr;
289     }
290     obj->fp = nullptr;
291     stream->obj_ = (void *) obj;
292 
293     /* Select the operations for a file stream object. */
294     stream->ops_ = const_cast<jas_stream_ops_t*> (&JPEG2000_VSIL_stream_fileops);
295 
296     /* Open the underlying file. */
297     if ((obj->fp = VSIFOpenL(filename, mode)) == nullptr) {
298         jas_stream_close(stream);
299         return nullptr;
300     }
301 
302     /* By default, use full buffering for this type of stream. */
303     JPEG2000_VSIL_jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, nullptr, 0);
304 
305     return stream;
306 }
307