From 455f675806670fb095b824a2cdb99350a63eeefc Mon Sep 17 00:00:00 2001 From: Julien Malik Date: Wed, 30 Nov 2011 16:55:25 +0000 Subject: [PATCH] [trunk] implement Large File support in the library --- CHANGES | 9 + applications/codec/index.c | 1 + libopenjpeg/cio.c | 104 ++++++------ libopenjpeg/cio.h | 42 ++--- libopenjpeg/j2k.c | 42 ++--- libopenjpeg/j2k.h | 2 +- libopenjpeg/openjpeg.c | 26 +-- libopenjpeg/openjpeg.h | 35 ++-- libopenjpeg/opj_includes.h | 2 +- tests/CMakeLists.txt | 3 + tests/j2k_random_tile_access.c | 298 +++++++++++++++++++++++++++++++++ 11 files changed, 440 insertions(+), 124 deletions(-) create mode 100644 tests/j2k_random_tile_access.c diff --git a/CHANGES b/CHANGES index bdf21386..33a592f9 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,15 @@ What's New for OpenJPEG ! : changed + : added +November 30, 2011 +* [jmalik] implement Large File support in the library : + - fix portability layer for windows (need WIN32) + - include opj_config.h before any system header (index) + - change types related to buffer size to OPJ_SIZE_T, for anything sent to memcpy, fread, fwrite + - change types related to index in stream to OPJ_OFF_T, thus resolving to a 64 bit signed integer + - change types related to size of stream to OPJ_UINT64_T + - change calls to fseek/ftell to LFS-capable OPJ_SEEK/OPJ_TELL + November 29, 2011 * [mickael] fix error with new way to detect kdu_expand diff --git a/applications/codec/index.c b/applications/codec/index.c index 27a40740..d500ce5e 100644 --- a/applications/codec/index.c +++ b/applications/codec/index.c @@ -25,6 +25,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#include "opj_config.h" #include #include diff --git a/libopenjpeg/cio.c b/libopenjpeg/cio.c index 32203a45..1628c215 100644 --- a/libopenjpeg/cio.c +++ b/libopenjpeg/cio.c @@ -371,7 +371,7 @@ void opj_read_float_LE(const OPJ_BYTE * p_buffer, OPJ_FLOAT32 * p_value) * Creates an abstract stream. This function does nothing except allocating memory and initializing the abstract stream. * @return a stream object. */ -opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_UINT32 p_size,opj_bool l_is_input) +opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_SIZE_T p_buffer_size,opj_bool l_is_input) { opj_stream_private_t * l_stream = 00; l_stream = (opj_stream_private_t*) opj_malloc(sizeof(opj_stream_private_t)); @@ -380,8 +380,8 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_UINT32 p_size,opj_bool l_is_inp } memset(l_stream,0,sizeof(opj_stream_private_t)); - l_stream->m_buffer_size = p_size; - l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_size); + l_stream->m_buffer_size = p_buffer_size; + l_stream->m_stored_data = (OPJ_BYTE *) opj_malloc(p_buffer_size); if (! l_stream->m_stored_data) { opj_free(l_stream); return 00; @@ -506,10 +506,9 @@ OPJ_API void OPJ_CALLCONV opj_stream_set_user_data(opj_stream_t* p_stream, void * @param p_stream the stream to modify * @param p_data the data to set. */ -OPJ_API void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream, OPJ_UINT32 data_length) +OPJ_API void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream, OPJ_UINT64 data_length) { opj_stream_private_t* l_stream = (opj_stream_private_t*) p_stream; - l_stream->m_user_data_length = data_length; } @@ -521,9 +520,9 @@ OPJ_API void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. */ -OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) +OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) { - OPJ_UINT32 l_read_nb_bytes = 0; + OPJ_SIZE_T l_read_nb_bytes = 0; if (p_stream->m_bytes_in_buffer >= p_size) { memcpy(p_buffer,p_stream->m_current_data,p_size); p_stream->m_current_data += p_size; @@ -637,10 +636,10 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes writtent, or -1 if an error occured. */ -OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer,OPJ_UINT32 p_size, opj_event_mgr_t * p_event_mgr) +OPJ_SIZE_T opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer,OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) { - OPJ_UINT32 l_remaining_bytes = 0; - OPJ_UINT32 l_write_nb_bytes = 0; + OPJ_SIZE_T l_remaining_bytes = 0; + OPJ_SIZE_T l_write_nb_bytes = 0; if (p_stream->m_status & opj_stream_e_error) @@ -693,7 +692,7 @@ OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE opj_bool opj_stream_flush (opj_stream_private_t * p_stream, opj_event_mgr_t * p_event_mgr) { // the number of bytes written on the media. - OPJ_UINT32 l_current_write_nb_bytes = 0; + OPJ_SIZE_T l_current_write_nb_bytes = 0; p_stream->m_current_data = p_stream->m_stored_data; while @@ -723,16 +722,18 @@ opj_bool opj_stream_flush (opj_stream_private_t * p_stream, opj_event_mgr_t * p_ * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +OPJ_OFF_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, opj_event_mgr_t * p_event_mgr) { - OPJ_SIZE_T l_skip_nb_bytes = 0; - OPJ_SIZE_T l_current_skip_nb_bytes = 0; + OPJ_OFF_T l_skip_nb_bytes = 0; + OPJ_OFF_T l_current_skip_nb_bytes = 0; if (p_stream->m_bytes_in_buffer >= p_size) { p_stream->m_current_data += p_size; - p_stream->m_bytes_in_buffer -= p_size; + // it is safe to cast p_size to OPJ_SIZE_T since it is <= m_bytes_in_buffer + // which is of type OPJ_SIZE_T + p_stream->m_bytes_in_buffer -= (OPJ_SIZE_T)p_size; l_skip_nb_bytes += p_size; p_stream->m_byte_offset += l_skip_nb_bytes; return l_skip_nb_bytes; @@ -746,7 +747,7 @@ OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_s p_stream->m_current_data += p_stream->m_bytes_in_buffer; p_stream->m_bytes_in_buffer = 0; p_stream->m_byte_offset += l_skip_nb_bytes; - return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T) -1; + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_OFF_T) -1; } // the flag is not set, we copy data and then do an actual skip on the stream @@ -765,14 +766,14 @@ OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_s // we should do an actual skip on the media l_current_skip_nb_bytes = p_stream->m_skip_fn(p_size, p_stream->m_user_data); if - (l_current_skip_nb_bytes == (OPJ_SIZE_T) -1) + (l_current_skip_nb_bytes == (OPJ_OFF_T) -1) { opj_event_msg_v2(p_event_mgr, EVT_INFO, "Stream reached its end !\n"); p_stream->m_status |= opj_stream_e_end; p_stream->m_byte_offset += l_skip_nb_bytes; // end if stream - return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T) -1; + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_OFF_T) -1; } p_size -= l_current_skip_nb_bytes; l_skip_nb_bytes += l_current_skip_nb_bytes; @@ -788,16 +789,16 @@ OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_s * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +OPJ_OFF_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, opj_event_mgr_t * p_event_mgr) { opj_bool l_is_written = 0; - OPJ_SIZE_T l_current_skip_nb_bytes = 0; - OPJ_SIZE_T l_skip_nb_bytes = 0; + OPJ_OFF_T l_current_skip_nb_bytes = 0; + OPJ_OFF_T l_skip_nb_bytes = 0; if (p_stream->m_status & opj_stream_e_error) { - return (OPJ_SIZE_T) -1; + return (OPJ_OFF_T) -1; } // we should flush data @@ -808,7 +809,7 @@ OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_ p_stream->m_status |= opj_stream_e_error; p_stream->m_bytes_in_buffer = 0; p_stream->m_current_data = p_stream->m_current_data; - return (OPJ_SIZE_T) -1; + return (OPJ_OFF_T) -1; } // then skip @@ -818,14 +819,14 @@ OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_ // we should do an actual skip on the media l_current_skip_nb_bytes = p_stream->m_skip_fn(p_size, p_stream->m_user_data); if - (l_current_skip_nb_bytes == (OPJ_SIZE_T)-1) + (l_current_skip_nb_bytes == (OPJ_OFF_T)-1) { opj_event_msg_v2(p_event_mgr, EVT_INFO, "Stream error!\n"); p_stream->m_status |= opj_stream_e_error; p_stream->m_byte_offset += l_skip_nb_bytes; // end if stream - return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_SIZE_T)-1; + return l_skip_nb_bytes ? l_skip_nb_bytes : (OPJ_OFF_T)-1; } p_size -= l_current_skip_nb_bytes; l_skip_nb_bytes += l_current_skip_nb_bytes; @@ -841,7 +842,7 @@ OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_ * * @return the current position of the stream. */ -OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream) +OPJ_OFF_T opj_stream_tell (const opj_stream_private_t * p_stream) { return p_stream->m_byte_offset; } @@ -854,7 +855,7 @@ OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream) * * @return Number of bytes left before the end of the stream. */ -OPJ_SIZE_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_stream) +OPJ_OFF_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_stream) { return p_stream->m_user_data_length ? p_stream->m_user_data_length - p_stream->m_byte_offset : @@ -868,8 +869,9 @@ OPJ_SIZE_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_strea * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +OPJ_OFF_T opj_stream_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, opj_event_mgr_t * p_event_mgr) { + assert(p_size >= 0); return p_stream->m_opj_skip(p_stream,p_size,p_event_mgr); } @@ -881,8 +883,9 @@ OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, opj_event_mgr_t * p_event_mgr) { + OPJ_ARG_NOT_USED(p_event_mgr); p_stream->m_current_data = p_stream->m_stored_data; p_stream->m_bytes_in_buffer = 0; @@ -907,7 +910,7 @@ opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_siz * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, opj_event_mgr_t * p_event_mgr) +opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, opj_event_mgr_t * p_event_mgr) { if (! opj_stream_flush(p_stream,p_event_mgr)) @@ -940,8 +943,9 @@ opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_si * @param p_event_mgr the user event manager to be notified of special events. * @return true if the stream is seekable. */ -opj_bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr) +opj_bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr) { + assert(p_size >= 0); return p_stream->m_opj_seek(p_stream,p_size,p_event_mgr); } @@ -953,28 +957,32 @@ opj_bool opj_stream_has_seek (const opj_stream_private_t * p_stream) return p_stream->m_seek_fn != opj_stream_default_seek; } - - - - -OPJ_UINT32 opj_stream_default_read (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) -{ - return (OPJ_UINT32) -1; -} -OPJ_UINT32 opj_stream_default_write (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) -{ - return (OPJ_UINT32) -1; -} -OPJ_SIZE_T opj_stream_default_skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +OPJ_SIZE_T opj_stream_default_read (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) { + OPJ_ARG_NOT_USED(p_buffer); + OPJ_ARG_NOT_USED(p_nb_bytes); + OPJ_ARG_NOT_USED(p_user_data); return (OPJ_SIZE_T) -1; } -opj_bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data) +OPJ_SIZE_T opj_stream_default_write (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) { - return EXIT_FAILURE; + OPJ_ARG_NOT_USED(p_buffer); + OPJ_ARG_NOT_USED(p_nb_bytes); + OPJ_ARG_NOT_USED(p_user_data); + return (OPJ_SIZE_T) -1; } +OPJ_OFF_T opj_stream_default_skip (OPJ_OFF_T p_nb_bytes, void * p_user_data) +{ + OPJ_ARG_NOT_USED(p_nb_bytes); + OPJ_ARG_NOT_USED(p_user_data); + return (OPJ_OFF_T) -1; +} - - +opj_bool opj_stream_default_seek (OPJ_OFF_T p_nb_bytes, void * p_user_data) +{ + OPJ_ARG_NOT_USED(p_nb_bytes); + OPJ_ARG_NOT_USED(p_user_data); + return EXIT_FAILURE; +} diff --git a/libopenjpeg/cio.h b/libopenjpeg/cio.h index 55df189f..b2769308 100644 --- a/libopenjpeg/cio.h +++ b/libopenjpeg/cio.h @@ -128,7 +128,7 @@ typedef struct opj_stream_private /** * User data length */ - OPJ_UINT32 m_user_data_length; + OPJ_UINT64 m_user_data_length; /** * Pointer to actual read function (NULL at the initialization of the cio. @@ -165,24 +165,24 @@ typedef struct opj_stream_private */ OPJ_BYTE * m_current_data; - OPJ_SIZE_T (* m_opj_skip)(struct opj_stream_private * ,OPJ_SIZE_T , struct opj_event_mgr *); + OPJ_OFF_T (* m_opj_skip)(struct opj_stream_private * ,OPJ_OFF_T , struct opj_event_mgr *); - opj_bool (* m_opj_seek) (struct opj_stream_private * , OPJ_SIZE_T , struct opj_event_mgr *); + opj_bool (* m_opj_seek) (struct opj_stream_private * , OPJ_OFF_T , struct opj_event_mgr *); /** * number of bytes containing in the buffer. */ - OPJ_UINT32 m_bytes_in_buffer; + OPJ_SIZE_T m_bytes_in_buffer; /** - * The number of bytes read/written. + * The number of bytes read/written from the beginning of the stream */ - OPJ_SIZE_T m_byte_offset; + OPJ_OFF_T m_byte_offset; /** * The size of the buffer. */ - OPJ_UINT32 m_buffer_size; + OPJ_SIZE_T m_buffer_size; /** * Flags to tell the status of the stream. @@ -293,7 +293,7 @@ void opj_write_float_BE(OPJ_BYTE * p_buffer, OPJ_FLOAT32 p_value); * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes read, or -1 if an error occured or if the stream is at the end. */ -OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, struct opj_event_mgr * p_event_mgr); +OPJ_SIZE_T opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); /** * Writes some bytes to the stream. @@ -303,7 +303,7 @@ OPJ_UINT32 opj_stream_read_data (opj_stream_private_t * p_stream,OPJ_BYTE * p_bu * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes writtent, or -1 if an error occured. */ -OPJ_UINT32 opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer, OPJ_UINT32 p_size, struct opj_event_mgr * p_event_mgr); +OPJ_SIZE_T opj_stream_write_data (opj_stream_private_t * p_stream,const OPJ_BYTE * p_buffer, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); /** * Writes the content of the stream buffer to the stream. @@ -320,7 +320,7 @@ opj_bool opj_stream_flush (opj_stream_private_t * p_stream, struct opj_event_mgr * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream,OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +OPJ_OFF_T opj_stream_skip (opj_stream_private_t * p_stream,OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); /** * Tells the byte offset on the stream (similar to ftell). @@ -329,7 +329,7 @@ OPJ_SIZE_T opj_stream_skip (opj_stream_private_t * p_stream,OPJ_SIZE_T p_size, s * * @return the current position o fthe stream. */ -OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream); +OPJ_OFF_T opj_stream_tell (const opj_stream_private_t * p_stream); /** @@ -339,7 +339,7 @@ OPJ_SIZE_T opj_stream_tell (const opj_stream_private_t * p_stream); * * @return Number of bytes left before the end of the stream. */ -OPJ_SIZE_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_stream); +OPJ_OFF_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_stream); /** * Skips a number of bytes from the stream. @@ -348,7 +348,7 @@ OPJ_SIZE_T opj_stream_get_number_byte_left (const opj_stream_private_t * p_strea * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +OPJ_OFF_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); /** * Skips a number of bytes from the stream. @@ -357,7 +357,7 @@ OPJ_SIZE_T opj_stream_write_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_ * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +OPJ_OFF_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); /** * Skips a number of bytes from the stream. @@ -366,7 +366,7 @@ OPJ_SIZE_T opj_stream_read_skip (opj_stream_private_t * p_stream, OPJ_SIZE_T p_s * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); /** * Skips a number of bytes from the stream. @@ -375,7 +375,7 @@ opj_bool opj_stream_read_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_siz * @param p_event_mgr the user event manager to be notified of special events. * @return the number of bytes skipped, or -1 if an error occured. */ -opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); /** * Seeks a number of bytes from the stream. @@ -384,17 +384,17 @@ opj_bool opj_stream_write_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_si * @param p_event_mgr the user event manager to be notified of special events. * @return true if the stream is seekable. */ -opj_bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_SIZE_T p_size, struct opj_event_mgr * p_event_mgr); +opj_bool opj_stream_seek (opj_stream_private_t * p_stream, OPJ_OFF_T p_size, struct opj_event_mgr * p_event_mgr); /** * Tells if the given stream is seekable. */ opj_bool opj_stream_has_seek (const opj_stream_private_t * p_stream); -OPJ_UINT32 opj_stream_default_read (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data); -OPJ_UINT32 opj_stream_default_write (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data); -OPJ_SIZE_T opj_stream_default_skip (OPJ_SIZE_T p_nb_bytes, void * p_user_data); -opj_bool opj_stream_default_seek (OPJ_SIZE_T p_nb_bytes, void * p_user_data); +OPJ_SIZE_T opj_stream_default_read (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data); +OPJ_SIZE_T opj_stream_default_write (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data); +OPJ_OFF_T opj_stream_default_skip (OPJ_OFF_T p_nb_bytes, void * p_user_data); +opj_bool opj_stream_default_seek (OPJ_OFF_T p_nb_bytes, void * p_user_data); diff --git a/libopenjpeg/j2k.c b/libopenjpeg/j2k.c index f1171d6a..19b4d2b4 100644 --- a/libopenjpeg/j2k.c +++ b/libopenjpeg/j2k.c @@ -669,7 +669,7 @@ Add main header marker information */ static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); -static void j2k_add_mhmarker_v2(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_UINT32 pos, OPJ_UINT32 len) ; +static void j2k_add_mhmarker_v2(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) ; /** Add tile header marker information @param tileno tile index number @@ -680,7 +680,7 @@ Add tile header marker information */ static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len); -static void j2k_add_tlmarker_v2(OPJ_UINT32 tileno, opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_UINT32 pos, OPJ_UINT32 len); +static void j2k_add_tlmarker_v2(OPJ_UINT32 tileno, opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len); /** * Reads an unknown marker @@ -1239,7 +1239,7 @@ static opj_bool j2k_read_soc_v2( opj_j2k_v2_t *p_j2k, p_j2k->m_specific_param.m_decoder.m_state = J2K_STATE_MHSIZ; /* FIXME move it in a index structure included in p_j2k*/ - p_j2k->cstr_index->main_head_start = (OPJ_UINT32) opj_stream_tell(p_stream) - 2; + p_j2k->cstr_index->main_head_start = opj_stream_tell(p_stream) - 2; opj_event_msg_v2(p_manager, EVT_INFO, "Start to read j2k main header (%d).\n", p_j2k->cstr_index->main_head_start); @@ -3914,8 +3914,13 @@ opj_bool j2k_read_sod_v2 ( l_tcp = &(p_j2k->m_cp.tcps[p_j2k->m_current_tile_number]); - if (p_j2k->m_specific_param.m_decoder.m_last_tile_part) - p_j2k->m_specific_param.m_decoder.m_sot_length = opj_stream_get_number_byte_left(p_stream) - 2; + if (p_j2k->m_specific_param.m_decoder.m_last_tile_part) { + // opj_stream_get_number_byte_left returns OPJ_OFF_T + // but we are in the last tile part, + // so its result will fit on OPJ_UINT32 unless we find + // a file with a single tile part of more than 4 GB... + p_j2k->m_specific_param.m_decoder.m_sot_length = (OPJ_UINT32)(opj_stream_get_number_byte_left(p_stream) - 2); + } else p_j2k->m_specific_param.m_decoder.m_sot_length -= 2; @@ -3923,10 +3928,10 @@ opj_bool j2k_read_sod_v2 ( l_tile_len = &l_tcp->m_data_size; if (! *l_current_data) { - *l_current_data = (OPJ_BYTE*) opj_malloc/*FIXME V2 -> my_opj_malloc*/(p_j2k->m_specific_param.m_decoder.m_sot_length); + *l_current_data = (OPJ_BYTE*) opj_malloc(p_j2k->m_specific_param.m_decoder.m_sot_length); } else { - *l_current_data = (OPJ_BYTE*) opj_realloc/*FIXME V2 -> my_opj_realloc*/(*l_current_data, *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length); + *l_current_data = (OPJ_BYTE*) opj_realloc(*l_current_data, *l_tile_len + p_j2k->m_specific_param.m_decoder.m_sot_length); } if (*l_current_data == 00) { @@ -3938,8 +3943,9 @@ opj_bool j2k_read_sod_v2 ( /* Index */ l_cstr_index = p_j2k->cstr_index; if (l_cstr_index) { - OPJ_SIZE_T l_current_pos = opj_stream_tell(p_stream) - 2; - OPJ_UINT32 l_current_tile_part =l_cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno; + OPJ_OFF_T l_current_pos = opj_stream_tell(p_stream) - 2; + + OPJ_UINT32 l_current_tile_part = l_cstr_index->tile_index[p_j2k->m_current_tile_number].current_tpsno; l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index[l_current_tile_part].end_header = l_current_pos; l_cstr_index->tile_index[p_j2k->m_current_tile_number].tp_index[l_current_tile_part].end_pos = @@ -3954,12 +3960,6 @@ opj_bool j2k_read_sod_v2 ( /*l_cstr_index->packno = 0;*/ } - - - - - - l_current_read_size = opj_stream_read_data( p_stream, *l_current_data + *l_tile_len, p_j2k->m_specific_param.m_decoder.m_sot_length, @@ -5770,7 +5770,7 @@ static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short in } -static void j2k_add_mhmarker_v2(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_UINT32 pos, OPJ_UINT32 len) { +static void j2k_add_mhmarker_v2(opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) { if (!cstr_index) return; @@ -5812,7 +5812,7 @@ static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsi cstr_info->tile[tileno].marknum++; } -static void j2k_add_tlmarker_v2(OPJ_UINT32 tileno, opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_UINT32 pos, OPJ_UINT32 len) +static void j2k_add_tlmarker_v2(OPJ_UINT32 tileno, opj_codestream_index_t *cstr_index, OPJ_UINT32 type, OPJ_OFF_T pos, OPJ_UINT32 len) { if (!cstr_index) @@ -6307,7 +6307,7 @@ opj_bool j2k_copy_default_tcp_and_create_tcd * * @return the handler associated with the id. */ -const opj_dec_memory_marker_handler_t * j2k_get_marker_handler (const OPJ_UINT32 p_id) +const opj_dec_memory_marker_handler_t * j2k_get_marker_handler (OPJ_UINT32 p_id) { const opj_dec_memory_marker_handler_t *e; for (e = j2k_memory_marker_handler_tab; e->id != 0; ++e) { @@ -6785,7 +6785,7 @@ opj_bool j2k_decode_tile ( opj_j2k_v2_t * p_j2k, l_tcp = &(p_j2k->m_cp.tcps[p_tile_index]); if (! l_tcp->m_data) { - j2k_tcp_destroy(&(p_j2k->m_cp.tcps[p_tile_index])); + j2k_tcp_destroy(&l_tcp); return OPJ_FALSE; } @@ -8220,14 +8220,14 @@ opj_bool j2k_decode_one_tile ( opj_j2k_v2_t *p_j2k, if (!j2k_allocate_tile_element_cstr_index(p_j2k)) return OPJ_FALSE; } - /* Move into the codestream to the first SOT used to decode the desired tile */ l_tile_no_to_dec = p_j2k->m_specific_param.m_decoder.m_tile_ind_to_dec; if (p_j2k->cstr_index->tile_index) if(p_j2k->cstr_index->tile_index->tp_index) { if ( ! p_j2k->cstr_index->tile_index[l_tile_no_to_dec].nb_tps) { - /* not build the index for this tile, so we will move to the last SOT read*/ + /* the index for this tile has not been built, + * so move to the last SOT read */ if ( opj_stream_read_seek(p_stream, p_j2k->m_specific_param.m_decoder.m_last_sot_read_pos+2, p_manager) ){ opj_event_msg_v2(p_manager, EVT_ERROR, "Problem with seek function\n"); return OPJ_FALSE; diff --git a/libopenjpeg/j2k.h b/libopenjpeg/j2k.h index 360d8699..2ec8980d 100644 --- a/libopenjpeg/j2k.h +++ b/libopenjpeg/j2k.h @@ -611,7 +611,7 @@ typedef struct opj_j2k_dec /** Index of the tile to decode (used in get_tile) */ OPJ_INT32 m_tile_ind_to_dec; /** Position of the last SOT marker read */ - OPJ_UINT32 m_last_sot_read_pos; + OPJ_OFF_T m_last_sot_read_pos; /** * Indicate that the current tile-part is assume as the last tile part of the codestream. diff --git a/libopenjpeg/openjpeg.c b/libopenjpeg/openjpeg.c index 73b136d6..4470887d 100644 --- a/libopenjpeg/openjpeg.c +++ b/libopenjpeg/openjpeg.c @@ -132,40 +132,40 @@ opj_codec_private_t; /* ---------------------------------------------------------------------- */ -OPJ_UINT32 opj_read_from_file (void * p_buffer, OPJ_UINT32 p_nb_bytes, FILE * p_file) +OPJ_SIZE_T opj_read_from_file (void * p_buffer, OPJ_SIZE_T p_nb_bytes, FILE * p_file) { - OPJ_UINT32 l_nb_read = fread(p_buffer,1,p_nb_bytes,p_file); + OPJ_SIZE_T l_nb_read = fread(p_buffer,1,p_nb_bytes,p_file); return l_nb_read ? l_nb_read : -1; } -OPJ_UINT32 opj_get_data_length_from_file (FILE * p_file) +OPJ_UINT64 opj_get_data_length_from_file (FILE * p_file) { - OPJ_UINT32 file_length = 0; + OPJ_OFF_T file_length = 0; - fseek(p_file, 0, SEEK_END); - file_length = ftell(p_file); - fseek(p_file, 0, SEEK_SET); + OPJ_FSEEK(p_file, 0, SEEK_END); + file_length = (OPJ_UINT64)OPJ_FTELL(p_file); + OPJ_FSEEK(p_file, 0, SEEK_SET); return file_length; } -OPJ_UINT32 opj_write_from_file (void * p_buffer, OPJ_UINT32 p_nb_bytes, FILE * p_file) +OPJ_SIZE_T opj_write_from_file (void * p_buffer, OPJ_SIZE_T p_nb_bytes, FILE * p_file) { return fwrite(p_buffer,1,p_nb_bytes,p_file); } -OPJ_SIZE_T opj_skip_from_file (OPJ_SIZE_T p_nb_bytes, FILE * p_user_data) +OPJ_OFF_T opj_skip_from_file (OPJ_OFF_T p_nb_bytes, FILE * p_user_data) { - if (fseek(p_user_data,p_nb_bytes,SEEK_CUR)) { + if (OPJ_FSEEK(p_user_data,p_nb_bytes,SEEK_CUR)) { return -1; } return p_nb_bytes; } -opj_bool opj_seek_from_file (OPJ_SIZE_T p_nb_bytes, FILE * p_user_data) +opj_bool opj_seek_from_file (OPJ_OFF_T p_nb_bytes, FILE * p_user_data) { - if (fseek(p_user_data,p_nb_bytes,SEEK_SET)) { + if (OPJ_FSEEK(p_user_data,p_nb_bytes,SEEK_SET)) { return EXIT_FAILURE; } @@ -617,7 +617,7 @@ opj_stream_t* OPJ_CALLCONV opj_stream_create_default_file_stream (FILE * p_file, return opj_stream_create_file_stream(p_file,J2K_STREAM_CHUNK_SIZE,p_is_read_stream); } -opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (FILE * p_file, OPJ_UINT32 p_size, opj_bool p_is_read_stream) +opj_stream_t* OPJ_CALLCONV opj_stream_create_file_stream (FILE * p_file, OPJ_SIZE_T p_size, opj_bool p_is_read_stream) { opj_stream_t* l_stream = 00; diff --git a/libopenjpeg/openjpeg.h b/libopenjpeg/openjpeg.h index 34915a16..d8a332b3 100644 --- a/libopenjpeg/openjpeg.h +++ b/libopenjpeg/openjpeg.h @@ -572,10 +572,10 @@ typedef struct opj_cio { /* * FIXME DOC */ -typedef OPJ_UINT32 (* opj_stream_read_fn) (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) ; -typedef OPJ_UINT32 (* opj_stream_write_fn) (void * p_buffer, OPJ_UINT32 p_nb_bytes, void * p_user_data) ; -typedef OPJ_SIZE_T (* opj_stream_skip_fn) (OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; -typedef opj_bool (* opj_stream_seek_fn) (OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; +typedef OPJ_SIZE_T (* opj_stream_read_fn) (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; +typedef OPJ_SIZE_T (* opj_stream_write_fn) (void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) ; +typedef OPJ_OFF_T (* opj_stream_skip_fn) (OPJ_OFF_T p_nb_bytes, void * p_user_data) ; +typedef opj_bool (* opj_stream_seek_fn) (OPJ_OFF_T p_nb_bytes, void * p_user_data) ; /* * JPEG2000 Stream. @@ -679,11 +679,11 @@ typedef struct opj_image_comptparm { * */ typedef struct opj_packet_info { /** packet start position (including SOP marker if it exists) */ - int start_pos; + OPJ_OFF_T start_pos; /** end of packet header position (including EPH marker if it exists)*/ - int end_ph_pos; + OPJ_OFF_T end_ph_pos; /** packet end position */ - int end_pos; + OPJ_OFF_T end_pos; /** packet distorsion */ double disto; } opj_packet_info_t; @@ -697,7 +697,7 @@ typedef struct opj_marker_info_t { /** marker type */ unsigned short int type; /** position in codestream */ - int pos; + OPJ_OFF_T pos; /** length, marker val included */ int len; } opj_marker_info_t; @@ -906,14 +906,11 @@ typedef struct opj_codestream_info_v2 { */ typedef struct opj_tp_index { /** start position */ - OPJ_UINT32 start_pos; + OPJ_OFF_T start_pos; /** end position of the header */ - OPJ_UINT32 end_header; + OPJ_OFF_T end_header; /** end position */ - OPJ_UINT32 end_pos; - - - + OPJ_OFF_T end_pos; } opj_tp_index_t; @@ -954,12 +951,12 @@ typedef struct opj_tile_index { */ typedef struct opj_codestream_index_ { /** main header start position (SOC position) */ - OPJ_UINT32 main_head_start; + OPJ_OFF_T main_head_start; /** main header end position (first SOT position) */ - OPJ_UINT32 main_head_end; + OPJ_OFF_T main_head_end; /** codestream's size */ - OPJ_UINT32 codestream_size; + OPJ_UINT64 codestream_size; /* UniPG>> */ /** number of markers */ @@ -1089,7 +1086,7 @@ OPJ_API void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos); * @return a stream object. */ OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_default_create(opj_bool p_is_input); -OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_UINT32 p_size, opj_bool p_is_input); +OPJ_API opj_stream_t* OPJ_CALLCONV opj_stream_create(OPJ_SIZE_T p_buffer_size, opj_bool p_is_input); /** * Destroys a stream created by opj_create_stream. This function does NOT close the abstract stream. If needed the user must @@ -1140,7 +1137,7 @@ OPJ_API void OPJ_CALLCONV opj_stream_set_user_data (opj_stream_t* p_stream, void * @param p_stream the stream to modify * @param data_length length of the user_data. */ -OPJ_API void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream, OPJ_UINT32 data_length); +OPJ_API void OPJ_CALLCONV opj_stream_set_user_data_length(opj_stream_t* p_stream, OPJ_UINT64 data_length); /** diff --git a/libopenjpeg/opj_includes.h b/libopenjpeg/opj_includes.h index 4801ef69..0ee873a8 100644 --- a/libopenjpeg/opj_includes.h +++ b/libopenjpeg/opj_includes.h @@ -60,7 +60,7 @@ #endif -#if defined(MSWINDOWS) && !defined(Windows95) && !defined(__BORLANDC__) && \ +#if defined(WIN32) && !defined(Windows95) && !defined(__BORLANDC__) && \ !(defined(_MSC_VER) && _MSC_VER < 1400) && \ !(defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x800) /* diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0a6215c4..1252948b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,6 +24,9 @@ TARGET_LINK_LIBRARIES(comparePGXimages ${OPENJPEG_LIBRARY_NAME} ADD_EXECUTABLE(compare_dump_files ${compare_dump_files_SRCS}) +ADD_EXECUTABLE(j2k_random_tile_access j2k_random_tile_access.c) +TARGET_LINK_LIBRARIES(j2k_random_tile_access ${OPENJPEG_LIBRARY_NAME}) + ADD_EXECUTABLE(compareRAWimages ${compareRAWimages_SRCS}) # No image send to the dashboard if lib PNG is not available. diff --git a/tests/j2k_random_tile_access.c b/tests/j2k_random_tile_access.c new file mode 100644 index 00000000..ab08760a --- /dev/null +++ b/tests/j2k_random_tile_access.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium + * Copyright (c) 2002-2007, Professor Benoit Macq + * Copyright (c) 2001-2003, David Janssens + * Copyright (c) 2002-2003, Yannick Verschueren + * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe + * Copyright (c) 2005, Herve Drolon, FreeImage Team + * Copyright (c) 2006-2007, Parvatha Elangovan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "opj_config.h" + +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#define _stricmp strcasecmp +#define _strnicmp strncasecmp +#endif /* _WIN32 */ + +#include "openjpeg.h" +#include "format_defs.h" + +/* -------------------------------------------------------------------------- */ +int get_file_format(const char *filename) { + unsigned int i; + static const char *extension[] = {"pgx", "pnm", "pgm", "ppm", "bmp","tif", "raw", "tga", "png", "j2k", "jp2", "jpt", "j2c", "jpc" }; + static const int format[] = { PGX_DFMT, PXM_DFMT, PXM_DFMT, PXM_DFMT, BMP_DFMT, TIF_DFMT, RAW_DFMT, TGA_DFMT, PNG_DFMT, J2K_CFMT, JP2_CFMT, JPT_CFMT, J2K_CFMT, J2K_CFMT }; + char * ext = strrchr(filename, '.'); + if (ext == NULL) + return -1; + ext++; + if(ext) { + for(i = 0; i < sizeof(format)/sizeof(*format); i++) { + if(_strnicmp(ext, extension[i], 3) == 0) { + return format[i]; + } + } + } + + return -1; +} + +/* -------------------------------------------------------------------------- */ + +/** +sample error callback expecting a FILE* client object +*/ +void error_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[ERROR] %s", msg); +} +/** +sample warning callback expecting a FILE* client object +*/ +void warning_callback(const char *msg, void *client_data) { + FILE *stream = (FILE*)client_data; + fprintf(stream, "[WARNING] %s", msg); +} +/** +sample debug callback expecting no client object +*/ +void info_callback(const char *msg, void *client_data) { + (void)client_data; + fprintf(stdout, "[INFO] %s", msg); +} + + +/* -------------------------------------------------------------------------- */ +#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a" +#define JP2_MAGIC "\x0d\x0a\x87\x0a" +/* position 45: "\xff\x52" */ +#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51" + +static int infile_format(const char *fname) +{ + FILE *reader; + const char *s, *magic_s; + int ext_format, magic_format; + unsigned char buf[12]; + unsigned int l_nb_read; + + reader = fopen(fname, "rb"); + + if (reader == NULL) + return -1; + + memset(buf, 0, 12); + l_nb_read = fread(buf, 1, 12, reader); + fclose(reader); + if (l_nb_read != 12) + return -1; + + + + ext_format = get_file_format(fname); + + if (ext_format == JPT_CFMT) + return JPT_CFMT; + + if (memcmp(buf, JP2_RFC3745_MAGIC, 12) == 0 || memcmp(buf, JP2_MAGIC, 4) == 0) { + magic_format = JP2_CFMT; + magic_s = ".jp2"; + } + else if (memcmp(buf, J2K_CODESTREAM_MAGIC, 4) == 0) { + magic_format = J2K_CFMT; + magic_s = ".j2k or .jpc or .j2c"; + } + else + return -1; + + if (magic_format == ext_format) + return ext_format; + + s = fname + strlen(fname) - 4; + + fputs("\n===========================================\n", stderr); + fprintf(stderr, "The extension of this file is incorrect.\n" + "FOUND %s. SHOULD BE %s\n", s, magic_s); + fputs("===========================================\n", stderr); + + return magic_format; +} + +/* -------------------------------------------------------------------------- */ +/** + * J2K_RANDOM_TILE_ACCESS MAIN + */ +/* -------------------------------------------------------------------------- */ +int main(int argc, char **argv) +{ + FILE *fsrc = NULL; + + opj_dparameters_t parameters; /* decompression parameters */ + opj_event_mgr_t event_mgr; /* event manager */ + opj_image_t* image = NULL; + opj_stream_t *cio = NULL; /* Stream */ + opj_codec_t* dinfo = NULL; /* Handle to a decompressor */ + opj_codestream_info_v2_t* cstr_info = NULL; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + /* Set event mgr */ + event_mgr.error_handler = error_callback; + event_mgr.warning_handler = warning_callback; + event_mgr.info_handler = info_callback; + opj_initialize_default_event_handler(&event_mgr, 1); + + /* Set decoding parameters to default values */ + opj_set_default_decoder_parameters(¶meters); + + strncpy(parameters.infile, argv[1], OPJ_PATH_LEN - 1); + + /* read the input file */ + /* ------------------- */ + fsrc = fopen(parameters.infile, "rb"); + if (!fsrc) { + fprintf(stderr, "ERROR -> failed to open %s for reading\n", parameters.infile); + return EXIT_FAILURE; + } + + /* decode the JPEG2000 stream */ + /* -------------------------- */ + parameters.decod_format = infile_format(parameters.infile); + + switch(parameters.decod_format) { + case J2K_CFMT: /* JPEG-2000 codestream */ + { + /* Get a decoder handle */ + dinfo = opj_create_decompress_v2(CODEC_J2K); + break; + } + case JP2_CFMT: /* JPEG 2000 compressed image data */ + { + /* Get a decoder handle */ + dinfo = opj_create_decompress_v2(CODEC_JP2); + break; + } + case JPT_CFMT: /* JPEG 2000, JPIP */ + { + /* Get a decoder handle */ + dinfo = opj_create_decompress_v2(CODEC_JPT); + break; + } + default: + fprintf(stderr, + "Unrecognized format for input %s [accept only *.j2k, *.jp2, *.jpc or *.jpt]\n\n", + parameters.infile); + return EXIT_FAILURE; + } + + cio = opj_stream_create_default_file_stream(fsrc,1); + if (!cio){ + fclose(fsrc); + fprintf(stderr, "ERROR -> failed to create the stream from the file\n"); + return EXIT_FAILURE; + } + + /* Setup the decoder decoding parameters using user parameters */ + if ( !opj_setup_decoder_v2(dinfo, ¶meters, &event_mgr) ){ + fprintf(stderr, "ERROR -> j2k_dump: failed to setup the decoder\n"); + opj_stream_destroy(cio); + fclose(fsrc); + opj_destroy_codec(dinfo); + return EXIT_FAILURE; + } + + /* Read the main header of the codestream and if necessary the JP2 boxes*/ + if(! opj_read_header(cio, dinfo, &image)){ + fprintf(stderr, "ERROR -> j2k_to_image: failed to read the header\n"); + opj_stream_destroy(cio); + fclose(fsrc); + opj_destroy_codec(dinfo); + opj_image_destroy(image); + return EXIT_FAILURE; + } + + /* Extract some info from the code stream */ + cstr_info = opj_get_cstr_info(dinfo); + + fprintf(stdout, "The file contains %dx%d tiles\n", cstr_info->tw, cstr_info->th); + + OPJ_UINT32 tile_ul = 0; + OPJ_UINT32 tile_ur = cstr_info->tw - 1; + OPJ_UINT32 tile_lr = cstr_info->tw * cstr_info->th - 1; + OPJ_UINT32 tile_ll = tile_lr - cstr_info->tw; + +#define TEST_TILE( tile_index ) \ + fprintf(stdout, "Decoding tile %d ...\n", tile_index); \ + if(!opj_get_decoded_tile(dinfo, cio, image, tile_index )){ \ + fprintf(stderr, "ERROR -> j2k_to_image: failed to decode tile %d\n", tile_index); \ + opj_stream_destroy(cio); \ + opj_destroy_cstr_info_v2(cstr_info); \ + opj_destroy_codec(dinfo); \ + opj_image_destroy(image); \ + fclose(fsrc); \ + return EXIT_FAILURE; \ + } \ + fprintf(stdout, "Tile %d is decoded successfully\n", tile_index); + + TEST_TILE(tile_ul) + TEST_TILE(tile_lr) + TEST_TILE(tile_ul) + TEST_TILE(tile_ll) + TEST_TILE(tile_ur) + TEST_TILE(tile_lr) + + /* Close the byte stream */ + opj_stream_destroy(cio); + + /* Destroy code stream info */ + opj_destroy_cstr_info_v2(cstr_info); + + /* Free remaining structures */ + opj_destroy_codec(dinfo); + + /* Free image data structure */ + opj_image_destroy(image); + + /* Close the input file */ + fclose(fsrc); + + return EXIT_SUCCESS; +} +//end main + + + +