Merge branch 'master' of github.com:singularity-viewer/SingularityViewer

This commit is contained in:
Drake Arconis
2013-01-05 20:50:49 -05:00
1413 changed files with 23754 additions and 12090 deletions

View File

@@ -17,15 +17,25 @@ find_library(FMODEX_LIBRARY
if (NOT FMODEX_LIBRARY)
set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.")
if (FMODEX_SDK_DIR)
find_library(FMODEX_LIBRARY
fmodex_vc fmodexL_vc fmodex fmodexL fmodex64 fmodexL64
PATHS
${FMODEX_SDK_DIR}/api/lib
${FMODEX_SDK_DIR}/api
${FMODEX_SDK_DIR}/lib
${FMODEX_SDK_DIR}
)
if(WORD_SIZE EQUAL 32)
find_library(FMODEX_LIBRARY
fmodex_vc fmodexL_vc fmodex fmodexL
PATHS
${FMODEX_SDK_DIR}/api/lib
${FMODEX_SDK_DIR}/api
${FMODEX_SDK_DIR}/lib
${FMODEX_SDK_DIR}
)
elseif(WORD_SIZE EQUAL 64)
find_library(FMODEX_LIBRARY
fmodex64 fmodexL64
PATHS
${FMODEX_SDK_DIR}/api/lib
${FMODEX_SDK_DIR}/api
${FMODEX_SDK_DIR}/lib
${FMODEX_SDK_DIR}
)
endif(WORD_SIZE EQUAL 32)
endif(FMODEX_SDK_DIR)
if(WINDOWS AND NOT FMODEX_LIBRARY)
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")

View File

@@ -3,16 +3,18 @@
# - Find JSONCpp
# Find the JSONCpp includes and library
# This module defines
# JSONCPP_INCLUDE_DIR, where to find json.h, etc.
# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp.
# JSONCPP_FOUND, If false, do not try to use jsoncpp.
# also defined, but not for general use are
# JSONCPP_LIBRARY, where to find the jsoncpp library.
# JSONCPP_FOUND, System has libjsoncpp.
# JSONCPP_INCLUDE_DIRS - The libjsoncpp include directories.
# JSONCPP_LIBRARIES - The libraries needed to use libjsoncpp.
# JSONCPP_DEFINITIONS - Compiler switches required for using libjsoncpp.
FIND_PATH(JSONCPP_INCLUDE_DIR json/json.h
/usr/local/include
/usr/include
)
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(PC_JSONCPP jsoncpp)
SET(JSONCPP_DEFINITIONS ${PC_JSONCPP_CFLAGS_OTHER})
FIND_PATH(JSONCPP_INCLUDE_DIR json/reader.h
HINTS ${PC_JSONCPP_INCLUDE_DIR} ${PC_JSONCPP_INCLUDE_DIRS}
PATH_SUFFIXES jsoncpp)
# Get the GCC compiler version
EXEC_PROGRAM(${CMAKE_CXX_COMPILER}
@@ -22,39 +24,16 @@ EXEC_PROGRAM(${CMAKE_CXX_COMPILER}
)
# Try to find a library that was compiled with the same compiler version as we currently use.
SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson_linux-gcc-${_gcc_COMPILER_VERSION}_libmt.so)
IF (STANDALONE)
# On standalone, assume that the system installed library was compiled with the used compiler.
SET(JSONCPP_NAMES ${JSONCPP_NAMES} libjson.so)
ENDIF (STANDALONE)
FIND_LIBRARY(JSONCPP_LIBRARY
NAMES ${JSONCPP_NAMES}
PATHS /usr/lib /usr/local/lib
)
NAMES libjson_linux-gcc-${_gcc_COMPILER_VERSION}_libmt.so libjsoncpp.so
HINTS ${PC_JSONCPP_LIBDIR} ${PC_JSONCPP_LIBRARY_DIRS}
PATHS /usr/lib /usr/local/lib)
IF (JSONCPP_LIBRARY AND JSONCPP_INCLUDE_DIR)
SET(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY})
SET(JSONCPP_FOUND "YES")
ELSE (JSONCPP_LIBRARY AND JSONCPP_INCLUDE_DIR)
SET(JSONCPP_FOUND "NO")
ENDIF (JSONCPP_LIBRARY AND JSONCPP_INCLUDE_DIR)
SET(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY})
SET(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(JSONCPP DEFAULT_MSG
JSONCPP_LIBRARY JSONCPP_INCLUDE_DIR)
IF (JSONCPP_FOUND)
IF (NOT JSONCPP_FIND_QUIETLY)
MESSAGE(STATUS "Found JSONCpp: ${JSONCPP_LIBRARIES}")
ENDIF (NOT JSONCPP_FIND_QUIETLY)
ELSE (JSONCPP_FOUND)
IF (JSONCPP_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find JSONCpp library")
ENDIF (JSONCPP_FIND_REQUIRED)
ENDIF (JSONCPP_FOUND)
# Deprecated declarations.
SET (NATIVE_JSONCPP_INCLUDE_PATH ${JSONCPP_INCLUDE_DIR} )
GET_FILENAME_COMPONENT (NATIVE_JSONCPP_LIB_PATH ${JSONCPP_LIBRARY} PATH)
MARK_AS_ADVANCED(
JSONCPP_LIBRARY
JSONCPP_INCLUDE_DIR
)
MARK_AS_ADVANCED(JSONCPP_LIBRARY JSONCPP_INCLUDE_DIR)

View File

@@ -11,10 +11,10 @@ else (STANDALONE)
if (LINUX OR WINDOWS AND NOT WORD_SIZE EQUAL 64)
use_prebuilt_binary(gperftools)
endif (LINUX OR WINDOWS AND NOT WORD_SIZE EQUAL 64)
if (WINDOWS)
if (WINDOWS AND NOT DISABLE_TCMALLOC)
set(TCMALLOC_LIBRARIES libtcmalloc_minimal.lib)
set(TCMALLOC_LINKER_FLAGS "/INCLUDE:\"__tcmalloc\"")
endif (WINDOWS)
endif (WINDOWS AND NOT DISABLE_TCMALLOC)
if (LINUX)
if(USE_GOOGLE_PERFTOOLS)
set(TCMALLOC_LIBRARIES tcmalloc)

View File

@@ -2,7 +2,7 @@
include(Prebuilt)
set(JSONCPP_FIND_QUIETLY ON)
set(JSONCPP_FIND_QUIETLY OFF)
set(JSONCPP_FIND_REQUIRED ON)
if (STANDALONE)

View File

@@ -4,9 +4,9 @@ include(Prebuilt)
set(OpenSSL_FIND_QUIETLY ON)
set(OpenSSL_FIND_REQUIRED ON)
if (STANDALONE)
if (STANDALONE OR USE_SYSTEM_OPENSSL)
include(FindOpenSSL)
else (STANDALONE)
else (STANDALONE OR USE_SYSTEM_OPENSSL)
use_prebuilt_binary(openSSL)
if (WINDOWS)
set(OPENSSL_LIBRARIES ssleay32 libeay32)
@@ -14,7 +14,7 @@ else (STANDALONE)
set(OPENSSL_LIBRARIES ssl)
endif (WINDOWS)
set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
endif (STANDALONE)
endif (STANDALONE OR USE_SYSTEM_OPENSSL)
if (LINUX OR DARWIN)
set(CRYPTO_LIBRARIES crypto)

View File

@@ -30,6 +30,7 @@ set(LIBS_SERVER_DIR ${CMAKE_SOURCE_DIR}/${LIBS_SERVER_PREFIX})
set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX})
set(SERVER_DIR ${CMAKE_SOURCE_DIR}/${SERVER_PREFIX})
set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX})
set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)")
set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation)")
set(VISTA_ICON OFF CACHE BOOL "Allow vista icon with pre 2008 Visual Studio IDEs. (Assumes replacement old rcdll.dll with new rcdll.dll from win sdk 7.0 or later)")

View File

@@ -236,8 +236,9 @@ void stop_recording_backtraces(void)
channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces.
channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used for output related to class AIStateMachine.
channel_ct caps DDCN("CAPS"); //!< This debug channel is used for output related to Capabilities.
channel_ct curl DDCN("CURL"); //!< This debug channel is used for output related to Curl.
channel_ct curlio DDCN("CURLIO"); //!< This debug channel is used to print debug output of libcurl.
channel_ct curl DDCN("CURL"); //!< This debug channel is used for output related to AICurl.
channel_ct curlio DDCN("CURLIO"); //!< This debug channel is used to print debug output of libcurl. This includes all HTTP network traffic.
channel_ct curltr DDCN("CURLTR"); //!< This debug channel is used to print libcurl API calls.
} // namespace dc
} // namespace DEBUGCHANNELS

View File

@@ -207,6 +207,7 @@ extern CWD_API channel_ct statemachine;
extern CWD_API channel_ct caps;
extern CWD_API channel_ct curl;
extern CWD_API channel_ct curlio;
extern CWD_API channel_ct curltr;
#endif

View File

@@ -766,13 +766,14 @@ Commands:
Command-options for "configure":
We use cmake variables to change the build configuration.
-DSERVER:BOOL=OFF Don't configure simulator/dataserver/etc
-DVIEWER:BOOL=OFF Don't configure the viewer
-DPACKAGE:BOOL=ON Create "package" target to make installers
-DLOCALIZESETUP:BOOL=ON Create one win_setup target per supported language
-DLL_TESTS:BOOL=OFF Don't generate unit test projects
-DEXAMPLEPLUGIN:BOOL=OFF Don't generate example plugin project
-VISTA_ICON:BOOL=ON Allow pre-2008 VS to use vista-optimized resource file. (Requires updated rcdll.dll!)
-DSERVER:BOOL=OFF Don't configure simulator/dataserver/etc
-DVIEWER:BOOL=OFF Don't configure the viewer
-DPACKAGE:BOOL=ON Create "package" target to make installers
-DLOCALIZESETUP:BOOL=ON Create one win_setup target per supported language
-DLL_TESTS:BOOL=OFF Don't generate unit test projects
-DEXAMPLEPLUGIN:BOOL=OFF Don't generate example plugin project
-DDISABLE_TCMALLOC:BOOL=ON Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)
-DVISTA_ICON:BOOL=ON Allow pre-2008 VS to use vista-optimized resource file. (Requires updated rcdll.dll!)
Examples:
Set up a viewer-only project for your system:

View File

@@ -7,14 +7,15 @@ include(00-Common)
# OPENJPEG version number, useful for packaging and doxygen doc:
set(OPENJPEG_VERSION_MAJOR 1)
set(OPENJPEG_VERSION_MINOR 4)
set(OPENJPEG_VERSION_BUILD 0)
set(OPENJPEG_VERSION_MINOR 5)
set(OPENJPEG_VERSION_BUILD 2)
set(OPENJPEG_VERSION
"${OPENJPEG_VERSION_MAJOR}.${OPENJPEG_VERSION_MINOR}.${OPENJPEG_VERSION_BUILD}")
set(openjpeg_SOURCE_FILES
bio.c
cio.c
cidx_manager.c
dwt.c
event.c
image.c
@@ -26,20 +27,26 @@ set(openjpeg_SOURCE_FILES
mqc.c
openjpeg.c
pi.c
phix_manager.c
ppix_manager.c
raw.c
t1.c
t2.c
tcd.c
tgt.c
thix_manager.c
tpix_manager.c
)
set(openjpeg_HEADER_FILES
bio.h
cio.h
cidx_manager.h
dwt.h
event.h
event.h
fix.h
image.h
indexbox_manager.h
int.h
j2k.h
j2k_lib.h
@@ -48,6 +55,7 @@ set(openjpeg_HEADER_FILES
mct.h
mqc.h
openjpeg.h
opj_config.h
opj_includes.h
opj_malloc.h
pi.h

View File

@@ -0,0 +1,211 @@
/*
* $Id: cidx_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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_includes.h"
/*
* Write CPTR Codestream finder box
*
* @param[in] coff offset of j2k codestream
* @param[in] clen length of j2k codestream
* @param[in] cio file output handle
*/
void write_cptr(int coff, int clen, opj_cio_t *cio);
/*
* Write main header index table (box)
*
* @param[in] coff offset of j2k codestream
* @param[in] cstr_info codestream information
* @param[in] cio file output handle
* @return length of mainmhix box
*/
int write_mainmhix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio);
/*
* Check if EPH option is used
*
* @param[in] coff offset of j2k codestream
* @param[in] markers marker information
* @param[in] marknum number of markers
* @param[in] cio file output handle
* @return true if EPH is used
*/
opj_bool check_EPHuse( int coff, opj_marker_info_t *markers, int marknum, opj_cio_t *cio);
int write_cidx( int offset, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t cstr_info, int j2klen)
{
int len, i, lenp;
opj_jp2_box_t *box;
int num_box = 0;
opj_bool EPHused;
(void)image; /* unused ? */
lenp = -1;
box = (opj_jp2_box_t *)opj_calloc( 32, sizeof(opj_jp2_box_t));
for (i=0;i<2;i++){
if(i)
cio_seek( cio, lenp);
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_CIDX, 4); /* CIDX */
write_cptr( offset, cstr_info.codestream_size, cio);
write_manf( i, num_box, box, cio);
num_box = 0;
box[num_box].length = write_mainmhix( offset, cstr_info, cio);
box[num_box].type = JPIP_MHIX;
num_box++;
box[num_box].length = write_tpix( offset, cstr_info, j2klen, cio);
box[num_box].type = JPIP_TPIX;
num_box++;
box[num_box].length = write_thix( offset, cstr_info, cio);
box[num_box].type = JPIP_THIX;
num_box++;
EPHused = check_EPHuse( offset, cstr_info.marker, cstr_info.marknum, cio);
box[num_box].length = write_ppix( offset, cstr_info, EPHused, j2klen, cio);
box[num_box].type = JPIP_PPIX;
num_box++;
box[num_box].length = write_phix( offset, cstr_info, EPHused, j2klen, cio);
box[num_box].type = JPIP_PHIX;
num_box++;
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
}
opj_free( box);
return len;
}
void write_cptr(int coff, int clen, opj_cio_t *cio)
{
int len, lenp;
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_CPTR, 4); /* T */
cio_write( cio, 0, 2); /* DR A PRECISER !! */
cio_write( cio, 0, 2); /* CONT */
cio_write( cio, coff, 8); /* COFF A PRECISER !! */
cio_write( cio, clen, 8); /* CLEN */
len = cio_tell( cio) - lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
}
void write_manf(int second, int v, opj_jp2_box_t *box, opj_cio_t *cio)
{
int len, lenp, i;
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_MANF,4); /* T */
if (second){ /* Write only during the second pass */
for( i=0; i<v; i++){
cio_write( cio, box[i].length, 4); /* Box length */
cio_write( cio, box[i].type, 4); /* Box type */
}
}
len = cio_tell( cio) - lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
}
int write_mainmhix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio)
{
int i;
int len, lenp;
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_MHIX, 4); /* MHIX */
cio_write( cio, cstr_info.main_head_end-cstr_info.main_head_start+1, 8); /* TLEN */
for(i = 1; i < cstr_info.marknum; i++){ /* Marker restricted to 1 apparition, skip SOC marker */
cio_write( cio, cstr_info.marker[i].type, 2);
cio_write( cio, 0, 2);
cio_write( cio, cstr_info.marker[i].pos-coff, 8);
cio_write( cio, cstr_info.marker[i].len, 2);
}
len = cio_tell( cio) - lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
return len;
}
opj_bool check_EPHuse( int coff, opj_marker_info_t *markers, int marknum, opj_cio_t *cio)
{
opj_bool EPHused = OPJ_FALSE;
int i=0;
int org_pos;
unsigned int Scod;
for(i = 0; i < marknum; i++){
if( markers[i].type == J2K_MS_COD){
org_pos = cio_tell( cio);
cio_seek( cio, coff+markers[i].pos+2);
Scod = cio_read( cio, 1);
if( ((Scod >> 2) & 1))
EPHused = OPJ_TRUE;
cio_seek( cio, org_pos);
break;
}
}
return EPHused;
}

View File

@@ -0,0 +1,56 @@
/*
* $Id: cidx_manager.h 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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.
*/
/*! \file
* \brief Modification of jpip.h from 2KAN indexer
*/
#ifndef CIDX_MANAGER_H_
# define CIDX_MANAGER_H_
#include "openjpeg.h"
/*
* Write Codestream index box (superbox)
*
* @param[in] offset offset of j2k codestream
* @param[in] cio file output handle
* @param[in] image image data
* @param[in] cstr_info codestream information
* @param[in] j2klen length of j2k codestream
* @return length of cidx box
*/
int write_cidx( int offset, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t cstr_info, int j2klen);
#endif /* !CIDX_MANAGER_H_ */

View File

@@ -126,13 +126,13 @@ unsigned char *cio_getbp(opj_cio_t *cio) {
/*
* Write a byte.
*/
bool cio_byteout(opj_cio_t *cio, unsigned char v) {
opj_bool cio_byteout(opj_cio_t *cio, unsigned char v) {
if (cio->bp >= cio->end) {
opj_event_msg(cio->cinfo, EVT_ERROR, "write error\n");
return false;
return OPJ_FALSE;
}
*cio->bp++ = v;
return true;
return OPJ_TRUE;
}
/*
@@ -152,7 +152,7 @@ unsigned char cio_bytein(opj_cio_t *cio) {
* v : value to write
* n : number of bytes to write
*/
unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n) {
unsigned int cio_write(opj_cio_t *cio, unsigned int64 v, int n) {
int i;
for (i = n - 1; i >= 0; i--) {
if( !cio_byteout(cio, (unsigned char) ((v >> (i << 3)) & 0xff)) )

View File

@@ -31,6 +31,13 @@
#ifndef __CIO_H
#define __CIO_H
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define int64 __int64
#else
#define int64 long long
#endif
/**
@file cio.h
@brief Implementation of a byte input-output process (CIO)
@@ -63,7 +70,7 @@ Write some bytes
@param n Number of bytes to write
@return Returns the number of bytes written or 0 if an error occured
*/
unsigned int cio_write(opj_cio_t *cio, unsigned int v, int n);
unsigned int cio_write(opj_cio_t *cio, unsigned int64 v, int n);
/**
Read some bytes
@param cio CIO handle

View File

@@ -64,12 +64,12 @@ typedef struct v4dwt_local {
int cas ;
} v4dwt_t ;
static const float dwt_alpha = 1.586134342f; // 12994
static const float dwt_beta = 0.052980118f; // 434
static const float dwt_gamma = -0.882911075f; // -7233
static const float dwt_delta = -0.443506852f; // -3633
static const float dwt_alpha = 1.586134342f; /* 12994 */
static const float dwt_beta = 0.052980118f; /* 434 */
static const float dwt_gamma = -0.882911075f; /* -7233 */
static const float dwt_delta = -0.443506852f; /* -3633 */
static const float K = 1.230174105f; // 10078
static const float K = 1.230174105f; /* 10078 */
/* FIXME: What is this constant? */
static const float c13318 = 1.625732422f;
@@ -527,7 +527,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1
int w = tilec->x1 - tilec->x0;
h.mem = (int *)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
h.mem = (int*)opj_aligned_malloc(dwt_decode_max_resolution(tr, numres) * sizeof(int));
v.mem = h.mem;
while( --numres) {
@@ -570,7 +570,7 @@ static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, in
int count = w->sn;
int i, k;
for(k = 0; k < 2; ++k){
if (count + 3 * x < size && ((long) a & 0x0f) == 0 && ((long) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
if (count + 3 * x < size && ((size_t) a & 0x0f) == 0 && ((size_t) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
/* Fast code path */
for(i = 0; i < count; ++i){
int j = i;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Hervé Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,6 +26,42 @@
#include "opj_includes.h"
/* ==========================================================
Utility functions
==========================================================*/
#ifdef OPJ_CODE_NOT_USED
#ifndef _WIN32
static char*
i2a(unsigned i, char *a, unsigned r) {
if (i/r > 0) a = i2a(i/r,a,r);
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i%r];
return a+1;
}
/**
Transforms integer i into an ascii string and stores the result in a;
string is encoded in the base indicated by r.
@param i Number to be converted
@param a String result
@param r Base of value; must be in the range 2 - 36
@return Returns a
*/
static char *
_itoa(int i, char *a, int r) {
r = ((r < 2) || (r > 36)) ? 10 : r;
if(i < 0) {
*a = '-';
*i2a(-i, a+1, r) = 0;
}
else *i2a(i, a, r) = 0;
return a;
}
#endif /* !_WIN32 */
#endif
/* ----------------------------------------------------------------------- */
opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_mgr_t *event_mgr, void *context) {
if(cinfo) {
opj_event_mgr_t *previous = cinfo->event_mgr;
@@ -37,7 +73,7 @@ opj_event_mgr_t* OPJ_CALLCONV opj_set_event_mgr(opj_common_ptr cinfo, opj_event_
return NULL;
}
bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) {
opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) {
#define MSG_SIZE 512 /* 512 bytes should be more than enough for a short message */
opj_msg_callback msg_handler = NULL;
@@ -57,30 +93,29 @@ bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...) {
break;
}
if(msg_handler == NULL) {
return false;
return OPJ_FALSE;
}
} else {
return false;
return OPJ_FALSE;
}
if ((fmt != NULL) && (event_mgr != NULL)) {
va_list arg;
int str_length/*, i, j*/; /* UniPG */
char message[MSG_SIZE];
memset(message, 0, MSG_SIZE);
/* initialize the optional parameter list */
va_start(arg, fmt);
/* check the length of the format string */
str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt);
/* parse the format string and put the result in 'message' */
vsprintf(message, fmt, arg); /* UniPG */
str_length = vsnprintf(message, MSG_SIZE, fmt, arg); /* UniPG */
/* deinitialize the optional parameter list */
va_end(arg);
/* output the message to the user program */
msg_handler(message, cinfo->client_data);
if( str_length > -1 && str_length < MSG_SIZE )
msg_handler(message, cinfo->client_data);
else return OPJ_FALSE;
}
return true;
return OPJ_TRUE;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,7 @@ Write formatted data to a string and send the string to a user callback.
@param fmt Format-control string (plus optionnal arguments)
@return Returns true if successful, returns false otherwise
*/
bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...);
opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ...);
/* ----------------------------------------------------------------------- */
/*@}*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,6 @@
opj_image_t* opj_image_create0(void) {
opj_image_t *image = (opj_image_t*)opj_calloc(1, sizeof(opj_image_t));
image->comps=NULL;
return image;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@@ -0,0 +1,118 @@
/*
* $Id: indexbox_manager.h 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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.
*/
/*! \file
* \brief Modification of jpip.c from 2KAN indexer
*/
#ifndef INDEXBOX_MANAGER_H_
# define INDEXBOX_MANAGER_H_
#include "openjpeg.h"
#include "j2k.h" /* needed to use jp2.h */
#include "jp2.h"
#define JPIP_CIDX 0x63696478 /* Codestream index */
#define JPIP_CPTR 0x63707472 /* Codestream Finder Box */
#define JPIP_MANF 0x6d616e66 /* Manifest Box */
#define JPIP_FAIX 0x66616978 /* Fragment array Index box */
#define JPIP_MHIX 0x6d686978 /* Main Header Index Table */
#define JPIP_TPIX 0x74706978 /* Tile-part Index Table box */
#define JPIP_THIX 0x74686978 /* Tile header Index Table box */
#define JPIP_PPIX 0x70706978 /* Precinct Packet Index Table box */
#define JPIP_PHIX 0x70686978 /* Packet Header index Table */
#define JPIP_FIDX 0x66696478 /* File Index */
#define JPIP_FPTR 0x66707472 /* File Finder */
#define JPIP_PRXY 0x70727879 /* Proxy boxes */
#define JPIP_IPTR 0x69707472 /* Index finder box */
#define JPIP_PHLD 0x70686c64 /* Place holder */
/*
* Write tile-part Index table box (superbox)
*
* @param[in] coff offset of j2k codestream
* @param[in] cstr_info codestream information
* @param[in] j2klen length of j2k codestream
* @param[in] cio file output handle
* @return length of tpix box
*/
int write_tpix( int coff, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio);
/*
* Write tile header index table box (superbox)
*
* @param[in] coff offset of j2k codestream
* @param[in] cstr_info codestream information pointer
* @param[in] cio file output handle
* @return length of thix box
*/
int write_thix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio);
/*
* Write precinct packet index table box (superbox)
*
* @param[in] coff offset of j2k codestream
* @param[in] cstr_info codestream information
* @param[in] EPHused true if EPH option used
* @param[in] j2klen length of j2k codestream
* @param[in] cio file output handle
* @return length of ppix box
*/
int write_ppix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio);
/*
* Write packet header index table box (superbox)
*
* @param[in] coff offset of j2k codestream
* @param[in] cstr_info codestream information
* @param[in] EPHused true if EPH option used
* @param[in] j2klen length of j2k codestream
* @param[in] cio file output handle
* @return length of ppix box
*/
int write_phix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio);
/*
* Wriet manifest box (box)
*
* @param[in] second number to be visited
* @param[in] v number of boxes
* @param[in] box box to be manifested
* @param[in] cio file output handle
*/
void write_manf(int second, int v, opj_jp2_box_t *box, opj_cio_t *cio);
#endif /* !INDEXBOX_MANAGER_H_ */

View File

@@ -6,6 +6,7 @@
* Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2006-2007, Parvatha Elangovan
* Copyright (c) 2010-2011, Kaori Hagihara
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -228,6 +229,23 @@ Read an unknown marker
@param j2k J2K handle
*/
static void j2k_read_unk(opj_j2k_t *j2k);
/**
Add main header marker information
@param cstr_info Codestream information structure
@param type marker type
@param pos byte offset of marker segment
@param len length of marker segment
*/
static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len);
/**
Add tile header marker information
@param tileno tile index number
@param cstr_info Codestream information structure
@param type marker type
@param pos byte offset of marker segment
@param len length of marker segment
*/
static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len);
/*@}*/
@@ -258,80 +276,6 @@ char *j2k_convert_progression_order(OPJ_PROG_ORDER prg_order){
return po->str_prog;
}
void j2k_dump_image(FILE *fd, opj_image_t * img) {
int compno;
fprintf(fd, "image {\n");
fprintf(fd, " x0=%d, y0=%d, x1=%d, y1=%d\n", img->x0, img->y0, img->x1, img->y1);
fprintf(fd, " numcomps=%d\n", img->numcomps);
for (compno = 0; compno < img->numcomps; compno++) {
opj_image_comp_t *comp = &img->comps[compno];
fprintf(fd, " comp %d {\n", compno);
fprintf(fd, " dx=%d, dy=%d\n", comp->dx, comp->dy);
fprintf(fd, " prec=%d\n", comp->prec);
//fprintf(fd, " bpp=%d\n", comp->bpp);
fprintf(fd, " sgnd=%d\n", comp->sgnd);
fprintf(fd, " }\n");
}
fprintf(fd, "}\n");
}
void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp) {
int tileno, compno, layno, bandno, resno, numbands;
fprintf(fd, "coding parameters {\n");
fprintf(fd, " tx0=%d, ty0=%d\n", cp->tx0, cp->ty0);
fprintf(fd, " tdx=%d, tdy=%d\n", cp->tdx, cp->tdy);
fprintf(fd, " tw=%d, th=%d\n", cp->tw, cp->th);
for (tileno = 0; tileno < cp->tw * cp->th; tileno++) {
opj_tcp_t *tcp = &cp->tcps[tileno];
fprintf(fd, " tile %d {\n", tileno);
fprintf(fd, " csty=%x\n", tcp->csty);
fprintf(fd, " prg=%d\n", tcp->prg);
fprintf(fd, " numlayers=%d\n", tcp->numlayers);
fprintf(fd, " mct=%d\n", tcp->mct);
fprintf(fd, " rates=");
for (layno = 0; layno < tcp->numlayers; layno++) {
fprintf(fd, "%.1f ", tcp->rates[layno]);
}
fprintf(fd, "\n");
for (compno = 0; compno < img->numcomps; compno++) {
opj_tccp_t *tccp = &tcp->tccps[compno];
fprintf(fd, " comp %d {\n", compno);
fprintf(fd, " csty=%x\n", tccp->csty);
fprintf(fd, " numresolutions=%d\n", tccp->numresolutions);
fprintf(fd, " cblkw=%d\n", tccp->cblkw);
fprintf(fd, " cblkh=%d\n", tccp->cblkh);
fprintf(fd, " cblksty=%x\n", tccp->cblksty);
fprintf(fd, " qmfbid=%d\n", tccp->qmfbid);
fprintf(fd, " qntsty=%d\n", tccp->qntsty);
fprintf(fd, " numgbits=%d\n", tccp->numgbits);
fprintf(fd, " roishift=%d\n", tccp->roishift);
fprintf(fd, " stepsizes=");
numbands = tccp->qntsty == J2K_CCP_QNTSTY_SIQNT ? 1 : tccp->numresolutions * 3 - 2;
for (bandno = 0; bandno < numbands; bandno++) {
fprintf(fd, "(%d,%d) ", tccp->stepsizes[bandno].mant,
tccp->stepsizes[bandno].expn);
}
fprintf(fd, "\n");
if (tccp->csty & J2K_CCP_CSTY_PRT) {
fprintf(fd, " prcw=");
for (resno = 0; resno < tccp->numresolutions; resno++) {
fprintf(fd, "%d ", tccp->prcw[resno]);
}
fprintf(fd, "\n");
fprintf(fd, " prch=");
for (resno = 0; resno < tccp->numresolutions; resno++) {
fprintf(fd, "%d ", tccp->prch[resno]);
}
fprintf(fd, "\n");
}
fprintf(fd, " }\n");
}
fprintf(fd, " }\n");
}
fprintf(fd, "}\n");
}
/* ----------------------------------------------------------------------- */
static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){
char *prog;
@@ -371,6 +315,9 @@ static int j2k_get_num_tp(opj_cp_t *cp,int pino,int tileno){
/** mem allocation for TLM marker*/
int j2k_calculate_tp(opj_cp_t *cp,int img_numcomp,opj_image_t *image,opj_j2k_t *j2k ){
int pino,tileno,totnum_tp=0;
OPJ_ARG_NOT_USED(img_numcomp);
j2k->cur_totnum_tp = (int *) opj_malloc(cp->tw * cp->th * sizeof(int));
for (tileno = 0; tileno < cp->tw * cp->th; tileno++) {
int cur_totnum_tp = 0;
@@ -399,12 +346,14 @@ static void j2k_write_soc(opj_j2k_t *j2k) {
opj_cio_t *cio = j2k->cio;
cio_write(cio, J2K_MS_SOC, 2);
if(j2k->cstr_info)
j2k_add_mhmarker(j2k->cstr_info, J2K_MS_SOC, cio_tell(cio), 0);
/* UniPG>> */
#ifdef USE_JPWL
/* update markers struct */
j2k_add_marker(j2k->cstr_info, J2K_MS_SOC, cio_tell(cio) - 2, 2);
#endif /* USE_JPWL */
/* <<UniPG */
}
@@ -425,7 +374,7 @@ static void j2k_write_siz(opj_j2k_t *j2k) {
opj_cio_t *cio = j2k->cio;
opj_image_t *image = j2k->image;
opj_cp_t *cp = j2k->cp;
cio_write(cio, J2K_MS_SIZ, 2); /* SIZ */
lenp = cio_tell(cio);
cio_skip(cio, 2);
@@ -448,6 +397,9 @@ static void j2k_write_siz(opj_j2k_t *j2k) {
cio_seek(cio, lenp);
cio_write(cio, len, 2); /* Lsiz */
cio_seek(cio, lenp + len);
if(j2k->cstr_info)
j2k_add_mhmarker(j2k->cstr_info, J2K_MS_SIZ, lenp, len);
}
static void j2k_read_siz(opj_j2k_t *j2k) {
@@ -516,6 +468,12 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
}
#endif /* USE_JPWL */
/* prevent division by zero */
if (!(cp->tdx * cp->tdy)) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: invalid tile size (tdx: %d, tdy: %d)\n", cp->tdx, cp->tdy);
return;
}
image->comps = (opj_image_comp_t*) opj_calloc(image->numcomps, sizeof(opj_image_comp_t));
for (i = 0; i < image->numcomps; i++) {
int tmp, w, h;
@@ -554,6 +512,12 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
}
#endif /* USE_JPWL */
/* prevent division by zero */
if (!(image->comps[i].dx * image->comps[i].dy)) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: invalid component size (dx: %d, dy: %d)\n", image->comps[i].dx, image->comps[i].dy);
return;
}
/* TODO: unused ? */
w = int_ceildiv(image->x1 - image->x0, image->comps[i].dx);
h = int_ceildiv(image->y1 - image->y0, image->comps[i].dy);
@@ -606,7 +570,17 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
#endif /* USE_JPWL */
cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t));
if (cp->tcps == NULL)
{
opj_event_msg(j2k->cinfo, EVT_ERROR, "Out of memory\n");
return;
}
cp->tileno = (int*) opj_malloc(cp->tw * cp->th * sizeof(int));
if (cp->tileno == NULL)
{
opj_event_msg(j2k->cinfo, EVT_ERROR, "Out of memory\n");
return;
}
cp->tileno_size = 0;
#ifdef USE_JPWL
@@ -678,6 +652,11 @@ static void j2k_write_com(opj_j2k_t *j2k) {
cio_seek(cio, lenp);
cio_write(cio, len, 2);
cio_seek(cio, lenp + len);
if(j2k->cstr_info)
j2k_add_mhmarker(j2k->cstr_info, J2K_MS_COM, lenp, len);
}
}
@@ -721,12 +700,18 @@ static void j2k_read_cox(opj_j2k_t *j2k, int compno) {
tccp->numresolutions = cio_read(cio, 1) + 1; /* SPcox (D) */
// If user wants to remove more resolutions than the codestream contains, return error
/* If user wants to remove more resolutions than the codestream contains, return error*/
if (cp->reduce >= tccp->numresolutions) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions to remove is higher than the number "
"of resolutions of this component\nModify the cp_reduce parameter.\n\n", compno);
j2k->state |= J2K_STATE_ERR;
}
if( tccp->numresolutions > J2K_MAXRLVLS ) {
opj_event_msg(j2k->cinfo, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions is too big: %d vs max= %d. Truncating.\n\n",
compno, tccp->numresolutions, J2K_MAXRLVLS);
j2k->state |= J2K_STATE_ERR;
tccp->numresolutions = J2K_MAXRLVLS;
}
tccp->cblkw = cio_read(cio, 1) + 2; /* SPcox (E) */
tccp->cblkh = cio_read(cio, 1) + 2; /* SPcox (F) */
@@ -781,6 +766,10 @@ static void j2k_write_cod(opj_j2k_t *j2k) {
cio_seek(cio, lenp);
cio_write(cio, len, 2); /* Lcod */
cio_seek(cio, lenp + len);
if(j2k->cstr_info)
j2k_add_mhmarker(j2k->cstr_info, J2K_MS_COD, lenp, len);
}
static void j2k_read_cod(opj_j2k_t *j2k) {
@@ -846,6 +835,12 @@ static void j2k_read_coc(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lcoc */
compno = cio_read(cio, image->numcomps <= 256 ? 1 : 2); /* Ccoc */
if (compno >= image->numcomps) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad component number in COC (%d out of a maximum of %d)\n",
compno, image->numcomps);
return;
}
tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */
j2k_read_cox(j2k, compno);
}
@@ -909,6 +904,15 @@ static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) {
};
};
#else
/* We check whether there are too many subbands */
if ((numbands < 0) || (numbands >= J2K_MAXBANDS)) {
opj_event_msg(j2k->cinfo, EVT_WARNING ,
"bad number of subbands in Sqcx (%d) regarding to J2K_MAXBANDS (%d) \n"
"- limiting number of bands to J2K_MAXBANDS and try to move to the next markers\n", numbands, J2K_MAXBANDS);
}
#endif /* USE_JPWL */
for (bandno = 0; bandno < numbands; bandno++) {
@@ -921,8 +925,10 @@ static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) {
expn = tmp >> 11;
mant = tmp & 0x7ff;
}
tccp->stepsizes[bandno].expn = expn;
tccp->stepsizes[bandno].mant = mant;
if (bandno < J2K_MAXBANDS){
tccp->stepsizes[bandno].expn = expn;
tccp->stepsizes[bandno].mant = mant;
}
}
/* Add Antonin : if scalar_derived -> compute other stepsizes */
@@ -950,6 +956,9 @@ static void j2k_write_qcd(opj_j2k_t *j2k) {
cio_seek(cio, lenp);
cio_write(cio, len, 2); /* Lqcd */
cio_seek(cio, lenp + len);
if(j2k->cstr_info)
j2k_add_mhmarker(j2k->cstr_info, J2K_MS_QCD, lenp, len);
}
static void j2k_read_qcd(opj_j2k_t *j2k) {
@@ -986,7 +995,7 @@ static void j2k_read_qcc(opj_j2k_t *j2k) {
int len, compno;
int numcomp = j2k->image->numcomps;
opj_cio_t *cio = j2k->cio;
len = cio_read(cio, 2); /* Lqcc */
compno = cio_read(cio, numcomp <= 256 ? 1 : 2); /* Cqcc */
@@ -1013,9 +1022,16 @@ static void j2k_read_qcc(opj_j2k_t *j2k) {
/* keep your private count of tiles */
backup_compno++;
};
}
#endif /* USE_JPWL */
if ((compno < 0) || (compno >= numcomp)) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad component number in QCC (%d out of a maximum of %d)\n",
compno, j2k->image->numcomps);
return;
}
j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2));
}
@@ -1271,6 +1287,10 @@ static void j2k_write_sot(opj_j2k_t *j2k) {
j2k_add_marker(j2k->cstr_info, J2K_MS_SOT, j2k->sot_start, len + 2);
#endif /* USE_JPWL */
/* <<UniPG */
if( j2k->cstr_info && j2k->cur_tp_num==0){
j2k_add_tlmarker( j2k->curtileno, j2k->cstr_info, J2K_MS_SOT, lenp, len);
}
}
static void j2k_read_sot(opj_j2k_t *j2k) {
@@ -1354,6 +1374,11 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
partno = cio_read(cio, 1);
numparts = cio_read(cio, 1);
if (partno >= numparts) {
opj_event_msg(j2k->cinfo, EVT_WARNING, "SOT marker inconsistency in tile %d: tile-part index greater (%d) than number of tile-parts (%d)\n", tileno, partno, numparts);
numparts = partno+1;
}
j2k->curtileno = tileno;
j2k->cur_tp_num = partno;
@@ -1369,15 +1394,14 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
j2k->cstr_info->tile[tileno].tileno = tileno;
j2k->cstr_info->tile[tileno].start_pos = cio_tell(cio) - 12;
j2k->cstr_info->tile[tileno].end_pos = j2k->cstr_info->tile[tileno].start_pos + totlen - 1;
j2k->cstr_info->tile[tileno].num_tps = numparts;
if (numparts)
j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(numparts * sizeof(opj_tp_info_t));
else
j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_malloc(10 * sizeof(opj_tp_info_t)); // Fixme (10)
}
else {
} else {
j2k->cstr_info->tile[tileno].end_pos += totlen;
}
}
j2k->cstr_info->tile[tileno].num_tps = numparts;
if (numparts)
j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, numparts * sizeof(opj_tp_info_t));
else
j2k->cstr_info->tile[tileno].tp = (opj_tp_info_t *) opj_realloc(j2k->cstr_info->tile[tileno].tp, 10 * sizeof(opj_tp_info_t)); /* Fixme (10)*/
j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos = cio_tell(cio) - 12;
j2k->cstr_info->tile[tileno].tp[partno].tp_end_pos =
j2k->cstr_info->tile[tileno].tp[partno].tp_start_pos + totlen - 1;
@@ -1413,6 +1437,11 @@ static void j2k_write_sod(opj_j2k_t *j2k, void *tile_coder) {
tcd->cur_tp_num = j2k->cur_tp_num;
cio_write(cio, J2K_MS_SOD, 2);
if( j2k->cstr_info && j2k->cur_tp_num==0){
j2k_add_tlmarker( j2k->curtileno, j2k->cstr_info, J2K_MS_SOD, cio_tell(cio), 0);
}
if (j2k->curtileno == 0) {
j2k->sod_start = cio_tell(cio) + j2k->pos_correction;
}
@@ -1489,6 +1518,24 @@ static void j2k_read_sod(opj_j2k_t *j2k) {
truncate = 1; /* Case of a truncate codestream */
}
{/* chop padding bytes: */
unsigned char *s, *e;
s = cio_getbp(cio);
e = s + len;
if(len > 8) s = e - 8;
if(e[-2] == 0x00 && e[-1] == 0x00) /* padding bytes */
{
while(e > s)
{
if(e[-2] == 0xff && e[-1] == 0xd9) break;
--len; --e; truncate = 1;
}
}
}
data = j2k->tile_data[curtileno];
data = (unsigned char*) opj_realloc(data, (j2k->tile_len[curtileno] + len) * sizeof(unsigned char));
@@ -1548,6 +1595,13 @@ static void j2k_read_rgn(opj_j2k_t *j2k) {
};
#endif /* USE_JPWL */
if (compno >= numcomps) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"bad component number in RGN (%d out of a maximum of %d)\n",
compno, j2k->image->numcomps);
return;
}
tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */
}
@@ -1566,7 +1620,7 @@ static void j2k_write_eoc(opj_j2k_t *j2k) {
static void j2k_read_eoc(opj_j2k_t *j2k) {
int i, tileno;
bool success;
opj_bool success = OPJ_FALSE;
/* if packets should be decoded */
if (j2k->cp->limit_decoding != DECODE_ALL_BUT_PACKETS) {
@@ -1574,12 +1628,17 @@ static void j2k_read_eoc(opj_j2k_t *j2k) {
tcd_malloc_decode(tcd, j2k->image, j2k->cp);
for (i = 0; i < j2k->cp->tileno_size; i++) {
tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info);
tileno = j2k->cp->tileno[i];
success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info);
opj_free(j2k->tile_data[tileno]);
j2k->tile_data[tileno] = NULL;
tcd_free_decode_tile(tcd, i);
if (success == false) {
if (j2k->cp->tileno[i] != -1)
{
tileno = j2k->cp->tileno[i];
success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info);
opj_free(j2k->tile_data[tileno]);
j2k->tile_data[tileno] = NULL;
tcd_free_decode_tile(tcd, i);
}
else
success = OPJ_FALSE;
if (success == OPJ_FALSE) {
j2k->state |= J2K_STATE_ERR;
break;
}
@@ -1749,6 +1808,14 @@ void j2k_destroy_decompress(opj_j2k_t *j2k) {
opj_free(j2k->tile_len);
}
if(j2k->tile_data != NULL) {
if(j2k->cp != NULL) {
for (i = 0; i < j2k->cp->tileno_size; i++) {
int tileno = j2k->cp->tileno[i];
opj_free(j2k->tile_data[tileno]);
j2k->tile_data[tileno] = NULL;
}
}
opj_free(j2k->tile_data);
}
if(j2k->default_tcp != NULL) {
@@ -1834,7 +1901,7 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
if (j2k->cp->correct) {
int orig_pos = cio_tell(cio);
bool status;
opj_bool status;
/* call the corrector */
status = jpwl_correct(j2k);
@@ -1868,18 +1935,24 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
#endif /* USE_JPWL */
if (id >> 8 != 0xff) {
opj_image_destroy(image);
opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
return 0;
if(cio_numbytesleft(cio) != 0) /* not end of file reached and no EOC */
{
opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
opj_image_destroy(image);
return 0;
}
opj_event_msg(cinfo, EVT_WARNING, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
j2k->state = J2K_STATE_NEOC;
break;
}
e = j2k_dec_mstab_lookup(id);
// Check if the marker is known
/* Check if the marker is known*/
if (!(j2k->state & e->states)) {
opj_image_destroy(image);
opj_event_msg(cinfo, EVT_ERROR, "%.8x: unexpected marker %x\n", cio_tell(cio) - 2, id);
return 0;
}
// Check if the decoding is limited to the main header
/* Check if the decoding is limited to the main header*/
if (e->id == J2K_MS_SOT && j2k->cp->limit_decoding == LIMIT_TO_MAIN_HEADER) {
opj_event_msg(cinfo, EVT_INFO, "Main Header decoded.\n");
return image;
@@ -1889,7 +1962,10 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
(*e->handler)(j2k);
}
if (j2k->state & J2K_STATE_ERR)
{
opj_image_destroy(image);
return NULL;
}
if (j2k->state == J2K_STATE_MT) {
break;
@@ -1905,7 +1981,6 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
if (j2k->state != J2K_STATE_MT) {
opj_event_msg(cinfo, EVT_WARNING, "Incomplete bitstream\n");
}
return image;
}
@@ -1917,9 +1992,10 @@ opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestre
opj_image_t *image = NULL;
opj_jpt_msg_header_t header;
int position;
opj_common_ptr cinfo = j2k->cinfo;
OPJ_ARG_NOT_USED(cstr_info);
j2k->cio = cio;
/* create an empty image */
@@ -1961,9 +2037,15 @@ opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestre
id = cio_read(cio, 2);
if (id >> 8 != 0xff) {
opj_image_destroy(image);
opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
return 0;
if(cio_numbytesleft(cio) != 0) /* no end of file reached and no EOC */
{
opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
opj_image_destroy(image);
return 0;
}
opj_event_msg(cinfo, EVT_WARNING, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
j2k->state = J2K_STATE_NEOC;
break;
}
e = j2k_dec_mstab_lookup(id);
if (!(j2k->state & e->states)) {
@@ -2110,12 +2192,12 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_
int i;
/* set JPWL on */
cp->epc_on = true;
cp->info_on = false; /* no informative technique */
cp->epc_on = OPJ_TRUE;
cp->info_on = OPJ_FALSE; /* no informative technique */
/* set EPB on */
if ((parameters->jpwl_hprot_MH > 0) || (parameters->jpwl_hprot_TPH[0] > 0)) {
cp->epb_on = true;
cp->epb_on = OPJ_TRUE;
cp->hprot_MH = parameters->jpwl_hprot_MH;
for (i = 0; i < JPWL_MAX_NO_TILESPECS; i++) {
@@ -2136,7 +2218,7 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_
/* set ESD writing */
if ((parameters->jpwl_sens_size == 1) || (parameters->jpwl_sens_size == 2)) {
cp->esd_on = true;
cp->esd_on = OPJ_TRUE;
cp->sens_size = parameters->jpwl_sens_size;
cp->sens_addr = parameters->jpwl_sens_addr;
@@ -2150,10 +2232,10 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_
}
/* always set RED writing to false: we are at the encoder */
cp->red_on = false;
cp->red_on = OPJ_FALSE;
} else {
cp->epc_on = false;
cp->epc_on = OPJ_FALSE;
}
#endif /* USE_JPWL */
@@ -2226,10 +2308,10 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_
if(parameters->cp_cinema)
{
//Precinct size for lowest frequency subband=128
/*Precinct size for lowest frequency subband=128*/
tccp->prcw[0] = 7;
tccp->prch[0] = 7;
//Precinct size at all other resolutions = 256
/*Precinct size at all other resolutions = 256*/
for (j = 1; j < tccp->numresolutions; j++) {
tccp->prcw[j] = 8;
tccp->prch[j] = 8;
@@ -2271,7 +2353,7 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_
}
p++;
/*printf("\nsize precinct for level %d : %d,%d\n", j,tccp->prcw[j], tccp->prch[j]); */
} //end for
} /*end for*/
} else {
for (j = 0; j < tccp->numresolutions; j++) {
tccp->prcw[j] = 15;
@@ -2285,7 +2367,7 @@ void j2k_setup_encoder(opj_j2k_t *j2k, opj_cparameters_t *parameters, opj_image_
}
}
bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) {
opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) {
int tileno, compno;
opj_cp_t *cp = NULL;
@@ -2296,8 +2378,6 @@ bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestre
cp = j2k->cp;
/* j2k_dump_cp(stdout, image, cp); */
/* INDEX >> */
j2k->cstr_info = cstr_info;
if (cstr_info) {
@@ -2394,6 +2474,9 @@ bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestre
/* INDEX >> */
if(cstr_info) {
cstr_info->tile[j2k->curtileno].start_pos = cio_tell(cio) + j2k->pos_correction;
cstr_info->tile[j2k->curtileno].maxmarknum = 10;
cstr_info->tile[j2k->curtileno].marker = (opj_marker_info_t *) opj_malloc(cstr_info->tile[j2k->curtileno].maxmarknum * sizeof(opj_marker_info_t));
cstr_info->tile[j2k->curtileno].marknum = 0;
}
/* << INDEX */
@@ -2500,11 +2583,46 @@ bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestre
}
#endif /* USE_JPWL */
return true;
return OPJ_TRUE;
}
static void j2k_add_mhmarker(opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) {
if (!cstr_info)
return;
/* expand the list? */
if ((cstr_info->marknum + 1) > cstr_info->maxmarknum) {
cstr_info->maxmarknum = 100 + (int) ((float) cstr_info->maxmarknum * 1.0F);
cstr_info->marker = (opj_marker_info_t*)opj_realloc(cstr_info->marker, cstr_info->maxmarknum);
}
/* add the marker */
cstr_info->marker[cstr_info->marknum].type = type;
cstr_info->marker[cstr_info->marknum].pos = pos;
cstr_info->marker[cstr_info->marknum].len = len;
cstr_info->marknum++;
}
static void j2k_add_tlmarker( int tileno, opj_codestream_info_t *cstr_info, unsigned short int type, int pos, int len) {
opj_marker_info_t *marker;
if (!cstr_info)
return;
/* expand the list? */
if ((cstr_info->tile[tileno].marknum + 1) > cstr_info->tile[tileno].maxmarknum) {
cstr_info->tile[tileno].maxmarknum = 100 + (int) ((float) cstr_info->tile[tileno].maxmarknum * 1.0F);
cstr_info->tile[tileno].marker = (opj_marker_info_t*)opj_realloc(cstr_info->tile[tileno].marker, cstr_info->maxmarknum);
}
marker = &(cstr_info->tile[tileno].marker[cstr_info->tile[tileno].marknum]);
/* add the marker */
marker->type = type;
marker->pos = pos;
marker->len = len;
cstr_info->tile[tileno].marknum++;
}

View File

@@ -265,15 +265,15 @@ typedef struct opj_cp {
/* UniPG>> */
#ifdef USE_JPWL
/** enables writing of EPC in MH, thus activating JPWL */
bool epc_on;
opj_bool epc_on;
/** enables writing of EPB, in case of activated JPWL */
bool epb_on;
opj_bool epb_on;
/** enables writing of ESD, in case of activated JPWL */
bool esd_on;
opj_bool esd_on;
/** enables writing of informative techniques of ESD, in case of activated JPWL */
bool info_on;
opj_bool info_on;
/** enables writing of RED, in case of activated JPWL */
bool red_on;
opj_bool red_on;
/** error protection method for MH (0,1,16,32,37-128) */
int hprot_MH;
/** tile number of header protection specification (>=0) */
@@ -299,7 +299,7 @@ typedef struct opj_cp {
/** sensitivity methods for TPHs (-1,0-7) */
int sens_TPH[JPWL_MAX_NO_TILESPECS];
/** enables JPWL correction at the decoder */
bool correct;
opj_bool correct;
/** expected number of components at the decoder */
int exp_comps;
/** maximum number of tiles at the decoder */
@@ -436,10 +436,8 @@ Encode an image into a JPEG-2000 codestream
@param cstr_info Codestream information structure if required, NULL otherwise
@return Returns true if successful, returns false otherwise
*/
bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info);
opj_bool j2k_encode(opj_j2k_t *j2k, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info);
void j2k_dump_image(FILE *fd, opj_image_t * img);
void j2k_dump_cp(FILE *fd, opj_image_t * img, opj_cp_t * cp);
/* ----------------------------------------------------------------------- */
/*@}*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,18 +24,18 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/times.h>
#endif /* WIN32 */
#endif /* _WIN32 */
#include "opj_includes.h"
double opj_clock(void) {
#ifdef WIN32
/* WIN32: use QueryPerformance (very accurate) */
#ifdef _WIN32
/* _WIN32: use QueryPerformance (very accurate) */
LARGE_INTEGER freq , t ;
/* freq is the clock speed of the CPU */
QueryPerformanceFrequency(&freq) ;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

File diff suppressed because it is too large Load Diff

View File

@@ -46,11 +46,64 @@
#define JP2_COLR 0x636f6c72 /**< Colour specification box */
#define JP2_JP2C 0x6a703263 /**< Contiguous codestream box */
#define JP2_URL 0x75726c20 /**< URL box */
#define JP2_DBTL 0x6474626c /**< ??? */
#define JP2_DTBL 0x6474626c /**< Data Reference box */
#define JP2_BPCC 0x62706363 /**< Bits per component box */
#define JP2_JP2 0x6a703220 /**< File type fields */
#define JP2_PCLR 0x70636c72 /**< Palette box */
#define JP2_CMAP 0x636d6170 /**< Component Mapping box */
#define JP2_CDEF 0x63646566 /**< Channel Definition box */
/* ----------------------------------------------------------------------- */
/**
Channel description: channel index, type, assocation
*/
typedef struct opj_jp2_cdef_info
{
unsigned short cn, typ, asoc;
} opj_jp2_cdef_info_t;
/**
Channel descriptions and number of descriptions
*/
typedef struct opj_jp2_cdef
{
opj_jp2_cdef_info_t *info;
unsigned short n;
} opj_jp2_cdef_t;
/**
Component mappings: channel index, mapping type, palette index
*/
typedef struct opj_jp2_cmap_comp
{
unsigned short cmp;
unsigned char mtyp, pcol;
} opj_jp2_cmap_comp_t;
/**
Palette data: table entries, palette columns
*/
typedef struct opj_jp2_pclr
{
unsigned int *entries;
unsigned char *channel_sign;
unsigned char *channel_size;
opj_jp2_cmap_comp_t *cmap;
unsigned short nr_entries, nr_channels;
} opj_jp2_pclr_t;
/**
Collector for ICC profile, palette, component mapping, channel description
*/
typedef struct opj_jp2_color
{
unsigned char *icc_profile_buf;
int icc_profile_len;
opj_jp2_cdef_t *jp2_cdef;
opj_jp2_pclr_t *jp2_pclr;
unsigned char jp2_has_colr;
} opj_jp2_color_t;
/**
JP2 component
@@ -87,6 +140,8 @@ typedef struct opj_jp2 {
opj_jp2_comps_t *comps;
unsigned int j2k_codestream_offset;
unsigned int j2k_codestream_length;
opj_bool jpip_on;
opj_bool ignore_pclr_cmap_cdef;
} opj_jp2_t;
/**
@@ -111,9 +166,10 @@ void jp2_write_jp2h(opj_jp2_t *jp2, opj_cio_t *cio);
Read the JP2H box - JP2 Header box (used in MJ2)
@param jp2 JP2 handle
@param cio Input buffer stream
@param ext Collector for profile, cdef and pclr data
@return Returns true if successful, returns false otherwise
*/
bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio);
opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color);
/**
Creates a JP2 decompression structure
@param cinfo Codec context info
@@ -139,7 +195,7 @@ Decode an image from a JPEG-2000 file stream
@param cstr_info Codestream information structure if required, NULL otherwise
@return Returns a decoded image if successful, returns NULL otherwise
*/
opj_image_t* jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info);
opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio, opj_codestream_info_t *cstr_info);
/**
Creates a JP2 compression structure
@param cinfo Codec context info
@@ -167,7 +223,8 @@ Encode an image into a JPEG-2000 file stream
@param cstr_info Codestream information structure if required, NULL otherwise
@return Returns true if successful, returns false otherwise
*/
bool jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info);
opj_bool opj_jp2_encode(opj_jp2_t *jp2, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info);
/* ----------------------------------------------------------------------- */
/*@}*/

View File

@@ -521,22 +521,21 @@ void mqc_init_dec(opj_mqc_t *mqc, unsigned char *bp, int len) {
unsigned int c;
unsigned int *ip;
unsigned char *end = mqc->end - 1;
mqc->buffer = opj_realloc(mqc->buffer, (2 * len + 1) * sizeof(unsigned int));
mqc->buffer = opj_realloc(mqc->buffer, (len + 1) * sizeof(unsigned int));
ip = (unsigned int *) mqc->buffer;
while (bp != end) {
while (bp < end) {
c = *(bp + 1);
if (*bp == 0xff) {
if (c > 0x8f) {
*ip = 0x0000ff18;
break;
} else {
bp++;
*ip = 0x00000017 | (c << 9);
}
} else {
bp++;
*ip = 0x00000018 | (c << 8);
}
bp++;
ip++;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,17 +24,22 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
#endif /* WIN32 */
#endif /* _WIN32 */
#include "opj_config.h"
#include "opj_includes.h"
/* ---------------------------------------------------------------------- */
#ifdef WIN32
#ifdef _WIN32
#ifndef OPJ_STATIC
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
OPJ_ARG_NOT_USED(lpReserved);
OPJ_ARG_NOT_USED(hModule);
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH :
break;
@@ -48,19 +53,19 @@ DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
return TRUE;
}
#endif /* OPJ_STATIC */
#endif /* WIN32 */
#endif /* _WIN32 */
/* ---------------------------------------------------------------------- */
const char* OPJ_CALLCONV opj_version(void) {
return OPENJPEG_VERSION;
return PACKAGE_VERSION;
}
opj_dinfo_t* OPJ_CALLCONV opj_create_decompress(OPJ_CODEC_FORMAT format) {
opj_dinfo_t *dinfo = (opj_dinfo_t*)opj_calloc(1, sizeof(opj_dinfo_t));
if(!dinfo) return NULL;
dinfo->is_decompressor = true;
dinfo->is_decompressor = OPJ_TRUE;
switch(format) {
case CODEC_J2K:
case CODEC_JPT:
@@ -120,9 +125,10 @@ void OPJ_CALLCONV opj_set_default_decoder_parameters(opj_dparameters_t *paramete
parameters->decod_format = -1;
parameters->cod_format = -1;
parameters->flags = 0;
/* UniPG>> */
#ifdef USE_JPWL
parameters->jpwl_correct = false;
parameters->jpwl_correct = OPJ_FALSE;
parameters->jpwl_exp_comps = JPWL_EXPECTED_COMPONENTS;
parameters->jpwl_max_tiles = JPWL_MAXIMUM_TILES;
#endif /* USE_JPWL */
@@ -159,7 +165,7 @@ opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *ci
case CODEC_JPT:
return j2k_decode_jpt_stream((opj_j2k_t*)dinfo->j2k_handle, cio, cstr_info);
case CODEC_JP2:
return jp2_decode((opj_jp2_t*)dinfo->jp2_handle, cio, cstr_info);
return opj_jp2_decode((opj_jp2_t*)dinfo->jp2_handle, cio, cstr_info);
case CODEC_UNKNOWN:
default:
break;
@@ -171,7 +177,7 @@ opj_image_t* OPJ_CALLCONV opj_decode_with_info(opj_dinfo_t *dinfo, opj_cio_t *ci
opj_cinfo_t* OPJ_CALLCONV opj_create_compress(OPJ_CODEC_FORMAT format) {
opj_cinfo_t *cinfo = (opj_cinfo_t*)opj_calloc(1, sizeof(opj_cinfo_t));
if(!cinfo) return NULL;
cinfo->is_decompressor = false;
cinfo->is_decompressor = OPJ_FALSE;
switch(format) {
case CODEC_J2K:
/* get a J2K coder handle */
@@ -243,10 +249,10 @@ void OPJ_CALLCONV opj_set_default_encoder_parameters(opj_cparameters_t *paramete
parameters->cp_disto_alloc = 0;
parameters->cp_fixed_alloc = 0;
parameters->cp_fixed_quality = 0;
parameters->jpip_on = OPJ_FALSE;
/* UniPG>> */
#ifdef USE_JPWL
parameters->jpwl_epc_on = false;
parameters->jpwl_epc_on = OPJ_FALSE;
parameters->jpwl_hprot_MH = -1; /* -1 means unassigned */
{
int i;
@@ -296,7 +302,7 @@ void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *param
}
}
bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index) {
opj_bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index) {
if (index != NULL)
opj_event_msg((opj_common_ptr)cinfo, EVT_WARNING, "Set index to NULL when calling the opj_encode function.\n"
"To extract the index, use the opj_encode_with_info() function.\n"
@@ -304,20 +310,20 @@ bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *im
return opj_encode_with_info(cinfo, cio, image, NULL);
}
bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) {
opj_bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info) {
if(cinfo && cio && image) {
switch(cinfo->codec_format) {
case CODEC_J2K:
return j2k_encode((opj_j2k_t*)cinfo->j2k_handle, cio, image, cstr_info);
case CODEC_JP2:
return jp2_encode((opj_jp2_t*)cinfo->jp2_handle, cio, image, cstr_info);
return opj_jp2_encode((opj_jp2_t*)cinfo->jp2_handle, cio, image, cstr_info);
case CODEC_JPT:
case CODEC_UNKNOWN:
default:
break;
}
}
return false;
return OPJ_FALSE;
}
void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) {
@@ -328,6 +334,7 @@ void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info) {
opj_free(tile_info->thresh);
opj_free(tile_info->packet);
opj_free(tile_info->tp);
opj_free(tile_info->marker);
}
opj_free(cstr_info->tile);
opj_free(cstr_info->marker);

View File

@@ -6,6 +6,7 @@
* Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2006-2007, Parvatha Elangovan
* Copyright (c) 2010-2011, Kaori Hagihara
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,7 +33,6 @@
#ifndef OPENJPEG_H
#define OPENJPEG_H
#define OPENJPEG_VERSION "1.4.0.635"
/*
==========================================================
@@ -40,7 +40,7 @@
==========================================================
*/
#if defined(OPJ_STATIC) || !(defined(WIN32) || defined(__WIN32__))
#if defined(OPJ_STATIC) || !defined(_WIN32)
#define OPJ_API
#define OPJ_CALLCONV
#else
@@ -53,38 +53,19 @@ that uses this DLL. This way any other project whose source files include this f
OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols
defined with this macro as being exported.
*/
#ifdef OPJ_EXPORTS
#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT)
#define OPJ_API __declspec(dllexport)
#else
#define OPJ_API __declspec(dllimport)
#endif /* OPJ_EXPORTS */
#endif /* !OPJ_STATIC || !WIN32 */
#endif /* !OPJ_STATIC || !_WIN32 */
#ifndef __cplusplus
#if defined(HAVE_STDBOOL_H)
/*
The C language implementation does correctly provide the standard header
file "stdbool.h".
*/
#include <stdbool.h>
#else
/*
The C language implementation does not provide the standard header file
"stdbool.h" as required by ISO/IEC 9899:1999. Try to compensate for this
braindamage below.
*/
#if !defined(bool)
#define bool int
#endif
#if !defined(true)
#define true 1
#endif
#if !defined(false)
#define false 0
#endif
#endif
#endif /* __cplusplus */
typedef int opj_bool;
#define OPJ_TRUE 1
#define OPJ_FALSE 0
/* Avoid compile-time warning because parameter is not used */
#define OPJ_ARG_NOT_USED(x) (void)(x)
/*
==========================================================
Useful constant definitions
@@ -154,14 +135,18 @@ typedef enum COLOR_SPACE {
CLRSPC_SYCC = 3 /**< YUV */
} OPJ_COLOR_SPACE;
#define ENUMCS_SRGB 16
#define ENUMCS_GRAY 17
#define ENUMCS_SYCC 18
/**
Supported codec
*/
typedef enum CODEC_FORMAT {
CODEC_UNKNOWN = -1, /**< place-holder */
CODEC_J2K = 0, /**< JPEG-2000 codestream : read/write */
CODEC_JPT = 1, /**< JPT-stream (JPEG 2000, JPIP) : read only */
CODEC_JP2 = 2 /**< JPEG-2000 file format : read/write */
CODEC_J2K = 0, /**< JPEG-2000 codestream : read/write */
CODEC_JPT = 1, /**< JPT-stream (JPEG 2000, JPIP) : read only */
CODEC_JP2 = 2 /**< JPEG-2000 file format : read/write */
} OPJ_CODEC_FORMAT;
/**
@@ -244,7 +229,7 @@ Compression parameters
*/
typedef struct opj_cparameters {
/** size of tile: tile_size_on = false (not in argument) or = true (in argument) */
bool tile_size_on;
opj_bool tile_size_on;
/** XTOsiz */
int cp_tx0;
/** YTOsiz */
@@ -326,7 +311,7 @@ typedef struct opj_cparameters {
/**@name JPWL encoding parameters */
/*@{*/
/** enables writing of EPC in MH, thus activating JPWL */
bool jpwl_epc_on;
opj_bool jpwl_epc_on;
/** error protection method for MH (0,1,16,32,37-128) */
int jpwl_hprot_MH;
/** tile number of header protection specification (>=0) */
@@ -366,8 +351,12 @@ typedef struct opj_cparameters {
char tp_flag;
/** MCT (multiple component transform) */
char tcp_mct;
/** Enable JPIP indexing*/
opj_bool jpip_on;
} opj_cparameters_t;
#define OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG 0x0001
/**
Decompression parameters
*/
@@ -404,7 +393,7 @@ typedef struct opj_dparameters {
/**@name JPWL decoding parameters */
/*@{*/
/** activates the JPWL correction capabilities */
bool jpwl_correct;
opj_bool jpwl_correct;
/** expected number of components */
int jpwl_exp_comps;
/** maximum number of tiles */
@@ -420,6 +409,7 @@ typedef struct opj_dparameters {
*/
OPJ_LIMIT_DECODING cp_limit_decoding;
unsigned int flags;
} opj_dparameters_t;
/** Common fields between JPEG-2000 compression and decompression master structs. */
@@ -427,7 +417,7 @@ typedef struct opj_dparameters {
#define opj_common_fields \
opj_event_mgr_t *event_mgr; /**< pointer to the event manager */\
void * client_data; /**< Available for use by application */\
bool is_decompressor; /**< So common code can tell which is which */\
opj_bool is_decompressor; /**< So common code can tell which is which */\
OPJ_CODEC_FORMAT codec_format; /**< selected codec */\
void *j2k_handle; /**< pointer to the J2K codec */\
void *jp2_handle; /**< pointer to the JP2 codec */\
@@ -555,6 +545,10 @@ typedef struct opj_image {
OPJ_COLOR_SPACE color_space;
/** image components */
opj_image_comp_t *comps;
/** 'restricted' ICC profile */
unsigned char *icc_profile_buf;
/** size of ICC profile */
int icc_profile_len;
} opj_image_t;
/**
@@ -601,6 +595,21 @@ typedef struct opj_packet_info {
double disto;
} opj_packet_info_t;
/* UniPG>> */
/**
Marker structure
*/
typedef struct opj_marker_info_t {
/** marker type */
unsigned short int type;
/** position in codestream */
int pos;
/** length, marker val included */
int len;
} opj_marker_info_t;
/* <<UniPG */
/**
Index structure : Information concerning tile-parts
*/
@@ -645,26 +654,18 @@ typedef struct opj_tile_info {
int numpix;
/** add fixed_quality */
double distotile;
/** number of markers */
int marknum;
/** list of markers */
opj_marker_info_t *marker;
/** actual size of markers array */
int maxmarknum;
/** number of tile parts */
int num_tps;
/** information concerning tile parts */
opj_tp_info_t *tp;
} opj_tile_info_t;
/* UniPG>> */
/**
Marker structure
*/
typedef struct opj_marker_info_t {
/** marker type */
unsigned short int type;
/** position in codestream */
int pos;
/** length, marker val included */
int len;
} opj_marker_info_t;
/* <<UniPG */
/**
Index structure of the codestream
*/
@@ -883,13 +884,13 @@ Setup the encoder parameters using the current image and using user parameters.
OPJ_API void OPJ_CALLCONV opj_setup_encoder(opj_cinfo_t *cinfo, opj_cparameters_t *parameters, opj_image_t *image);
/**
Encode an image into a JPEG-2000 codestream
@param cinfo compressor handle
3@param cinfo compressor handle
@param cio Output buffer stream
@param image Image to encode
@param index Depreacted -> Set to NULL. To extract index, used opj_encode_wci()
@return Returns true if successful, returns false otherwise
*/
OPJ_API bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index);
OPJ_API opj_bool OPJ_CALLCONV opj_encode(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, char *index);
/**
Encode an image into a JPEG-2000 codestream and extract the codestream information
@param cinfo compressor handle
@@ -898,13 +899,14 @@ Encode an image into a JPEG-2000 codestream and extract the codestream informati
@param cstr_info Codestream information structure if needed afterwards, NULL otherwise
@return Returns true if successful, returns false otherwise
*/
OPJ_API bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info);
OPJ_API opj_bool OPJ_CALLCONV opj_encode_with_info(opj_cinfo_t *cinfo, opj_cio_t *cio, opj_image_t *image, opj_codestream_info_t *cstr_info);
/**
Destroy Codestream information after compression or decompression
@param cstr_info Codestream information structure
*/
OPJ_API void OPJ_CALLCONV opj_destroy_cstr_info(opj_codestream_info_t *cstr_info);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,36 @@
/* create config.h for CMake */
#define PACKAGE_VERSION "1.5.2"
#define HAVE_INTTYPES_H
#define HAVE_MEMORY_H
#define HAVE_STDINT_H
#define HAVE_STDLIB_H
#define HAVE_STRINGS_H
#define HAVE_STRING_H
#define HAVE_SYS_STAT_H
#define HAVE_SYS_TYPES_H
#define HAVE_UNISTD_H
/* #define HAVE_LIBPNG */
/* #define HAVE_PNG_H */
/* #define HAVE_LIBTIFF */
/* #define HAVE_TIFF_H */
/* #undef HAVE_LIBLCMS1 */
/* #undef HAVE_LIBLCMS2 */
/* #undef HAVE_LCMS1_H */
/* #undef HAVE_LCMS2_H */
/* Byte order. */
/* All compilers that support Mac OS X define either __BIG_ENDIAN__ or
* __LITTLE_ENDIAN__ to match the endianness of the architecture being
* compiled for. This is not necessarily the same as the architecture of the
* machine doing the building. In order to support Universal Binaries on
* Mac OS X, we prefer those defines to decide the endianness.
* On other platforms we use the result of the TRY_RUN. */
#if !defined(__APPLE__)
/* #undef OPJ_BIG_ENDIAN */
#elif defined(__BIG_ENDIAN__)
# define OPJ_BIG_ENDIAN
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,20 +89,25 @@ Most compilers implement their own version of this keyword ...
/* MSVC and Borland C do not have lrintf */
#if defined(_MSC_VER) || defined(__BORLANDC__)
static INLINE long lrintf(float f){
int i;
_asm{
fld f
fistp i
};
return i;
#ifdef _M_X64
return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f));
#else
int i;
_asm{
fld f
fistp i
};
return i;
#endif
}
#endif
#include "j2k_lib.h"
#include "opj_malloc.h"
#include "event.h"
#include "bio.h"
#include "cio.h"
#include "image.h"
@@ -123,9 +128,12 @@ static INLINE long lrintf(float f){
#include "int.h"
#include "fix.h"
#include "cidx_manager.h"
#include "indexbox_manager.h"
/* JPWL>> */
#ifdef USE_JPWL
#include "../jpwl/jpwl.h"
#include "./jpwl/jpwl.h"
#endif /* USE_JPWL */
/* <<JPWL */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, Herv<EFBFBD> Drolon, FreeImage Team
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2007, Callum Lerwick <seg@haxxed.com>
* All rights reserved.
*
@@ -69,7 +69,7 @@ Allocate memory aligned to a 16 byte boundry
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
*/
/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
#ifdef WIN32
#ifdef _WIN32
/* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
#ifdef __GNUC__
#include <mm_malloc.h>
@@ -80,11 +80,13 @@ Allocate memory aligned to a 16 byte boundry
#define HAVE_MM_MALLOC
#endif
#endif
#else /* Not WIN32 */
#else /* Not _WIN32 */
#if defined(__sun)
#define HAVE_MEMALIGN
#elif defined(__FreeBSD__)
#define HAVE_POSIX_MEMALIGN
/* Linux x86_64 and OSX always align allocations to 16 bytes */
#elif !defined(__amd64__) && !defined(__APPLE__)
#elif !defined(__amd64__) && !defined(__APPLE__) && !defined(_AIX)
#define HAVE_MEMALIGN
#include <malloc.h>
#endif
@@ -130,22 +132,22 @@ Allocate memory aligned to a 16 byte boundry
/**
Reallocate memory blocks.
@param memblock Pointer to previously allocated memory block
@param size New size in bytes
@param m Pointer to previously allocated memory block
@param s New size in bytes
@return Returns a void pointer to the reallocated (and possibly moved) memory block
*/
#ifdef ALLOC_PERF_OPT
void * OPJ_CALLCONV opj_realloc(void * _Memory, size_t NewSize);
void * OPJ_CALLCONV opj_realloc(void * m, size_t s);
#else
#define opj_realloc(m, s) realloc(m, s)
#endif
/**
Deallocates or frees a memory block.
@param memblock Previously allocated memory block to be freed
@param m Previously allocated memory block to be freed
*/
#ifdef ALLOC_PERF_OPT
void OPJ_CALLCONV opj_free(void * _Memory);
void OPJ_CALLCONV opj_free(void * m);
#else
#define opj_free(m) free(m)
#endif

View File

@@ -0,0 +1,170 @@
/*
* $Id: phix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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.
*/
/*! \file
* \brief Modification of jpip.c from 2KAN indexer
*/
#include <stdlib.h>
#include <math.h>
#include "opj_includes.h"
/*
* Write faix box of phix
*
* @param[in] coff offset of j2k codestream
* @param[in] compno component number
* @param[in] cstr_info codestream information
* @param[in] EPHused true if if EPH option used
* @param[in] j2klen length of j2k codestream
* @param[in] cio file output handle
* @return length of faix box
*/
int write_phixfaix( int coff, int compno, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio);
int write_phix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio)
{
int len, lenp=0, compno, i;
opj_jp2_box_t *box;
box = (opj_jp2_box_t *)opj_calloc( cstr_info.numcomps, sizeof(opj_jp2_box_t));
for( i=0;i<2;i++){
if (i) cio_seek( cio, lenp);
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_PHIX, 4); /* PHIX */
write_manf( i, cstr_info.numcomps, box, cio);
for( compno=0; compno<cstr_info.numcomps; compno++){
box[compno].length = write_phixfaix( coff, compno, cstr_info, EPHused, j2klen, cio);
box[compno].type = JPIP_FAIX;
}
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
}
opj_free(box);
return len;
}
int write_phixfaix( int coff, int compno, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio)
{
int len, lenp, tileno, version, i, nmax, size_of_coding; /* 4 or 8 */
opj_tile_info_t *tile_Idx;
opj_packet_info_t packet;
int resno, precno, layno, num_packet;
int numOfres, numOfprec, numOflayers;
packet.end_ph_pos = packet.start_pos = -1;
(void)EPHused; /* unused ? */
if( j2klen > pow( 2.0, 32)){
size_of_coding = 8;
version = 1;
}
else{
size_of_coding = 4;
version = 0;
}
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_FAIX, 4); /* FAIX */
cio_write( cio, version,1); /* Version 0 = 4 bytes */
nmax = 0;
for( i=0; i<=cstr_info.numdecompos[compno]; i++)
nmax += cstr_info.tile[0].ph[i] * cstr_info.tile[0].pw[i] * cstr_info.numlayers;
cio_write( cio, nmax, size_of_coding); /* NMAX */
cio_write( cio, cstr_info.tw*cstr_info.th, size_of_coding); /* M */
for( tileno=0; tileno<cstr_info.tw*cstr_info.th; tileno++){
tile_Idx = &cstr_info.tile[ tileno];
num_packet = 0;
numOfres = cstr_info.numdecompos[compno] + 1;
for( resno=0; resno<numOfres ; resno++){
numOfprec = tile_Idx->pw[resno]*tile_Idx->ph[resno];
for( precno=0; precno<numOfprec; precno++){
numOflayers = cstr_info.numlayers;
for( layno=0; layno<numOflayers; layno++){
switch ( cstr_info.prog){
case LRCP:
packet = tile_Idx->packet[ ((layno*numOfres+resno)*cstr_info.numcomps+compno)*numOfprec+precno];
break;
case RLCP:
packet = tile_Idx->packet[ ((resno*numOflayers+layno)*cstr_info.numcomps+compno)*numOfprec+precno];
break;
case RPCL:
packet = tile_Idx->packet[ ((resno*numOfprec+precno)*cstr_info.numcomps+compno)*numOflayers+layno];
break;
case PCRL:
packet = tile_Idx->packet[ ((precno*cstr_info.numcomps+compno)*numOfres+resno)*numOflayers + layno];
break;
case CPRL:
packet = tile_Idx->packet[ ((compno*numOfprec+precno)*numOfres+resno)*numOflayers + layno];
break;
default:
fprintf( stderr, "failed to ppix indexing\n");
}
cio_write( cio, packet.start_pos-coff, size_of_coding); /* start position */
cio_write( cio, packet.end_ph_pos-packet.start_pos+1, size_of_coding); /* length */
num_packet++;
}
}
}
/* PADDING */
while( num_packet < nmax){
cio_write( cio, 0, size_of_coding); /* start position */
cio_write( cio, 0, size_of_coding); /* length */
num_packet++;
}
}
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
return len;
}

View File

@@ -43,31 +43,31 @@ Get next packet in layer-resolution-component-precinct order.
@param pi packet iterator to modify
@return returns false if pi pointed to the last packet or else returns true
*/
static bool pi_next_lrcp(opj_pi_iterator_t * pi);
static opj_bool pi_next_lrcp(opj_pi_iterator_t * pi);
/**
Get next packet in resolution-layer-component-precinct order.
@param pi packet iterator to modify
@return returns false if pi pointed to the last packet or else returns true
*/
static bool pi_next_rlcp(opj_pi_iterator_t * pi);
static opj_bool pi_next_rlcp(opj_pi_iterator_t * pi);
/**
Get next packet in resolution-precinct-component-layer order.
@param pi packet iterator to modify
@return returns false if pi pointed to the last packet or else returns true
*/
static bool pi_next_rpcl(opj_pi_iterator_t * pi);
static opj_bool pi_next_rpcl(opj_pi_iterator_t * pi);
/**
Get next packet in precinct-component-resolution-layer order.
@param pi packet iterator to modify
@return returns false if pi pointed to the last packet or else returns true
*/
static bool pi_next_pcrl(opj_pi_iterator_t * pi);
static opj_bool pi_next_pcrl(opj_pi_iterator_t * pi);
/**
Get next packet in component-precinct-resolution-layer order.
@param pi packet iterator to modify
@return returns false if pi pointed to the last packet or else returns true
*/
static bool pi_next_cprl(opj_pi_iterator_t * pi);
static opj_bool pi_next_cprl(opj_pi_iterator_t * pi);
/*@}*/
@@ -79,7 +79,7 @@ static bool pi_next_cprl(opj_pi_iterator_t * pi);
==========================================================
*/
static bool pi_next_lrcp(opj_pi_iterator_t * pi) {
static opj_bool pi_next_lrcp(opj_pi_iterator_t * pi) {
opj_pi_comp_t *comp = NULL;
opj_pi_resolution_t *res = NULL;
long index = 0;
@@ -108,7 +108,7 @@ static bool pi_next_lrcp(opj_pi_iterator_t * pi) {
index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p;
if (!pi->include[index]) {
pi->include[index] = 1;
return true;
return OPJ_TRUE;
}
LABEL_SKIP:;
}
@@ -116,10 +116,10 @@ LABEL_SKIP:;
}
}
return false;
return OPJ_FALSE;
}
static bool pi_next_rlcp(opj_pi_iterator_t * pi) {
static opj_bool pi_next_rlcp(opj_pi_iterator_t * pi) {
opj_pi_comp_t *comp = NULL;
opj_pi_resolution_t *res = NULL;
long index = 0;
@@ -147,7 +147,7 @@ static bool pi_next_rlcp(opj_pi_iterator_t * pi) {
index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p;
if (!pi->include[index]) {
pi->include[index] = 1;
return true;
return OPJ_TRUE;
}
LABEL_SKIP:;
}
@@ -155,10 +155,10 @@ LABEL_SKIP:;
}
}
return false;
return OPJ_FALSE;
}
static bool pi_next_rpcl(opj_pi_iterator_t * pi) {
static opj_bool pi_next_rpcl(opj_pi_iterator_t * pi) {
opj_pi_comp_t *comp = NULL;
opj_pi_resolution_t *res = NULL;
long index = 0;
@@ -229,7 +229,7 @@ if (!pi->tp_on){
index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p;
if (!pi->include[index]) {
pi->include[index] = 1;
return true;
return OPJ_TRUE;
}
LABEL_SKIP:;
}
@@ -238,10 +238,10 @@ LABEL_SKIP:;
}
}
return false;
return OPJ_FALSE;
}
static bool pi_next_pcrl(opj_pi_iterator_t * pi) {
static opj_bool pi_next_pcrl(opj_pi_iterator_t * pi) {
opj_pi_comp_t *comp = NULL;
opj_pi_resolution_t *res = NULL;
long index = 0;
@@ -310,7 +310,7 @@ static bool pi_next_pcrl(opj_pi_iterator_t * pi) {
index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p;
if (!pi->include[index]) {
pi->include[index] = 1;
return true;
return OPJ_TRUE;
}
LABEL_SKIP:;
}
@@ -319,10 +319,10 @@ LABEL_SKIP:;
}
}
return false;
return OPJ_FALSE;
}
static bool pi_next_cprl(opj_pi_iterator_t * pi) {
static opj_bool pi_next_cprl(opj_pi_iterator_t * pi) {
opj_pi_comp_t *comp = NULL;
opj_pi_resolution_t *res = NULL;
long index = 0;
@@ -389,7 +389,7 @@ static bool pi_next_cprl(opj_pi_iterator_t * pi) {
index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno * pi->step_c + pi->precno * pi->step_p;
if (!pi->include[index]) {
pi->include[index] = 1;
return true;
return OPJ_TRUE;
}
LABEL_SKIP:;
}
@@ -398,7 +398,7 @@ LABEL_SKIP:;
}
}
return false;
return OPJ_FALSE;
}
/*
@@ -707,7 +707,7 @@ void pi_destroy(opj_pi_iterator_t *pi, opj_cp_t *cp, int tileno) {
}
}
bool pi_next(opj_pi_iterator_t * pi) {
opj_bool pi_next(opj_pi_iterator_t * pi) {
switch (pi->poc.prg) {
case LRCP:
return pi_next_lrcp(pi);
@@ -720,13 +720,13 @@ bool pi_next(opj_pi_iterator_t * pi) {
case CPRL:
return pi_next_cprl(pi);
case PROG_UNKNOWN:
return false;
return OPJ_FALSE;
}
return false;
return OPJ_FALSE;
}
bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp){
opj_bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp){
char prog[4];
int i;
int incr_top=1,resetX=0;
@@ -748,7 +748,7 @@ bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,
case RPCL: strncpy(prog, "RPCL",4);
break;
case PROG_UNKNOWN:
return true;
return OPJ_TRUE;
}
if(!(cp->tp_on && ((!cp->cinema && (t2_mode == FINAL_PASS)) || cp->cinema))){
@@ -958,6 +958,6 @@ bool pi_create_encode( opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,
}
}
}
return false;
return OPJ_FALSE;
}

View File

@@ -115,12 +115,14 @@ Modify the packet iterator for enabling tile part generation
@param pi Handle to the packet iterator generated in pi_initialise_encode
@param cp Coding parameters
@param tileno Number that identifies the tile for which to list the packets
@param pino Iterator index for pi
@param tpnum Tile part number of the current tile
@param tppos The position of the tile part flag in the progression order
@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass
@param cur_totnum_tp The total number of tile parts in the current tile
@return Returns true if an error is detected
*/
bool pi_create_encode(opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp);
opj_bool pi_create_encode(opj_pi_iterator_t *pi, opj_cp_t *cp,int tileno, int pino,int tpnum, int tppos, J2K_T2_MODE t2_mode,int cur_totnum_tp);
/**
Create a packet iterator for Decoder
@param image Raw image for which the packets will be listed
@@ -145,7 +147,7 @@ Modify the packet iterator to point to the next packet
@param pi Packet iterator to modify
@return Returns false if pi pointed to the last packet or else returns true
*/
bool pi_next(opj_pi_iterator_t * pi);
opj_bool pi_next(opj_pi_iterator_t * pi);
/* ----------------------------------------------------------------------- */
/*@}*/

View File

@@ -0,0 +1,173 @@
/*
* $Id: ppix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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.
*/
/*! \file
* \brief Modification of jpip.c from 2KAN indexer
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "opj_includes.h"
/*
* Write faix box of ppix
*
* @param[in] coff offset of j2k codestream
* @param[in] compno component number
* @param[in] cstr_info codestream information
* @param[in] EPHused true if if EPH option used
* @param[in] j2klen length of j2k codestream
* @param[in] cio file output handle
* @return length of faix box
*/
int write_ppixfaix( int coff, int compno, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio);
int write_ppix( int coff, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio)
{
int len, lenp, compno, i;
opj_jp2_box_t *box;
/* printf("cstr_info.packno %d\n", cstr_info.packno); //NMAX? */
lenp = -1;
box = (opj_jp2_box_t *)opj_calloc( cstr_info.numcomps, sizeof(opj_jp2_box_t));
for (i=0;i<2;i++){
if (i) cio_seek( cio, lenp);
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_PPIX, 4); /* PPIX */
write_manf( i, cstr_info.numcomps, box, cio);
for (compno=0; compno<cstr_info.numcomps; compno++){
box[compno].length = write_ppixfaix( coff, compno, cstr_info, EPHused, j2klen, cio);
box[compno].type = JPIP_FAIX;
}
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
}
opj_free(box);
return len;
}
int write_ppixfaix( int coff, int compno, opj_codestream_info_t cstr_info, opj_bool EPHused, int j2klen, opj_cio_t *cio)
{
int len, lenp, tileno, version, i, nmax, size_of_coding; /* 4 or 8*/
opj_tile_info_t *tile_Idx;
opj_packet_info_t packet;
int resno, precno, layno, num_packet;
int numOfres, numOfprec, numOflayers;
packet.end_pos = packet.end_ph_pos = packet.start_pos = -1;
(void)EPHused; /* unused ? */
if( j2klen > pow( 2.0, 32)){
size_of_coding = 8;
version = 1;
}
else{
size_of_coding = 4;
version = 0;
}
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_FAIX, 4); /* FAIX */
cio_write( cio, version, 1); /* Version 0 = 4 bytes */
nmax = 0;
for( i=0; i<=cstr_info.numdecompos[compno]; i++)
nmax += cstr_info.tile[0].ph[i] * cstr_info.tile[0].pw[i] * cstr_info.numlayers;
cio_write( cio, nmax, size_of_coding); /* NMAX */
cio_write( cio, cstr_info.tw*cstr_info.th, size_of_coding); /* M */
for( tileno=0; tileno<cstr_info.tw*cstr_info.th; tileno++){
tile_Idx = &cstr_info.tile[ tileno];
num_packet=0;
numOfres = cstr_info.numdecompos[compno] + 1;
for( resno=0; resno<numOfres ; resno++){
numOfprec = tile_Idx->pw[resno]*tile_Idx->ph[resno];
for( precno=0; precno<numOfprec; precno++){
numOflayers = cstr_info.numlayers;
for( layno=0; layno<numOflayers; layno++){
switch ( cstr_info.prog){
case LRCP:
packet = tile_Idx->packet[ ((layno*numOfres+resno)*cstr_info.numcomps+compno)*numOfprec+precno];
break;
case RLCP:
packet = tile_Idx->packet[ ((resno*numOflayers+layno)*cstr_info.numcomps+compno)*numOfprec+precno];
break;
case RPCL:
packet = tile_Idx->packet[ ((resno*numOfprec+precno)*cstr_info.numcomps+compno)*numOflayers+layno];
break;
case PCRL:
packet = tile_Idx->packet[ ((precno*cstr_info.numcomps+compno)*numOfres+resno)*numOflayers + layno];
break;
case CPRL:
packet = tile_Idx->packet[ ((compno*numOfprec+precno)*numOfres+resno)*numOflayers + layno];
break;
default:
fprintf( stderr, "failed to ppix indexing\n");
}
cio_write( cio, packet.start_pos-coff, size_of_coding); /* start position */
cio_write( cio, packet.end_pos-packet.start_pos+1, size_of_coding); /* length */
num_packet++;
}
}
}
while( num_packet < nmax){ /* PADDING */
cio_write( cio, 0, size_of_coding); /* start position */
cio_write( cio, 0, size_of_coding); /* length */
num_packet++;
}
}
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
return len;
}

View File

@@ -123,20 +123,20 @@ static void t1_enc_refpass_step(
/**
Decode refinement pass
*/
static void INLINE t1_dec_refpass_step_raw(
static INLINE void t1_dec_refpass_step_raw(
opj_t1_t *t1,
flag_t *flagsp,
int *datap,
int poshalf,
int neghalf,
int vsc);
static void INLINE t1_dec_refpass_step_mqc(
static INLINE void t1_dec_refpass_step_mqc(
opj_t1_t *t1,
flag_t *flagsp,
int *datap,
int poshalf,
int neghalf);
static void INLINE t1_dec_refpass_step_mqc_vsc(
static INLINE void t1_dec_refpass_step_mqc_vsc(
opj_t1_t *t1,
flag_t *flagsp,
int *datap,
@@ -240,6 +240,7 @@ Encode 1 code-block
@param stepsize
@param cblksty Code-block style
@param numcomps
@param mct
@param tile
*/
static void t1_encode_cblk(
@@ -381,9 +382,10 @@ static INLINE void t1_dec_sigpass_step_raw(
int vsc)
{
int v, flag;
opj_raw_t *raw = t1->raw; /* RAW component */
OPJ_ARG_NOT_USED(orient);
flag = vsc ? ((*flagsp) & (~(T1_SIG_S | T1_SIG_SE | T1_SIG_SW | T1_SGN_S))) : (*flagsp);
if ((flag & T1_SIG_OTH) && !(flag & (T1_SIG | T1_VISIT))) {
if (raw_decode(raw)) {
@@ -822,9 +824,10 @@ static void t1_dec_clnpass_step_partial(
int oneplushalf)
{
int v, flag;
opj_mqc_t *mqc = t1->mqc; /* MQC component */
OPJ_ARG_NOT_USED(orient);
flag = *flagsp;
mqc_setcurctx(mqc, t1_getctxno_sc(flag));
v = mqc_decode(mqc) ^ t1_getspb(flag);
@@ -1088,34 +1091,21 @@ static double t1_getwmsedec(
int numcomps,
int mct)
{
double w1 = 1, w2, wmsedec;
// Prevent running an MCT on more than 3 components. NB openjpeg v2.0 will support this via
// custom MCT tables that can be passed as encode parameters, 1.3 cannot support this as it
// uses a static table of 3 entries and there for can only cope with 3 components with out an
// array overflow
if(numcomps==3) {
if (qmfbid == 1) {
w1 = (numcomps > 1) ? mct_getnorm(compno) : 1.0;
} else {
w1 = (numcomps > 1) ? mct_getnorm_real(compno) : 1.0;
}
}
double w1, w2, wmsedec;
if (qmfbid == 1) {
w1 = (mct && numcomps==3) ? mct_getnorm(compno) : 1.0;
w2 = dwt_getnorm(level, orient);
} else { /* if (qmfbid == 0) */
w1 = (mct && numcomps==3) ? mct_getnorm_real(compno) : 1.0;
w2 = dwt_getnorm_real(level, orient);
}
wmsedec = w1 * w2 * stepsize * (1 << bpno);
wmsedec *= wmsedec * nmsedec / 8192.0;
return wmsedec;
}
static bool allocate_buffers(
static opj_bool allocate_buffers(
opj_t1_t *t1,
int w,
int h)
@@ -1127,7 +1117,7 @@ static bool allocate_buffers(
opj_aligned_free(t1->data);
t1->data = (int*) opj_aligned_malloc(datasize * sizeof(int));
if(!t1->data){
return false;
return OPJ_FALSE;
}
t1->datasize=datasize;
}
@@ -1140,7 +1130,7 @@ static bool allocate_buffers(
opj_aligned_free(t1->flags);
t1->flags = (flag_t*) opj_aligned_malloc(flagssize * sizeof(flag_t));
if(!t1->flags){
return false;
return OPJ_FALSE;
}
t1->flagssize=flagssize;
}
@@ -1149,7 +1139,7 @@ static bool allocate_buffers(
t1->w=w;
t1->h=h;
return true;
return OPJ_TRUE;
}
/** mod fixed_quality */
@@ -1425,6 +1415,7 @@ void t1_encode_cblks(
for (bandno = 0; bandno < res->numbands; ++bandno) {
opj_tcd_band_t* restrict band = &res->bands[bandno];
int bandconst = 8192 * 8192 / ((int) floor(band->stepsize * 8192));
for (precno = 0; precno < res->pw * res->ph; ++precno) {
opj_tcd_precinct_t *prc = &band->precincts[precno];
@@ -1475,7 +1466,7 @@ void t1_encode_cblks(
datap[(j * cblk_w) + i] =
fix_mul(
tmp,
8192 * 8192 / ((int) floor(band->stepsize * 8192))) >> (11 - T1_NMSEDEC_FRACBITS);
bandconst) >> (11 - T1_NMSEDEC_FRACBITS);
}
}
}
@@ -1586,6 +1577,7 @@ void t1_decode_cblks(
opj_free(cblk->segs);
} /* cblkno */
opj_free(precinct->cblks.dec);
precinct->cblks.dec = NULL;
} /* precno */
} /* bandno */
} /* resno */

View File

@@ -135,8 +135,8 @@ void t1_encode_cblks(opj_t1_t *t1, opj_tcd_tile_t *tile, opj_tcp_t *tcp);
/**
Decode the code-blocks of a tile
@param t1 T1 handle
@param tile The tile to decode
@param tcp Tile coding parameters
@param tilec The tile to decode
@param tccp Tile coding parameters
*/
void t1_decode_cblks(opj_t1_t* t1, opj_tcd_tilecomp_t* tilec, opj_tccp_t* tccp);
/* ----------------------------------------------------------------------- */

View File

@@ -59,11 +59,12 @@ Encode a packet of a tile to a destination buffer
*/
static int t2_encode_packet(opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterator_t *pi, unsigned char *dest, int len, opj_codestream_info_t *cstr_info, int tileno);
/**
@param seg
@param cblk
@param index
@param cblksty
@param first
*/
static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first);
static opj_bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first);
/**
Decode a packet of a tile from a source buffer
@param t2 T2 handle
@@ -72,6 +73,7 @@ Decode a packet of a tile from a source buffer
@param tile Tile for which to write the packets
@param tcp Tile coding parameters
@param pi Packet identity
@param pack_info Packet information
@return
*/
static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile,
@@ -147,8 +149,8 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera
c[1] = 145;
c[2] = 0;
c[3] = 4;
c[4] = (tile->packno % 65536) / 256;
c[5] = (tile->packno % 65536) % 256;
c[4] = (unsigned char)((tile->packno % 65536) / 256);
c[5] = (unsigned char)((tile->packno % 65536) % 256);
c += 6;
}
/* </SOP> */
@@ -253,8 +255,8 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera
/* </EPH> */
/* << INDEX */
// End of packet header position. Currently only represents the distance to start of packet
// Will be updated later by incrementing with packet start value
/* End of packet header position. Currently only represents the distance to start of packet
// Will be updated later by incrementing with packet start value */
if(cstr_info && cstr_info->index_write) {
opj_packet_info_t *info_PK = &cstr_info->tile[tileno].packet[cstr_info->packno];
info_PK->end_ph_pos = (int)(c - dest);
@@ -294,9 +296,17 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera
return (c - dest);
}
static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) {
static opj_bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) {
opj_tcd_seg_t* seg;
cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t));
opj_tcd_seg_t* segs;
segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t));
if (segs == NULL)
{
return OPJ_FALSE;
}
cblk->segs = segs;
seg = &cblk->segs[index];
seg->data = NULL;
seg->dataindex = 0;
@@ -314,6 +324,8 @@ static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int fi
} else {
seg->maxpasses = 109;
}
return OPJ_TRUE;
}
static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile,
@@ -401,8 +413,8 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
}
/* << INDEX */
// End of packet header position. Currently only represents the distance to start of packet
// Will be updated later by incrementing with packet start value
/* End of packet header position. Currently only represents the distance to start of packet
// Will be updated later by incrementing with packet start value*/
if(pack_info) {
pack_info->end_ph_pos = (int)(c - src);
}
@@ -460,12 +472,22 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
cblk->numlenbits += increment;
segno = 0;
if (!cblk->numsegs) {
t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1);
if (!t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1))
{
opj_event_msg(t2->cinfo, EVT_ERROR, "Out of memory\n");
bio_destroy(bio);
return -999;
}
} else {
segno = cblk->numsegs - 1;
if (cblk->segs[segno].numpasses == cblk->segs[segno].maxpasses) {
++segno;
t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0);
if (!t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0))
{
opj_event_msg(t2->cinfo, EVT_ERROR, "Out of memory\n");
bio_destroy(bio);
return -999;
}
}
}
n = cblk->numnewpasses;
@@ -476,7 +498,12 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
n -= cblk->segs[segno].numnewpasses;
if (n > 0) {
++segno;
t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0);
if (!t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0))
{
opj_event_msg(t2->cinfo, EVT_ERROR, "Out of memory\n");
bio_destroy(bio);
return -999;
}
}
} while (n > 0);
}
@@ -494,14 +521,15 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
if (tcp->csty & J2K_CP_CSTY_EPH) {
if ((*hd) != 0xff || (*(hd + 1) != 0x92)) {
opj_event_msg(t2->cinfo, EVT_ERROR, "Expected EPH marker\n");
return -999;
} else {
hd += 2;
}
}
/* << INDEX */
// End of packet header position. Currently only represents the distance to start of packet
// Will be updated later by incrementing with packet start value
/* End of packet header position. Currently only represents the distance to start of packet
// Will be updated later by incrementing with packet start value*/
if(pack_info) {
pack_info->end_ph_pos = (int)(hd - src);
}
@@ -565,7 +593,7 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
#endif /* USE_JPWL */
cblk->data = (unsigned char*) opj_realloc(cblk->data, (cblk->len + seg->newlen) * sizeof(unsigned char*));
cblk->data = (unsigned char*) opj_realloc(cblk->data, (cblk->len + seg->newlen) * sizeof(unsigned char));
memcpy(cblk->data + cblk->len, c, seg->newlen);
if (seg->numpasses == 0) {
seg->data = &cblk->data;
@@ -659,8 +687,8 @@ int t2_encode_packets(opj_t2_t* t2,int tileno, opj_tcd_tile_t *tile, int maxlaye
info_PK->start_pos = ((cp->tp_on | tcp->POC)&& info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1;
}
info_PK->end_pos = info_PK->start_pos + e - 1;
info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance
// to start of packet is incremented by value of start of packet
info_PK->end_ph_pos += info_PK->start_pos - 1; /* End of packet header which now only represents the distance
// to start of packet is incremented by value of start of packet*/
}
cstr_info->packno++;
@@ -711,7 +739,11 @@ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj
} else {
e = 0;
}
if(e == -999)
{
pi_destroy(pi, cp, tileno);
return -999;
}
/* progression in resolution */
image->comps[pi[pino].compno].resno_decoded =
(e > 0) ?
@@ -725,8 +757,9 @@ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj
opj_packet_info_t *info_PK = &info_TL->packet[cstr_info->packno];
if (!cstr_info->packno) {
info_PK->start_pos = info_TL->end_header + 1;
} else if (info_TL->packet[cstr_info->packno-1].end_pos >= (int)cstr_info->tile[tileno].tp[curtp].tp_end_pos){ // New tile part
info_TL->tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; // Number of packets in previous tile-part
} else if (info_TL->packet[cstr_info->packno-1].end_pos >= (int)cstr_info->tile[tileno].tp[curtp].tp_end_pos){ /* New tile part*/
info_TL->tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; /* Number of packets in previous tile-part*/
info_TL->tp[curtp].tp_start_pack = tp_start_packno;
tp_start_packno = cstr_info->packno;
curtp++;
info_PK->start_pos = cstr_info->tile[tileno].tp[curtp].tp_end_header+1;
@@ -734,8 +767,8 @@ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj
info_PK->start_pos = (cp->tp_on && info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[cstr_info->packno - 1].end_pos + 1;
}
info_PK->end_pos = info_PK->start_pos + e - 1;
info_PK->end_ph_pos += info_PK->start_pos - 1; // End of packet header which now only represents the distance
// to start of packet is incremented by value of start of packet
info_PK->end_ph_pos += info_PK->start_pos - 1; /* End of packet header which now only represents the distance
// to start of packet is incremented by value of start of packet*/
cstr_info->packno++;
}
/* << INDEX */
@@ -749,7 +782,8 @@ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj
}
/* INDEX >> */
if(cstr_info) {
cstr_info->tile[tileno].tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; // Number of packets in last tile-part
cstr_info->tile[tileno].tp[curtp].tp_numpacks = cstr_info->packno - tp_start_packno; /* Number of packets in last tile-part*/
cstr_info->tile[tileno].tp[curtp].tp_start_pack = tp_start_packno;
}
/* << INDEX */

View File

@@ -67,6 +67,7 @@ Encode the packets of a tile to a destination buffer
@param cstr_info Codestream information structure
@param tpnum Tile part number of the current tile
@param tppos The position of the tile part flag in the progression order
@param pino
@param t2_mode If == 0 In Threshold calculation ,If == 1 Final pass
@param cur_totnum_tp The total number of tile parts in the current tile
*/
@@ -78,6 +79,7 @@ Decode the packets of a tile from a source buffer
@param len length of the source buffer
@param tileno number that identifies the tile for which to decode the packets
@param tile tile for which to decode the packets
@param cstr_info Codestream information structure
*/
int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj_tcd_tile_t *tile, opj_codestream_info_t *cstr_info);

View File

@@ -30,10 +30,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#define _ISOC99_SOURCE /* lrintf is C99 */
#include "opj_includes.h"
void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) {
int tileno, compno, resno, bandno, precno;//, cblkno;
int tileno, compno, resno, bandno, precno;/*, cblkno;*/
fprintf(fd, "image {\n");
fprintf(fd, " tw=%d, th=%d x0=%d x1=%d y0=%d y1=%d\n",
@@ -290,6 +291,7 @@ void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int c
for (i = 0; i < res->pw * res->ph * 3; i++) {
band->precincts[i].imsbtree = NULL;
band->precincts[i].incltree = NULL;
band->precincts[i].cblks.enc = NULL;
}
for (precno = 0; precno < res->pw * res->ph; precno++) {
@@ -332,8 +334,10 @@ void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int c
cblk->y0 = int_max(cblkystart, prc->y0);
cblk->x1 = int_min(cblkxend, prc->x1);
cblk->y1 = int_min(cblkyend, prc->y1);
cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char));
cblk->data = (unsigned char*) opj_calloc(9728+2, sizeof(unsigned char));
/* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */
cblk->data[0] = 0;
cblk->data[1] = 0;
cblk->data += 2;
cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t));
cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t));
@@ -593,6 +597,8 @@ void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int cur
cblk->y1 = int_min(cblkyend, prc->y1);
cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char));
/* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */
cblk->data[0] = 0;
cblk->data[1] = 0;
cblk->data += 2;
cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t));
cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t));
@@ -613,7 +619,7 @@ void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp) {
tcd->image = image;
tcd->tcd_image->tw = cp->tw;
tcd->tcd_image->th = cp->th;
tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tcd_tile_t));
tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_calloc(cp->tw * cp->th, sizeof(opj_tcd_tile_t));
/*
Allocate place to store the decoded data = final image
@@ -656,7 +662,7 @@ void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp) {
tilec->y1 = int_ceildiv(tile->y1, image->comps[i].dy);
x0 = j == 0 ? tilec->x0 : int_min(x0, (unsigned int) tilec->x0);
y0 = j == 0 ? tilec->y0 : int_min(y0, (unsigned int) tilec->x0);
y0 = j == 0 ? tilec->y0 : int_min(y0, (unsigned int) tilec->y0);
x1 = j == 0 ? tilec->x1 : int_max(x1, (unsigned int) tilec->x1);
y1 = j == 0 ? tilec->y1 : int_max(y1, (unsigned int) tilec->y1);
}
@@ -676,6 +682,8 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
opj_tcp_t *tcp;
opj_tcd_tile_t *tile;
OPJ_ARG_NOT_USED(cstr_info);
tcd->cp = cp;
tcp = &(cp->tcps[cp->tileno[tileno]]);
@@ -687,6 +695,12 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
opj_tccp_t *tccp = &tcp->tccps[compno];
opj_tcd_tilecomp_t *tilec = &tile->comps[compno];
if (tccp->numresolutions <= 0)
{
cp->tileno[tileno] = -1;
return;
}
/* border of each tile component (global) */
tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx);
tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy);
@@ -997,7 +1011,7 @@ void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final) {
}
}
bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) {
opj_bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) {
int compno, resno, bandno, precno, cblkno, passno, layno;
double min, max;
double cumdisto[100]; /* fixed_quality */
@@ -1149,7 +1163,7 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre
}
if (!success) {
return false;
return OPJ_FALSE;
}
if(cstr_info) { /* Threshold for Marcela Index */
@@ -1161,7 +1175,7 @@ bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestre
cumdisto[layno] = (layno == 0) ? tcd_tile->distolayer[0] : (cumdisto[layno - 1] + tcd_tile->distolayer[layno]);
}
return true;
return OPJ_TRUE;
}
int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, opj_codestream_info_t *cstr_info) {
@@ -1313,7 +1327,7 @@ int tcd_encode_tile(opj_tcd_t *tcd, int tileno, unsigned char *dest, int len, op
return l;
}
bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info) {
opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info) {
int l;
int compno;
int eof = 0;
@@ -1349,7 +1363,7 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, op
}
else {
cstr_info->tile[tileno].pdx[resno] = 15;
cstr_info->tile[tileno].pdx[resno] = 15;
cstr_info->tile[tileno].pdy[resno] = 15;
}
}
}
@@ -1373,14 +1387,24 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, op
t1_time = opj_clock(); /* time needed to decode a tile */
t1 = t1_create(tcd->cinfo);
if (t1 == NULL)
{
opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
t1_destroy(t1);
return OPJ_FALSE;
}
for (compno = 0; compno < tile->numcomps; ++compno) {
opj_tcd_tilecomp_t* tilec = &tile->comps[compno];
/* The +3 is headroom required by the vectorized DWT */
tilec->data = (int*) opj_aligned_malloc((((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0))+3) * sizeof(int));
if(tilec->data)
t1_decode_cblks(t1, tilec, &tcd->tcp->tccps[compno]);
else
opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: tile size invalid\n");
if (tilec->data == NULL)
{
opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
return OPJ_FALSE;
}
t1_decode_cblks(t1, tilec, &tcd->tcp->tccps[compno]);
}
t1_destroy(t1);
t1_time = opj_clock() - t1_time;
@@ -1394,18 +1418,15 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, op
int numres2decode;
if (tcd->cp->reduce != 0) {
tcd->image->comps[compno].resno_decoded =
tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
if (tcd->image->comps[compno].resno_decoded < 0) {
if ( tile->comps[compno].numresolutions < ( tcd->cp->reduce - 1 ) ) {
opj_event_msg(tcd->cinfo, EVT_ERROR, "Error decoding tile. The number of resolutions to remove [%d+1] is higher than the number "
" of resolutions in the original codestream [%d]\nModify the cp_reduce parameter.\n", tcd->cp->reduce, tile->comps[compno].numresolutions);
return false;
return OPJ_FALSE;
}
}
if(!tilec->data) {
opj_event_msg(tcd->cinfo, EVT_ERROR, "Error decoding tile. null data\n");
return false;
else {
tcd->image->comps[compno].resno_decoded =
tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
}
}
numres2decode = tcd->image->comps[compno].resno_decoded + 1;
@@ -1424,18 +1445,23 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, op
if (tcd->tcp->mct) {
int n = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0);
if (tcd->tcp->tccps[0].qmfbid == 1) {
mct_decode(
tile->comps[0].data,
tile->comps[1].data,
tile->comps[2].data,
n);
} else {
mct_decode_real(
(float*)tile->comps[0].data,
(float*)tile->comps[1].data,
(float*)tile->comps[2].data,
n);
if (tile->numcomps >= 3 ){
if (tcd->tcp->tccps[0].qmfbid == 1) {
mct_decode(
tile->comps[0].data,
tile->comps[1].data,
tile->comps[2].data,
n);
} else {
mct_decode_real(
(float*)tile->comps[0].data,
(float*)tile->comps[1].data,
(float*)tile->comps[2].data,
n);
}
} else{
opj_event_msg(tcd->cinfo, EVT_WARNING,"Number of components (%d) is inconsistent with a MCT. Skip the MCT step.\n",tile->numcomps);
}
}
@@ -1459,6 +1485,11 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, op
if(!imagec->data){
imagec->data = (int*) opj_malloc(imagec->w * imagec->h * sizeof(int));
}
if (!imagec->data)
{
opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
return OPJ_FALSE;
}
if(tcd->tcp->tccps[compno].qmfbid == 1) {
for(j = res->y0; j < res->y1; ++j) {
for(i = res->x0; i < res->x1; ++i) {
@@ -1484,40 +1515,59 @@ bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, op
opj_event_msg(tcd->cinfo, EVT_INFO, "- tile decoded in %f s\n", tile_time);
if (eof) {
return false;
return OPJ_FALSE;
}
return true;
return OPJ_TRUE;
}
void tcd_free_decode(opj_tcd_t *tcd) {
opj_tcd_image_t *tcd_image = tcd->tcd_image;
int i = 0;
for (i = 0; i < tcd_image->tw * tcd_image->th; i++)
{
tcd_free_decode_tile(tcd, i);
}
opj_free(tcd_image->tiles);
}
void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno) {
int compno,resno,bandno,precno;
int compno,resno,bandno,precno,cblkno;
opj_tcd_image_t *tcd_image = tcd->tcd_image;
opj_tcd_tile_t *tile = &tcd_image->tiles[tileno];
for (compno = 0; compno < tile->numcomps; compno++) {
opj_tcd_tilecomp_t *tilec = &tile->comps[compno];
for (resno = 0; resno < tilec->numresolutions; resno++) {
opj_tcd_resolution_t *res = &tilec->resolutions[resno];
for (bandno = 0; bandno < res->numbands; bandno++) {
opj_tcd_band_t *band = &res->bands[bandno];
for (precno = 0; precno < res->ph * res->pw; precno++) {
opj_tcd_precinct_t *prec = &band->precincts[precno];
if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree);
if (prec->incltree != NULL) tgt_destroy(prec->incltree);
if (tile->comps != NULL) {
for (compno = 0; compno < tile->numcomps; compno++) {
opj_tcd_tilecomp_t *tilec = &tile->comps[compno];
for (resno = 0; resno < tilec->numresolutions; resno++) {
opj_tcd_resolution_t *res = &tilec->resolutions[resno];
for (bandno = 0; bandno < res->numbands; bandno++) {
opj_tcd_band_t *band = &res->bands[bandno];
for (precno = 0; precno < res->ph * res->pw; precno++) {
opj_tcd_precinct_t *prec = &band->precincts[precno];
if (prec->cblks.dec != NULL) {
for (cblkno = 0; cblkno < prec->cw * prec->ch; ++cblkno) {
opj_tcd_cblk_dec_t* cblk = &prec->cblks.dec[cblkno];
opj_free(cblk->data);
opj_free(cblk->segs);
}
opj_free(prec->cblks.dec);
}
if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree);
if (prec->incltree != NULL) tgt_destroy(prec->incltree);
}
opj_free(band->precincts);
}
opj_free(band->precincts);
}
opj_free(tilec->resolutions);
}
opj_free(tilec->resolutions);
opj_free(tile->comps);
tile->comps = NULL;
}
opj_free(tile->comps);
}

View File

@@ -251,7 +251,7 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
void tcd_makelayer_fixed(opj_tcd_t *tcd, int layno, int final);
void tcd_rateallocate_fixed(opj_tcd_t *tcd);
void tcd_makelayer(opj_tcd_t *tcd, int layno, double thresh, int final);
bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info);
opj_bool tcd_rateallocate(opj_tcd_t *tcd, unsigned char *dest, int len, opj_codestream_info_t *cstr_info);
/**
Encode a tile from the raw image into a buffer
@param tcd TCD handle
@@ -268,8 +268,9 @@ Decode a tile from a buffer into a raw image
@param src Source buffer
@param len Length of source buffer
@param tileno Number that identifies one of the tiles to be decoded
@param cstr_info Codestream information structure
*/
bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info);
opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno, opj_codestream_info_t *cstr_info);
/**
Free the memory allocated for decoding
@param tcd TCD handle

View File

@@ -0,0 +1,120 @@
/*
* $Id: thix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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.
*/
/*! \file
* \brief Modification of jpip.c from 2KAN indexer
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "opj_includes.h"
/*
* Write tile-part headers mhix box
*
* @param[in] coff offset of j2k codestream
* @param[in] cstr_info codestream information
* @param[in] tileno tile number
* @param[in] cio file output handle
* @return length of mhix box
*/
int write_tilemhix( int coff, opj_codestream_info_t cstr_info, int tileno, opj_cio_t *cio);
int write_thix( int coff, opj_codestream_info_t cstr_info, opj_cio_t *cio)
{
int len, lenp, i;
int tileno;
opj_jp2_box_t *box;
lenp = 0;
box = (opj_jp2_box_t *)opj_calloc( cstr_info.tw*cstr_info.th, sizeof(opj_jp2_box_t));
for ( i = 0; i < 2 ; i++ ){
if (i)
cio_seek( cio, lenp);
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_THIX, 4); /* THIX */
write_manf( i, cstr_info.tw*cstr_info.th, box, cio);
for (tileno = 0; tileno < cstr_info.tw*cstr_info.th; tileno++){
box[tileno].length = write_tilemhix( coff, cstr_info, tileno, cio);
box[tileno].type = JPIP_MHIX;
}
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
}
opj_free(box);
return len;
}
int write_tilemhix( int coff, opj_codestream_info_t cstr_info, int tileno, opj_cio_t *cio)
{
int i;
opj_tile_info_t tile;
opj_tp_info_t tp;
int len, lenp;
opj_marker_info_t *marker;
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_MHIX, 4); /* MHIX */
tile = cstr_info.tile[tileno];
tp = tile.tp[0];
cio_write( cio, tp.tp_end_header-tp.tp_start_pos+1, 8); /* TLEN */
marker = cstr_info.tile[tileno].marker;
for( i=0; i<cstr_info.tile[tileno].marknum; i++){ /* Marker restricted to 1 apparition */
cio_write( cio, marker[i].type, 2);
cio_write( cio, 0, 2);
cio_write( cio, marker[i].pos-coff, 8);
cio_write( cio, marker[i].len, 2);
}
/* free( marker);*/
len = cio_tell( cio) - lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
return len;
}

View File

@@ -0,0 +1,153 @@
/*
* $Id: tpix_manager.c 897 2011-08-28 21:43:57Z Kaori.Hagihara@gmail.com $
*
* Copyright (c) 2002-2011, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium
* Copyright (c) 2002-2011, Professor Benoit Macq
* Copyright (c) 2003-2004, Yannick Verschueren
* Copyright (c) 2010-2011, Kaori Hagihara
* 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.
*/
/*! \file
* \brief Modification of jpip.c from 2KAN indexer
*/
#include <math.h>
#include "opj_includes.h"
#define MAX(a,b) ((a)>(b)?(a):(b))
/*
* Write faix box of tpix
*
* @param[in] coff offset of j2k codestream
* @param[in] compno component number
* @param[in] cstr_info codestream information
* @param[in] j2klen length of j2k codestream
* @param[in] cio file output handle
* @return length of faix box
*/
int write_tpixfaix( int coff, int compno, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio);
int write_tpix( int coff, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio)
{
int len, lenp;
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_TPIX, 4); /* TPIX */
write_tpixfaix( coff, 0, cstr_info, j2klen, cio);
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
return len;
}
/*
* Get number of maximum tile parts per tile
*
* @param[in] cstr_info codestream information
* @return number of maximum tile parts per tile
*/
int get_num_max_tile_parts( opj_codestream_info_t cstr_info);
int write_tpixfaix( int coff, int compno, opj_codestream_info_t cstr_info, int j2klen, opj_cio_t *cio)
{
int len, lenp;
int i, j;
int Aux;
int num_max_tile_parts;
int size_of_coding; /* 4 or 8 */
opj_tp_info_t tp;
int version;
num_max_tile_parts = get_num_max_tile_parts( cstr_info);
if( j2klen > pow( 2.0, 32)){
size_of_coding = 8;
version = num_max_tile_parts == 1 ? 1:3;
}
else{
size_of_coding = 4;
version = num_max_tile_parts == 1 ? 0:2;
}
lenp = cio_tell( cio);
cio_skip( cio, 4); /* L [at the end] */
cio_write( cio, JPIP_FAIX, 4); /* FAIX */
cio_write( cio, version, 1); /* Version 0 = 4 bytes */
cio_write( cio, num_max_tile_parts, size_of_coding); /* NMAX */
cio_write( cio, cstr_info.tw*cstr_info.th, size_of_coding); /* M */
for (i = 0; i < cstr_info.tw*cstr_info.th; i++){
for (j = 0; j < cstr_info.tile[i].num_tps; j++){
tp = cstr_info.tile[i].tp[j];
cio_write( cio, tp.tp_start_pos-coff, size_of_coding); /* start position */
cio_write( cio, tp.tp_end_pos-tp.tp_start_pos+1, size_of_coding); /* length */
if (version & 0x02){
if( cstr_info.tile[i].num_tps == 1 && cstr_info.numdecompos[compno] > 1)
Aux = cstr_info.numdecompos[compno] + 1;
else
Aux = j + 1;
cio_write( cio, Aux,4);
/*cio_write(img.tile[i].tile_parts[j].num_reso_AUX,4);*/ /* Aux_i,j : Auxiliary value */
/* fprintf(stderr,"AUX value %d\n",Aux);*/
}
/*cio_write(0,4);*/
}
/* PADDING */
while (j < num_max_tile_parts){
cio_write( cio, 0, size_of_coding); /* start position */
cio_write( cio, 0, size_of_coding); /* length */
if (version & 0x02)
cio_write( cio, 0,4); /* Aux_i,j : Auxiliary value */
j++;
}
}
len = cio_tell( cio)-lenp;
cio_seek( cio, lenp);
cio_write( cio, len, 4); /* L */
cio_seek( cio, lenp+len);
return len;
}
int get_num_max_tile_parts( opj_codestream_info_t cstr_info)
{
int num_max_tp = 0, i;
for( i=0; i<cstr_info.tw*cstr_info.th; i++)
num_max_tp = MAX( cstr_info.tile[i].num_tps, num_max_tp);
return num_max_tp;
}

View File

@@ -50,8 +50,7 @@ LLMultiGesture::LLMultiGesture()
mSteps(),
mPlaying(FALSE),
mCurrentStep(0),
mDoneCallback(NULL),
mCallbackData(NULL)
mDoneCallback(NULL)
{
reset();
}

View File

@@ -100,8 +100,7 @@ public:
// Timer for waiting
LLFrameTimer mWaitTimer;
void (*mDoneCallback)(LLMultiGesture* gesture, void* data);
void* mCallbackData;
boost::function<void (LLMultiGesture*)> mDoneCallback;
// Animations that we requested to start
std::set<LLUUID> mRequestedAnimIDs;

View File

@@ -27,7 +27,7 @@
#include "linden_common.h"
#include "llallocator.h"
#if LL_USE_TCMALLOC
#if (LL_USE_TCMALLOC && LL_USE_HEAP_PROFILER)
#include "google/heap-profiler.h"
#include "google/commandlineflags_public.h"

View File

@@ -56,6 +56,7 @@ public:
};
LLDynamicArray(S32 size=0) : std::vector<Type>(size) { if (size < BlockSize) std::vector<Type>::reserve(BlockSize); }
LLDynamicArray(const std::vector<Type>& copy) : std::vector<Type>(copy) {}
void reset() { std::vector<Type>::clear(); }

View File

@@ -444,13 +444,13 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
{
// The new node isn't last. Place it between the previous node and
// the successor.
newNode = (myprev + mydmi->second)/2.0;
newNode = (myprev + mydmi->second)/2.f;
}
else
{
// The new node is last. Bump myprev up to the next integer, add
// 1.0 and use that.
newNode = std::ceil(myprev) + 1.0;
newNode = std::ceil(myprev) + 1.f;
}
// Now that newNode has a value that places it appropriately in mSignal,
// connect it.

View File

@@ -67,6 +67,17 @@ BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE;
LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker;
#endif
void ll_assert_aligned_func(uintptr_t ptr,U32 alignment)
{
#ifdef SHOW_ASSERT
// Redundant, place to set breakpoints.
if (ptr%alignment!=0)
{
llwarns << "alignment check failed" << llendl;
}
llassert(ptr%alignment==0);
#endif
}
//static
void LLMemory::initClass()
{
@@ -246,21 +257,6 @@ U32 LLMemory::getAllocatedMemKB()
return sAllocatedMemInKB ;
}
void* ll_allocate (size_t size)
{
if (size == 0)
{
llwarns << "Null allocation" << llendl;
}
void *p = malloc(size);
if (p == NULL)
{
LLMemory::freeReserve();
llerrs << "Out of memory Error" << llendl;
}
return p;
}
//----------------------------------------------------------------------------
#if defined(LL_WINDOWS)
@@ -1358,7 +1354,7 @@ char* LLPrivateMemoryPool::allocate(U32 size)
//if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it
if(size >= CHUNK_SIZE)
{
return (char*)malloc(size) ;
return (char*)ll_aligned_malloc_16(size) ;
}
char* p = NULL ;
@@ -1415,7 +1411,7 @@ char* LLPrivateMemoryPool::allocate(U32 size)
to_log = false ;
}
return (char*)malloc(size) ;
return (char*)ll_aligned_malloc_16(size) ;
}
return p ;
@@ -1434,7 +1430,7 @@ void LLPrivateMemoryPool::freeMem(void* addr)
if(!chunk)
{
free(addr) ; //release from heap
ll_aligned_free_16(addr) ; //release from heap
}
else
{
@@ -1558,7 +1554,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde
mReservedPoolSize += preferred_size + overhead ;
char* buffer = (char*)malloc(preferred_size + overhead) ;
char* buffer = (char*)ll_aligned_malloc_16(preferred_size + overhead) ;
if(!buffer)
{
return NULL ;
@@ -1626,7 +1622,7 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk)
mReservedPoolSize -= chunk->getBufferSize() ;
//release memory
free(chunk->getBuffer()) ;
ll_aligned_free_16(chunk->getBuffer()) ;
}
U16 LLPrivateMemoryPool::findHashKey(const char* addr)
@@ -1970,7 +1966,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size,
if(!poolp)
{
p = (char*)malloc(size) ;
p = (char*)ll_aligned_malloc_16(size) ;
}
else
{
@@ -1999,7 +1995,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size)
}
else
{
return (char*)malloc(size) ;
return (char*)ll_aligned_malloc_16(size) ;
}
}
#endif
@@ -2024,7 +2020,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr
{
if(!sPrivatePoolEnabled)
{
free(addr) ; //private pool is disabled.
ll_aligned_free_16(addr) ; //private pool is disabled.
}
else if(!sInstance) //the private memory manager is destroyed, try the dangling list
{

View File

@@ -39,9 +39,14 @@
#include <stdint.h> // uintptr_t
#endif
#include "llerror.h"
#include "llmemtype.h"
#if LL_DEBUG
#if LL_WINDOWS && LL_DEBUG
#define LL_CHECK_MEMORY llassert(_CrtCheckMemory());
#else
#define LL_CHECK_MEMORY
#endif
inline void* ll_aligned_malloc( size_t size, int align )
{
void* mem = malloc( size + (align - 1) + sizeof(void*) );
@@ -57,10 +62,11 @@ inline void ll_aligned_free( void* ptr )
free( ((void**)ptr)[-1] );
}
#if !LL_USE_TCMALLOC
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
return _mm_malloc(size, 16);
return _aligned_malloc(size, 16);
#elif defined(LL_DARWIN)
return malloc(size); // default osx malloc is 16 byte aligned.
#else
@@ -75,7 +81,7 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi
inline void ll_aligned_free_16(void *p)
{
#if defined(LL_WINDOWS)
_mm_free(p);
_aligned_free(p);
#elif defined(LL_DARWIN)
return free(p);
#else
@@ -83,10 +89,39 @@ inline void ll_aligned_free_16(void *p)
#endif
}
inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
return _aligned_realloc(ptr, size, 16);
#elif defined(LL_DARWIN)
return realloc(ptr,size); // default osx malloc is 16 byte aligned.
#else
//FIXME: memcpy is SLOW
void* ret = ll_aligned_malloc_16(size);
if (ptr)
{
if (ret)
{
// Only copy the size of the smallest memory block to avoid memory corruption.
memcpy(ret, ptr, llmin(old_size, size));
}
ll_aligned_free_16(ptr);
}
return ret;
#endif
}
#else // USE_TCMALLOC
// ll_aligned_foo_16 are not needed with tcmalloc
#define ll_aligned_malloc_16 malloc
#define ll_aligned_realloc_16(a,b,c) realloc(a,b)
#define ll_aligned_free_16 free
#endif // USE_TCMALLOC
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
{
#if defined(LL_WINDOWS)
return _mm_malloc(size, 32);
return _aligned_malloc(size, 32);
#elif defined(LL_DARWIN)
return ll_aligned_malloc( size, 32 );
#else
@@ -101,22 +136,13 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi
inline void ll_aligned_free_32(void *p)
{
#if defined(LL_WINDOWS)
_mm_free(p);
_aligned_free(p);
#elif defined(LL_DARWIN)
ll_aligned_free( p );
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
}
#else // LL_DEBUG
// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
#define ll_aligned_malloc( size, align ) malloc(size)
#define ll_aligned_free( ptr ) free(ptr)
#define ll_aligned_malloc_16 malloc
#define ll_aligned_free_16 free
#define ll_aligned_malloc_32 malloc
#define ll_aligned_free_32 free
#endif // LL_DEBUG
#ifndef __DEBUG_PRIVATE_MEM__
#define __DEBUG_PRIVATE_MEM__ 0
@@ -521,6 +547,14 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr)
#endif
#endif
LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);
#ifdef SHOW_ASSERT
#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment))
#else
#define ll_assert_aligned(ptr,alignment)
#endif
//EVENTUALLY REMOVE THESE:
#include "llpointer.h"
#include "llsingleton.h"

View File

@@ -262,11 +262,6 @@ U64 totalTime()
// No wrapping, we're all okay.
gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount;
}
else if((gLastTotalTimeClockCount - current_clock_count)<0xFFFF)
{
//clock is glitching and walking backwards - ignore it
gTotalTimeClockCount = gLastTotalTimeClockCount;
}
else
{
// We've wrapped. Compensate correctly

View File

@@ -206,6 +206,19 @@ U8* LLImageBase::allocateData(S32 size)
// virtual
U8* LLImageBase::reallocateData(S32 size)
{
if (size == -1)
{
size = mWidth * mHeight * mComponents;
if (size <= 0)
{
llerrs << llformat("LLImageBase::reallocateData called with bad dimensions: %dx%dx%d", mWidth, mHeight, (S32)mComponents) << llendl;
}
}
else if (size <= 0 || (size > 4096 * 4096 * 16 && !mAllowOverSize))
{
llerrs << "LLImageBase::reallocateData: bad size: " << size << llendl;
}
if(mData && (mDataSize == size))
return mData;
@@ -300,6 +313,32 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
++sRawImageCount;
}
LLImageRaw::LLImageRaw(LLImageRaw const* src, U16 width, U16 height, U16 crop_offset, bool crop_vertically) : mCacheEntries(0)
{
mMemType = LLMemType::MTYPE_IMAGERAW;
llassert_always(src);
S8 const components = src->getComponents();
U8 const* const data = src->getData();
if (allocateDataSize(width, height, components))
{
if (crop_vertically)
{
llassert_always(width == src->getWidth());
memcpy(getData(), data + width * crop_offset * components, width * height * components);
}
else
{
llassert_always(height == src->getHeight());
U16 const src_width = src->getWidth();
for (U16 row = 0; row < height; ++row)
{
memcpy(getData() + width * row * components, data + (src_width * row + crop_offset) * components, width * components);
}
}
}
++sRawImageCount;
}
/*LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
: LLImageBase(), mCacheEntries(0)
{
@@ -516,7 +555,7 @@ void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
scale( new_width, new_height, scale_image );
}
void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
void LLImageRaw::biasedScaleToPowerOfTwo(S32 target_width, S32 target_height, S32 max_dim)
{
// Strong bias towards rounding down (to save bandwidth)
// No bias would mean THRESHOLD == 1.5f;
@@ -525,22 +564,22 @@ void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
// Find new sizes
S32 larger_w = max_dim; // 2^n >= mWidth
S32 smaller_w = max_dim; // 2^(n-1) <= mWidth
while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) )
while( (smaller_w > target_width) && (smaller_w > MIN_IMAGE_SIZE) )
{
larger_w = smaller_w;
smaller_w >>= 1;
}
S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
S32 new_width = ( (F32)target_width / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
S32 larger_h = max_dim; // 2^m >= mHeight
S32 smaller_h = max_dim; // 2^(m-1) <= mHeight
while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) )
while( (smaller_h > target_height) && (smaller_h > MIN_IMAGE_SIZE) )
{
larger_h = smaller_h;
smaller_h >>= 1;
}
S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
S32 new_height = ( (F32)target_height / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
scale( new_width, new_height );
@@ -943,76 +982,66 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
return TRUE; // Nothing to do.
}
// Reallocate the data buffer.
U8* old_buffer = NULL;
U8* new_buffer;
S32 const old_width_bytes = old_width * getComponents();
S32 const new_width_bytes = new_width * getComponents();
S32 const min_height = llmin(old_height, new_height);
S32 const min_width_bytes = llmin(old_width_bytes, new_width_bytes);
if (scale_image_data)
{
// Vertical
S32 temp_data_size = old_width * new_height * getComponents();
llassert_always(temp_data_size > 0);
U8* temp_buffer = new (std::nothrow) U8[ temp_data_size ];
if (!temp_buffer )
if (new_height != old_height)
{
llerrs << "Out of memory in LLImageRaw::scale()" << llendl;
return FALSE;
// Resize vertically.
old_buffer = LLImageBase::release();
new_buffer = allocateDataSize(old_width, new_height, getComponents());
for (S32 col = 0; col < old_width; ++col)
{
copyLineScaled(old_buffer + getComponents() * col, new_buffer + getComponents() * col, old_height, new_height, old_width, old_width);
}
LLImageBase::deleteData(old_buffer);
}
for( S32 col = 0; col < old_width; col++ )
if (new_width != old_width)
{
copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width );
// Resize horizontally.
old_buffer = LLImageBase::release();
new_buffer = allocateDataSize(new_width, new_height, getComponents());
for (S32 row = 0; row < new_height; ++row)
{
copyLineScaled(old_buffer + old_width_bytes * row, new_buffer + new_width_bytes * row, old_width, new_width, 1, 1);
}
LLImageBase::deleteData(old_buffer);
}
deleteData();
U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
// Horizontal
for( S32 row = 0; row < new_height; row++ )
{
copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
}
// Clean up
delete[] temp_buffer;
}
else
{
// copy out existing image data
S32 temp_data_size = old_width * old_height * getComponents();
U8* temp_buffer = new (std::nothrow) U8[ temp_data_size ];
if (!temp_buffer)
if (new_width == old_width)
{
llwarns << "Out of memory in LLImageRaw::scale: old (w, h, c) = (" << old_width << ", " << old_height << ", " << (S32)getComponents() <<
") ; new (w, h, c) = (" << new_width << ", " << new_height << ", " << (S32)getComponents() << ")" << llendl;
return FALSE ;
setSize(new_width, new_height, getComponents());
new_buffer = reallocateData();
}
memcpy(temp_buffer, getData(), temp_data_size); /* Flawfinder: ignore */
// allocate new image data, will delete old data
U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
for( S32 row = 0; row < new_height; row++ )
else
{
if (row < old_height)
old_buffer = LLImageBase::release();
new_buffer = allocateDataSize(new_width, new_height, getComponents());
for (S32 row = 0; row < min_height; ++row)
{
memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); /* Flawfinder: ignore */
if (old_width < new_width)
memcpy(new_buffer + row * new_width_bytes, old_buffer + row * old_width_bytes, min_width_bytes);
if (new_width_bytes > old_width_bytes)
{
// pad out rest of row with black
memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width));
// Pad out rest of row with black.
memset(new_buffer + new_width_bytes * row + old_width_bytes, 0, new_width_bytes - old_width_bytes);
}
}
else
{
// pad remaining rows with black
memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents());
}
LLImageBase::deleteData(old_buffer);
}
if (new_height > old_height)
{
// Pad remaining rows with black.
memset(new_buffer + new_width_bytes * min_height, 0, new_width_bytes * (new_height - old_height));
}
// Clean up
delete[] temp_buffer;
}
return TRUE ;
}
@@ -1690,6 +1719,12 @@ static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8*
dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2);
}
void LLImageBase::setDataAndSize(U8 *data, S32 size)
{
ll_assert_aligned(data, 16);
mData = data; mDataSize = size;
}
//static
void LLImageBase::generateMip(const U8* indata, U8* mipdata, S32 width, S32 height, S32 nchannels)
{

View File

@@ -114,6 +114,8 @@ public:
virtual void deleteData();
virtual U8* allocateData(S32 size = -1);
virtual U8* reallocateData(S32 size = -1);
static void deleteData(U8* data) { FREE_MEM(sPrivatePoolp, data); }
U8* release() { U8* data = mData; mData = NULL; mDataSize = 0; return data; } // Same as deleteData(), but returns old data. Call deleteData(old_data) to free it.
virtual void dump();
virtual void sanityCheck();
@@ -134,7 +136,7 @@ public:
protected:
// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }
void setDataAndSize(U8 *data, S32 size);
public:
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
@@ -175,12 +177,13 @@ public:
LLImageRaw();
LLImageRaw(U16 width, U16 height, S8 components);
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
LLImageRaw(LLImageRaw const* src, U16 width, U16 height, U16 crop_offset, bool crop_vertically);
// Construct using createFromFile (used by tools)
//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
/*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1);
/*virtual*/ U8* reallocateData(S32 size);
/*virtual*/ U8* reallocateData(S32 size = -1);
BOOL resize(U16 width, U16 height, S8 components);
@@ -194,7 +197,8 @@ public:
void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
void biasedScaleToPowerOfTwo(S32 target_width, S32 target_height, S32 max_dim = MAX_IMAGE_SIZE);
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE) { biasedScaleToPowerOfTwo(getWidth(), getHeight(), max_dim); }
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
//BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
@@ -287,7 +291,7 @@ public:
// LLImageBase
/*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1);
/*virtual*/ U8* reallocateData(S32 size);
/*virtual*/ U8* reallocateData(S32 size = -1);
/*virtual*/ void dump();
/*virtual*/ void sanityCheck();

View File

@@ -1,4 +1,4 @@
/**
/**
* @file llimagej2coj.cpp
* @brief This is an implementation of JPEG2000 encode/decode using OpenJPEG.
*
@@ -35,9 +35,7 @@
const char* fallbackEngineInfoLLImageJ2CImpl()
{
static std::string version_string =
std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
+ opj_version();
static std::string version_string = std::string("OpenJPEG: ") + opj_version();
return version_string.c_str();
}
@@ -186,7 +184,15 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
{
opj_image_destroy(image);
}
#if 0
std::stringstream filename;
filename << "err" << (int)base.getRawDiscardLevel() << "_" << rand() << ".jp2";
FILE* file = fopen(filename.str().c_str(), "wb");
if (file) {
fwrite(base.getData(), base.getDataSize(), 1, file);
fclose(file);
}
#endif
base.decodeFailed();
return TRUE; // done
}

View File

@@ -66,7 +66,7 @@ static const F32 MAX_FIELD_OF_VIEW = 175.f * DEG_TO_RAD;
// roll(), pitch(), yaw()
// etc...
LL_ALIGN_PREFIX(16)
class LLCamera
: public LLCoordFrame
{
@@ -114,7 +114,7 @@ public:
};
private:
LLPlane mAgentPlanes[7]; //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
LL_ALIGN_16(LLPlane mAgentPlanes[7]); //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
U8 mPlaneMask[8]; // 8 for alignment
F32 mView; // angle between top and bottom frustum planes in radians.
@@ -122,13 +122,13 @@ private:
S32 mViewHeightInPixels; // for ViewHeightInPixels() only
F32 mNearPlane;
F32 mFarPlane;
LLPlane mLocalPlanes[4];
LL_ALIGN_16(LLPlane mLocalPlanes[4]);
F32 mFixedDistance; // Always return this distance, unless < 0
LLVector3 mFrustCenter; // center of frustum and radius squared for ultra-quick exclusion test
F32 mFrustRadiusSquared;
LLPlane mWorldPlanes[PLANE_NUM];
LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
LL_ALIGN_16(LLPlane mWorldPlanes[PLANE_NUM]);
LL_ALIGN_16(LLPlane mHorizPlanes[HORIZ_PLANE_NUM]);
U32 mPlaneCount; //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
@@ -214,7 +214,7 @@ protected:
void calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom);
void calculateFrustumPlanesFromWindow(F32 x1, F32 y1, F32 x2, F32 y2);
void calculateWorldFrustumPlanes();
};
} LL_ALIGN_POSTFIX(16);
#endif

View File

@@ -111,7 +111,7 @@ public:
protected:
LLVector4a mColumns[3];
LL_ALIGN_16(LLVector4a mColumns[3]);
};

View File

@@ -34,7 +34,7 @@
class LLMatrix4a
{
public:
LLVector4a mMatrix[4];
LL_ALIGN_16(LLVector4a mMatrix[4]);
inline void clear()
{

View File

@@ -37,6 +37,7 @@
#include "v3math.h"
#include "llvector4a.h"
#include <vector>
#include <boost/pool/pool.hpp>
#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
#define OCT_ERRS LL_ERRS("OctreeErrors")
@@ -46,6 +47,7 @@
#endif
extern U32 gOctreeMaxCapacity;
extern U32 gOctreeReserveCapacity;
#if LL_DEBUG
#define LL_OCTREE_PARANOIA_CHECK 0
#else
@@ -56,6 +58,106 @@ extern U32 gOctreeMaxCapacity;
template <class T> class LLOctreeNode;
#include "lltimer.h"
//#define LL_OCTREE_STATS
#define LL_OCTREE_POOLS
#ifdef LL_OCTREE_STATS
class OctreeStats : public LLSingleton<OctreeStats>
{
public:
OctreeStats() :
mPeriodNodesCreated(0),
mPeriodNodesDestroyed(0),
mPeriodAllocs(0),
mPeriodFrees(0),
mPeriodLargestSize(0),
mTotalNodes(0),
mTotalAllocs(0),
mTotalFrees(0),
mLargestSize(0),
mTotalSize(0)
{
mTotalTimer.reset();
mPeriodTimer.reset();
}
void addNode()
{
++mTotalNodes;
++mPeriodNodesCreated;
}
void removeNode()
{
--mTotalNodes;
++mPeriodNodesDestroyed;
}
void realloc(U32 old_count, U32 new_count)
{
if(new_count >= old_count)
mTotalSize+=new_count-old_count;
else
mTotalSize-=old_count-new_count;
if(mLargestSize < new_count)
mLargestSize = new_count;
if(mPeriodLargestSize < new_count)
mPeriodLargestSize = new_count;
++mTotalAllocs;
++mPeriodAllocs;
}
void free(U32 count)
{
mTotalSize-=count;
++mTotalFrees;
++mPeriodFrees;
}
void dump()
{
llinfos << llformat("Lifetime: Allocs:(+%u|-%u) Allocs/s: (+%lf|-%lf) Nodes: %u AccumSize: %llubytes Avg: %lf LargestSize: %u",
mTotalAllocs,
mTotalFrees,
F64(mTotalAllocs)/mTotalTimer.getElapsedTimeF64(),
F64(mTotalFrees)/mTotalTimer.getElapsedTimeF64(),
mTotalNodes,
mTotalSize*sizeof(LLPointer<LLRefCount>),
F64(mTotalSize)/F64(mTotalNodes),
mLargestSize
) << llendl;
llinfos << llformat("Timeslice: Allocs:(+%u|-%u) Allocs/s: (+%lf|-%lf) Nodes:(+%u|-%u) LargestSize: %u",
mPeriodAllocs,
mPeriodFrees,
F64(mPeriodAllocs)/mPeriodTimer.getElapsedTimeF64(),
F64(mPeriodFrees)/mPeriodTimer.getElapsedTimeF64(),
mPeriodNodesCreated,
mPeriodNodesDestroyed,
mPeriodLargestSize
) << llendl;
mPeriodNodesCreated=0;
mPeriodNodesDestroyed=0;
mPeriodAllocs=0;
mPeriodFrees=0;
mPeriodLargestSize=0;
mPeriodTimer.reset();
}
private:
//Accumulate per timer update
U32 mPeriodNodesCreated;
U32 mPeriodNodesDestroyed;
U32 mPeriodAllocs;
U32 mPeriodFrees;
U32 mPeriodLargestSize;
LLTimer mPeriodTimer;
//Accumulate through entire app lifetime:
U32 mTotalNodes;
U32 mTotalAllocs;
U32 mTotalFrees;
U32 mLargestSize;
U64 mTotalSize;
LLTimer mTotalTimer;
};
#endif //LL_OCTREE_STATS
template <class T>
class LLOctreeListener: public LLTreeListener<T>
{
@@ -129,25 +231,52 @@ public:
typedef LLOctreeTraveler<T> oct_traveler;
typedef LLTreeTraveler<T> tree_traveler;
typedef LLPointer<T>* element_list;
typedef LLPointer<T>* element_iter;
typedef const LLPointer<T>* const_element_iter;
typedef std::vector<LLPointer<T> > element_list;
typedef typename element_list::iterator element_iter;
typedef typename element_list::const_iterator const_element_iter;
typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter;
typedef LLOctreeNode<T>** child_list;
typedef LLOctreeNode<T>** child_iter;
typedef LLTreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
/*void* operator new(size_t size)
#ifdef LL_OCTREE_POOLS
struct octree_pool_alloc
{
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
static char * malloc(const std::size_t bytes)
{ return (char *)ll_aligned_malloc_16(bytes); }
static void free(char * const block)
{ ll_aligned_free_16(block); }
};
static boost::pool<octree_pool_alloc>& getPool(const std::size_t& size)
{
static boost::pool<octree_pool_alloc> sPool((std::size_t)LL_NEXT_ALIGNED_ADDRESS((char*)size),1200);
llassert_always((std::size_t)LL_NEXT_ALIGNED_ADDRESS((char*)size) == sPool.get_requested_size());
return sPool;
}
void* operator new(size_t size)
{
return getPool(size).malloc();
}
void operator delete(void* ptr)
{
getPool(sizeof(LLOctreeNode<T>)).free(ptr);
}
#else
void* operator new(size_t size)
{
return ll_aligned_malloc_16(size);
}
void operator delete(void* ptr)
{
ll_aligned_free_16(ptr);
}*/
}
#endif
LLOctreeNode( const LLVector4a& center,
const LLVector4a& size,
@@ -156,8 +285,16 @@ public:
: mParent((oct_node*)parent),
mOctant(octant)
{
mData = NULL;
mDataEnd = NULL;
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->addNode();
#endif
if(gOctreeReserveCapacity)
mData.reserve(gOctreeReserveCapacity);
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->realloc(0,mData.capacity());
#endif
//mData = NULL;
//mDataEnd = NULL;
mCenter = center;
mSize = size;
@@ -168,24 +305,31 @@ public:
mOctant = ((oct_node*) mParent)->getOctant(mCenter);
}
mElementCount = 0;
//mElementCount = 0;
clearChildren();
}
virtual ~LLOctreeNode()
{
{
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->removeNode();
#endif
BaseType::destroyListeners();
for (U32 i = 0; i < mElementCount; ++i)
//for (U32 i = 0; i < mElementCount; ++i)
for (U32 i = 0; i < mData.size(); ++i)
{
mData[i]->setBinIndex(-1);
mData[i] = NULL;
}
free(mData);
mData = NULL;
mDataEnd = NULL;
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->free(mData.capacity());
#endif
//free(mData);
//mData = NULL;
//mDataEnd = NULL;
for (U32 i = 0; i < getChildCount(); i++)
{
@@ -285,14 +429,14 @@ public:
void accept(oct_traveler* visitor) { visitor->visit(this); }
virtual bool isLeaf() const { return mChildCount == 0; }
U32 getElementCount() const { return mElementCount; }
bool isEmpty() const { return mElementCount == 0; }
U32 getElementCount() const { return mData.size(); }
bool isEmpty() const { return mData.size() == 0; }
//element_list& getData() { return mData; }
//const element_list& getData() const { return mData; }
element_iter getDataBegin() { return mData; }
element_iter getDataEnd() { return mDataEnd; }
const_element_iter getDataBegin() const { return mData; }
const_element_iter getDataEnd() const { return mDataEnd; }
element_iter getDataBegin() { return mData.begin(); }
element_iter getDataEnd() { return mData.end(); }
const_element_iter getDataBegin() const { return mData.begin(); }
const_element_iter getDataEnd() const { return mData.end(); }
U32 getChildCount() const { return mChildCount; }
oct_node* getChild(U32 index) { return mChild[index]; }
@@ -372,7 +516,10 @@ public:
if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) ||
(data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity)))
{ //it belongs here
mElementCount++;
/*mElementCount++;
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->realloc(mElementCount-1,mElementCount);
#endif
mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
//avoid unref on uninitialized memory
@@ -380,7 +527,18 @@ public:
mData[mElementCount-1] = data;
mDataEnd = mData + mElementCount;
data->setBinIndex(mElementCount-1);
data->setBinIndex(mElementCount-1);*/
#ifdef LL_OCTREE_STATS
U32 old_cap = mData.capacity();
#endif
data->setBinIndex(mData.size());
mData.push_back(data);
#ifdef LL_OCTREE_STATS
if(old_cap != mData.capacity())
OctreeStats::getInstance()->realloc(old_cap,mData.capacity());
#endif
BaseType::insert(data);
return true;
}
@@ -415,7 +573,10 @@ public:
if( lt == 0x7 )
{
mElementCount++;
/*mElementCount++;
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->realloc(mElementCount-1,mElementCount);
#endif
mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
//avoid unref on uninitialized memory
@@ -423,7 +584,17 @@ public:
mData[mElementCount-1] = data;
mDataEnd = mData + mElementCount;
data->setBinIndex(mElementCount-1);
data->setBinIndex(mElementCount-1);*/
#ifdef LL_OCTREE_STATS
U32 old_cap = mData.capacity();
#endif
data->setBinIndex(mData.size());
mData.push_back(data);
#ifdef LL_OCTREE_STATS
if(old_cap != mData.capacity())
OctreeStats::getInstance()->realloc(old_cap,mData.capacity());
#endif
BaseType::insert(data);
return true;
}
@@ -476,10 +647,10 @@ public:
void _remove(T* data, S32 i)
{ //precondition -- mElementCount > 0, idx is in range [0, mElementCount)
OctreeGuard::checkGuarded(this);
mElementCount--;
//mElementCount--;
data->setBinIndex(-1);
if (mElementCount > 0)
/* if (mElementCount > 0)
{
if (mElementCount != i)
{
@@ -488,15 +659,51 @@ public:
}
mData[mElementCount] = NULL; //needed for unref
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->realloc(mElementCount+1,mElementCount);
#endif
mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
mDataEnd = mData+mElementCount;
}
else
{
mData[0] = NULL; //needed for unref
#ifdef LL_OCTREE_STATS
OctreeStats::getInstance()->free(1);
#endif
free(mData);
mData = NULL;
mDataEnd = NULL;
}*/
if(mData.size())
{
if((mData.size()-1)!=i)
{
mData[i] = mData[mData.size()-1];
mData[i]->setBinIndex(i);
}
#ifdef LL_OCTREE_STATS
U32 old_cap = mData.capacity();
#endif
mData.pop_back();
if( mData.size() == gOctreeReserveCapacity ||
(mData.size() > gOctreeReserveCapacity && mData.capacity() > gOctreeReserveCapacity + mData.size() - 1 - (mData.size() - gOctreeReserveCapacity - 1) % 4))
{
//Shrink to lowest possible (reserve)+4*i size.. Say reserve is 5, here are [size,capacity] pairs. [10,13],[9,9],[8,9],[7,9],[6,9],[5,5],[4,5],[3,5],[2,5],[1,5],[0,5]
//For Windows: We always assume vs2010 or later, which support this c++11 feature with no configuration needed.
//For GCC: __cplusplus >= 201103L indicates C++11 support. __GXX_EXPERIMENTAL_CXX0X being set indicates experimental c++0x support. C++11 support replaces C++0x support.
// std::vector::shrink_to_fit was added to GCCs C++0x implementation in version 4.5.0.
#if defined(LL_WINDOWS) || __cplusplus >= 201103L || (defined(__GXX_EXPERIMENTAL_CXX0X) && __GNUC_MINOR__ >= 5)
mData.shrink_to_fit();
#else
std::vector<LLPointer<T> >(mData.begin(), mData.end()).swap(mData); //Need to confirm this works on OSX..
#endif
}
#ifdef LL_OCTREE_STATS
if(old_cap != mData.capacity())
OctreeStats::getInstance()->realloc(old_cap,mData.capacity());
#endif
}
this->notifyRemoval(data);
@@ -508,7 +715,8 @@ public:
OctreeGuard::checkGuarded(this);
S32 i = data->getBinIndex();
if (i >= 0 && i < (S32)mElementCount)
//if (i >= 0 && i < mElementCount)
if (i >= 0 && i < (S32)mData.size())
{
if (mData[i] == data)
{ //found it
@@ -552,7 +760,8 @@ public:
void removeByAddress(T* data)
{
OctreeGuard::checkGuarded(this);
for (U32 i = 0; i < mElementCount; ++i)
//for (U32 i = 0; i < mElementCount; ++i)
for (U32 i = 0; i < mData.size(); ++i)
{
if (mData[i] == data)
{ //we have data
@@ -660,8 +869,6 @@ public:
listener->handleChildRemoval(this, getChild(index));
}
if (destroy)
{
mChild[index]->destroy();
@@ -733,8 +940,8 @@ protected:
U32 mChildCount;
element_list mData;
element_iter mDataEnd;
U32 mElementCount;
//element_iter mDataEnd;
//U32 mElementCount;
};

View File

@@ -42,6 +42,8 @@
// The plane normal = [A, B, C]
// The closest approach = D / sqrt(A*A + B*B + C*C)
LL_ALIGN_PREFIX(16)
class LLPlane
{
public:
@@ -100,7 +102,7 @@ public:
private:
LLVector4a mV;
};
} LL_ALIGN_POSTFIX(16);

View File

@@ -124,8 +124,8 @@ public:
if (end_y < mBottom) clip_y = end_y - mBottom;
// clip_? and delta_? should have same sign, since starting point is in rect
// so ratios will be positive
F32 ratio_x = ((F32)clip_x / (F32)delta_x);
F32 ratio_y = ((F32)clip_y / (F32)delta_y);
F32 ratio_x = delta_x ? ((F32)clip_x / (F32)delta_x) : 0.f;
F32 ratio_y = delta_y ? ((F32)clip_y / (F32)delta_y) : 0.f;
if (ratio_x > ratio_y)
{
// clip along x direction

View File

@@ -67,11 +67,10 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
#include <xmmintrin.h>
#include <emmintrin.h>
#include "llmemory.h"
#include "llsimdtypes.h"
#include "llsimdtypes.inl"

View File

@@ -62,6 +62,7 @@ inline LLSimdScalar operator/(const LLSimdScalar& a, const LLSimdScalar& b)
inline LLSimdScalar operator-(const LLSimdScalar& a)
{
static LL_ALIGN_16(const U32 signMask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000 };
ll_assert_aligned(signMask,16);
return _mm_xor_ps(*reinterpret_cast<const LLQuad*>(signMask), a);
}
@@ -146,6 +147,7 @@ inline LLSimdScalar& LLSimdScalar::operator/=(const LLSimdScalar& rhs)
inline LLSimdScalar LLSimdScalar::getAbs() const
{
static const LL_ALIGN_16(U32 F_ABS_MASK_4A[4]) = { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
ll_assert_aligned(F_ABS_MASK_4A,16);
return _mm_and_ps( mQ, *reinterpret_cast<const LLQuad*>(F_ABS_MASK_4A));
}

View File

@@ -24,6 +24,7 @@
* $/LicenseInfo$
*/
#include "llmemory.h"
#include "llmath.h"
#include "llquantize.h"
@@ -44,7 +45,10 @@ extern const LLVector4a LL_V4A_EPSILON = reinterpret_cast<const LLVector4a&> ( F
assert(dst != NULL);
assert(bytes > 0);
assert((bytes % sizeof(F32))== 0);
ll_assert_aligned(src,16);
ll_assert_aligned(dst,16);
assert(bytes%16==0);
F32* end = dst + (bytes / sizeof(F32) );
if (bytes > 64)
@@ -189,6 +193,8 @@ void LLVector4a::quantize16( const LLVector4a& low, const LLVector4a& high )
LLVector4a oneOverDelta;
{
static LL_ALIGN_16( const F32 F_TWO_4A[4] ) = { 2.f, 2.f, 2.f, 2.f };
ll_assert_aligned(F_TWO_4A,16);
LLVector4a two; two.load4a( F_TWO_4A );
// Here we use _mm_rcp_ps plus one round of newton-raphson

View File

@@ -32,6 +32,7 @@ class LLRotation;
#include <assert.h>
#include "llpreprocessor.h"
#include "llmemory.h"
///////////////////////////////////
// FIRST TIME USERS PLEASE READ
@@ -46,6 +47,7 @@ class LLRotation;
// LLVector3/LLVector4.
/////////////////////////////////
LL_ALIGN_PREFIX(16)
class LLVector4a
{
public:
@@ -90,6 +92,7 @@ public:
LLVector4a()
{ //DO NOT INITIALIZE -- The overhead is completely unnecessary
ll_assert_aligned(this,16);
}
LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f)
@@ -313,7 +316,7 @@ public:
private:
LLQuad mQ;
};
} LL_ALIGN_POSTFIX(16);
inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p)
{

View File

@@ -27,6 +27,7 @@
#ifndef LL_VECTOR4LOGICAL_H
#define LL_VECTOR4LOGICAL_H
#include "llmemory.h"
////////////////////////////
// LLVector4Logical
@@ -77,6 +78,7 @@ public:
inline LLVector4Logical& invert()
{
static const LL_ALIGN_16(U32 allOnes[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
ll_assert_aligned(allOnes,16);
mQ = _mm_andnot_ps( mQ, *(LLQuad*)(allOnes) );
return *this;
}

View File

@@ -29,6 +29,10 @@
#include "llmath.h"
#include <set>
#if !LL_WINDOWS
#include <stdint.h>
#endif
#include <cmath>
#include "llerror.h"
#include "llmemtype.h"
@@ -91,17 +95,6 @@ const S32 SCULPT_MIN_AREA_DETAIL = 1;
extern BOOL gDebugGL;
void assert_aligned(void* ptr, uintptr_t alignment)
{
#if 0
uintptr_t t = (uintptr_t) ptr;
if (t%alignment != 0)
{
llerrs << "Alignment check failed." << llendl;
}
#endif
}
BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
{
LLVector3 test = (pt2-pt1)%(pt3-pt2);
@@ -6963,14 +6956,14 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
if (num_verts)
{
mPositions = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
assert_aligned(mPositions, 16);
ll_assert_aligned(mPositions, 16);
mNormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
assert_aligned(mNormals, 16);
ll_assert_aligned(mNormals, 16);
//pad texture coordinate block end to allow for QWORD reads
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
assert_aligned(mTexCoords, 16);
ll_assert_aligned(mTexCoords, 16);
}
else
{
@@ -6991,17 +6984,21 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
{
S32 new_verts = mNumVertices+1;
S32 new_size = new_verts*16;
// S32 old_size = mNumVertices*16;
S32 old_size = mNumVertices*16;
//positions
mPositions = (LLVector4a*) realloc(mPositions, new_size);
mPositions = (LLVector4a*) ll_aligned_realloc_16(mPositions, new_size, old_size);
ll_assert_aligned(mPositions,16);
//normals
mNormals = (LLVector4a*) realloc(mNormals, new_size);
mNormals = (LLVector4a*) ll_aligned_realloc_16(mNormals, new_size, old_size);
ll_assert_aligned(mNormals,16);
//tex coords
new_size = ((new_verts*8)+0xF) & ~0xF;
mTexCoords = (LLVector2*) realloc(mTexCoords, new_size);
old_size = ((mNumVertices*8)+0xF) & ~0xF;
mTexCoords = (LLVector2*) ll_aligned_realloc_16(mTexCoords, new_size, old_size);
ll_assert_aligned(mTexCoords,16);
//just clear binormals
@@ -7054,7 +7051,8 @@ void LLVolumeFace::pushIndex(const U16& idx)
S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
if (new_size != old_size)
{
mIndices = (U16*) realloc(mIndices, new_size);
mIndices = (U16*) ll_aligned_realloc_16(mIndices, new_size, old_size);
ll_assert_aligned(mIndices,16);
}
mIndices[mNumIndices++] = idx;
@@ -7095,12 +7093,12 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
}
//allocate new buffer space
mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a));
assert_aligned(mPositions, 16);
mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a));
assert_aligned(mNormals, 16);
mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF);
assert_aligned(mTexCoords, 16);
mPositions = (LLVector4a*) ll_aligned_realloc_16(mPositions, new_count*sizeof(LLVector4a), mNumVertices*sizeof(LLVector4a));
ll_assert_aligned(mPositions, 16);
mNormals = (LLVector4a*) ll_aligned_realloc_16(mNormals, new_count*sizeof(LLVector4a), mNumVertices*sizeof(LLVector4a));
ll_assert_aligned(mNormals, 16);
mTexCoords = (LLVector2*) ll_aligned_realloc_16(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF, (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF);
ll_assert_aligned(mTexCoords, 16);
mNumVertices = new_count;
@@ -7146,7 +7144,7 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
new_count = mNumIndices + face.mNumIndices;
//allocate new index buffer
mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF);
mIndices = (U16*) ll_aligned_realloc_16(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF, (mNumIndices*sizeof(U16)+0xF) & ~0xF);
//get destination address into new index buffer
U16* dst_idx = mIndices+mNumIndices;

View File

@@ -37,6 +37,15 @@
class LLVolumeTriangle : public LLRefCount
{
public:
void* operator new(size_t size)
{
return ll_aligned_malloc_16(size);
}
void operator delete(void* ptr)
{
ll_aligned_free_16(ptr);
}
LLVolumeTriangle()
{
mBinIndex = -1;
@@ -58,7 +67,7 @@ public:
}
LLVector4a mPositionGroup;
LL_ALIGN_16(LLVector4a mPositionGroup);
const LLVector4a* mV[3];
U16 mIndex[3];
@@ -78,6 +87,16 @@ class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
{
public:
void* operator new(size_t size)
{
return ll_aligned_malloc_16(size);
}
void operator delete(void* ptr)
{
ll_aligned_free_16(ptr);
}
LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node);
~LLVolumeOctreeListener();
@@ -104,8 +123,8 @@ public:
public:
LLVector4a mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects)
LLVector4a mExtents[2]; // extents (min, max) of this node and all its children
LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects)
LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
};
class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>

View File

@@ -308,9 +308,10 @@ LLAtomicU32 Stats::llsd_body_count;
LLAtomicU32 Stats::llsd_body_parse_error;
LLAtomicU32 Stats::raw_body_count;
// Called from BufferedCurlEasyRequest::setStatusAndReason.
// The only allowed values for 'status' are S <= status < S+20, where S={100,200,300,400,500}.
U32 Stats::status2index(U32 status)
{
llassert_always(status >= 100 && status < 600 && (status % 100) < 20); // Max value 519.
return (status - 100) / 100 * 20 + status % 100; // Returns 0..99 (for status 100..519).
}
@@ -418,6 +419,7 @@ void cleanupCurl(void)
if (CurlMultiHandle::getTotalMultiHandles() != 0)
llwarns << "Not all CurlMultiHandle objects were destroyed!" << llendl;
AIStateMachine::flush();
clearCommandQueue();
Stats::print();
ssl_cleanup();
@@ -491,12 +493,10 @@ void Stats::print(void)
// Even more strict, BufferedCurlEasyRequest may not be created directly either, only as
// base class of ThreadSafeBufferedCurlEasyRequest.
llassert(BufferedCurlEasyRequest_count == ThreadSafeBufferedCurlEasyRequest_count);
// Each AICurlEasyRequestStateMachine is responsible for exactly one easy handle.
llassert(easy_handles >= AICurlEasyRequest_count);
// Each AICurlEasyRequestStateMachine has one AICurlEasyRequest member.
llassert(AICurlEasyRequest_count >= AICurlEasyRequestStateMachine_count);
// AIFIXME: is this really always the case? And why?
llassert(easy_handles <= ResponderBase_count);
llassert(easy_handles <= S32(ResponderBase_count));
}
} // namespace AICurlInterface
@@ -546,6 +546,9 @@ void CurlEasyHandle::handle_easy_error(CURLcode code)
// Throws AICurlNoEasyHandle.
CurlEasyHandle::CurlEasyHandle(void) : mActiveMultiHandle(NULL), mErrorBuffer(NULL), mQueuedForRemoval(false)
#ifdef DEBUG_CURLIO
, mDebug(false)
#endif
#ifdef SHOW_ASSERT
, mRemovedPerCommand(true)
#endif
@@ -589,6 +592,12 @@ CurlEasyHandle::~CurlEasyHandle()
llassert(!mActiveMultiHandle);
curl_easy_cleanup(mEasyHandle);
Stats::easy_cleanup_calls++;
#ifdef DEBUG_CURLIO
if (mDebug)
{
debug_curl_remove_easy(mEasyHandle);
}
#endif
}
//static
@@ -761,17 +770,17 @@ void CurlEasyRequest::setoptString(CURLoption option, std::string const& value)
setopt(option, value.c_str());
}
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size)
void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive)
{
llassert_always(postdata->data());
DoutCurl("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\".");
setPostField(postdata); // Make sure the data stays around until we don't need it anymore.
setPost_raw(size, postdata->data());
setPost_raw(size, postdata->data(), keepalive);
}
void CurlEasyRequest::setPost_raw(U32 size, char const* data)
void CurlEasyRequest::setPost_raw(U32 size, char const* data, bool keepalive)
{
if (!data)
{
@@ -781,7 +790,7 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data)
// The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default.
addHeader("Expect:");
if (size > 0)
if (size > 0 && keepalive)
{
addHeader("Connection: keep-alive");
addHeader("Keep-alive: 300");
@@ -1006,6 +1015,8 @@ CURLcode CurlEasyRequest::curlCtxCallback(CURL* curl, void* sslctx, void* parm)
options |= SSL_OP_NO_TLSv1_1;
}
#else
// This is expected when you compile against the headers of a version < 1.0.1 and then link at runtime with version >= 1.0.1.
// Don't do that.
llassert_always(!need_renegotiation_hack);
#endif
SSL_CTX_set_options(ctx, options);
@@ -1226,6 +1237,20 @@ void CurlEasyRequest::removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy
mHandleEventsTarget->removed_from_multi_handle(curl_easy_request_w);
}
void CurlEasyRequest::bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w)
{
if (mHandleEventsTarget)
mHandleEventsTarget->bad_file_descriptor(curl_easy_request_w);
}
#ifdef SHOW_ASSERT
void CurlEasyRequest::queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w)
{
if (mHandleEventsTarget)
mHandleEventsTarget->queued_for_removal(curl_easy_request_w);
}
#endif
PerHostRequestQueuePtr CurlEasyRequest::getPerHostPtr(void)
{
if (!mPerHostPtr)
@@ -1289,7 +1314,17 @@ void BufferedCurlEasyRequest::timed_out(void)
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput);
if (mResponder->needsHeaders())
{
send_buffer_events_to(NULL); // Revoke buffer events: we sent them to the responder.
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
}
mResponder = NULL;
}
void BufferedCurlEasyRequest::bad_socket(void)
{
mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "File descriptor went bad! Aborted.", sChannels, mOutput);
if (mResponder->needsHeaders())
{
send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder.
}
mResponder = NULL;
}
@@ -1348,11 +1383,22 @@ void BufferedCurlEasyRequest::prepRequest(AICurlEasyRequest_wat& curl_easy_reque
curl_easy_request_w->setReadCallback(&curlReadCallback, lockobj);
curl_easy_request_w->setHeaderCallback(&curlHeaderCallback, lockobj);
bool allow_cookies = headers.hasHeader("Cookie");
// Allow up to ten redirects.
if (responder->followRedir())
{
curl_easy_request_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
// This is needed (at least) for authentication after temporary redirection
// to id.secondlife.com for marketplace.secondlife.com.
allow_cookies = true;
}
if (allow_cookies)
{
// Given an empty or non-existing file or by passing the empty string (""),
// this option will enable cookies for this curl handle, making it understand
// and parse received cookies and then use matching cookies in future requests.
curl_easy_request_w->setopt(CURLOPT_COOKIEFILE, "");
}
// Keep responder alive.
@@ -1398,3 +1444,18 @@ CurlMultiHandle::~CurlMultiHandle()
}
} // namespace AICurlPrivate
#if LL_LINUX
extern "C" {
// Keep linker happy.
const SSL_METHOD *SSLv2_client_method(void)
{
// Never used.
llassert_always(false);
return NULL;
}
}
#endif

View File

@@ -208,6 +208,10 @@ struct AICurlEasyHandleEvents {
virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
#ifdef SHOW_ASSERT
virtual void queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
#endif
// Avoid compiler warning.
virtual ~AICurlEasyHandleEvents() { }
};
@@ -271,6 +275,11 @@ class AICurlEasyRequest {
// Queue a command to remove this request from the multi session (or cancel a queued command to add it).
void removeRequest(void);
#ifdef DEBUG_CURLIO
// Turn on/off debug output.
void debug(bool debug) { AICurlEasyRequest_wat(*mBufferedCurlEasyRequest)->debug(debug); }
#endif
private:
// The actual pointer to the ThreadSafeBufferedCurlEasyRequest instance.
AICurlPrivate::BufferedCurlEasyRequestPtr mBufferedCurlEasyRequest;

View File

@@ -40,7 +40,8 @@ enum curleasyrequeststatemachine_state_type {
AICurlEasyRequestStateMachine_timedOut, // This must be smaller than the rest, so they always overrule.
AICurlEasyRequestStateMachine_finished,
AICurlEasyRequestStateMachine_removed, // The removed states must be largest two, so they are never ignored.
AICurlEasyRequestStateMachine_removed_after_finished
AICurlEasyRequestStateMachine_removed_after_finished,
AICurlEasyRequestStateMachine_bad_file_descriptor
};
char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state) const
@@ -54,6 +55,7 @@ char const* AICurlEasyRequestStateMachine::state_str_impl(state_type run_state)
AI_CASE_RETURN(AICurlEasyRequestStateMachine_finished);
AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed);
AI_CASE_RETURN(AICurlEasyRequestStateMachine_removed_after_finished);
AI_CASE_RETURN(AICurlEasyRequestStateMachine_bad_file_descriptor);
}
return "UNKNOWN STATE";
}
@@ -94,6 +96,24 @@ void AICurlEasyRequestStateMachine::removed_from_multi_handle(AICurlEasyRequest_
set_state(mFinished ? AICurlEasyRequestStateMachine_removed_after_finished : AICurlEasyRequestStateMachine_removed);
}
// CURL-THREAD
void AICurlEasyRequestStateMachine::bad_file_descriptor(AICurlEasyRequest_wat&)
{
if (!mFinished)
{
mFinished = true;
set_state(AICurlEasyRequestStateMachine_bad_file_descriptor);
}
}
#ifdef SHOW_ASSERT
// CURL-THREAD
void AICurlEasyRequestStateMachine::queued_for_removal(AICurlEasyRequest_wat&)
{
llassert(mFinished || mTimedOut); // See AICurlEasyRequestStateMachine::removed_from_multi_handle
}
#endif
void AICurlEasyRequestStateMachine::multiplex_impl(void)
{
mSetStateLock.lock();
@@ -207,6 +227,11 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void)
break;
}
case AICurlEasyRequestStateMachine_bad_file_descriptor:
{
AICurlEasyRequest_wat(*mCurlEasyRequest)->bad_socket();
abort();
}
}
}

View File

@@ -81,6 +81,14 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa
// Called after this curl easy handle was removed from a multi handle.
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
// Called when the curl thread detected that the socket of this handle has become unusable.
/*virtual*/ void bad_file_descriptor(AICurlEasyRequest_wat&);
#ifdef SHOW_ASSERT
// Called when a command was added to remove this easy handle.
/*virtual*/ void queued_for_removal(AICurlEasyRequest_wat&);
#endif
protected:
// AIStateMachine implementations.

View File

@@ -56,12 +56,17 @@ PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname
//static
void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
{
if (instance->lastone())
if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap.
{
// The viewer can be have left main() we can't access the global sInstanceMap anymore.
if (LLApp::isStopped())
{
return;
}
instance_map_wat instance_map_w(sInstanceMap);
// It is possible that 'lastone' is not up to date anymore.
// It is possible that 'exactly_two_left' is not up to date anymore.
// Therefore, recheck the condition now that we have locked sInstanceMap.
if (!instance->lastone())
if (!instance->exactly_two_left())
{
// Some other thread added this host in the meantime.
return;
@@ -87,13 +92,13 @@ void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance)
bool PerHostRequestQueue::throttled() const
{
llassert(mAdded <= curl_concurrent_connections_per_host);
return mAdded == curl_concurrent_connections_per_host;
llassert(mAdded <= int(curl_concurrent_connections_per_host));
return mAdded == int(curl_concurrent_connections_per_host);
}
void PerHostRequestQueue::added_to_multi_handle(void)
{
llassert(mAdded < curl_concurrent_connections_per_host);
llassert(mAdded < int(curl_concurrent_connections_per_host));
++mAdded;
}

View File

@@ -118,7 +118,7 @@ class PerHostRequestQueue {
class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue {
public:
RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { }
bool lastone(void) const { llassert(mReferenceCount >= 2); return mReferenceCount == 2; }
bool exactly_two_left(void) const { return mReferenceCount == 2; }
private:
// Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero.

View File

@@ -119,6 +119,7 @@ inline CURLMcode check_multi_code(CURLMcode code) { AICurlInterface::Stats::mult
bool curlThreadIsRunning(void);
void wakeUpCurlThread(void);
void stopCurlThread(void);
void clearCommandQueue(void);
#define DECLARE_SETOPT(param_type) \
CURLcode setopt(CURLoption option, param_type parameter)
@@ -200,12 +201,19 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
// In case it's added after being removed.
void add_queued(void) { mQueuedForRemoval = false; }
#ifdef DEBUG_CURLIO
void debug(bool debug) { if (mDebug) debug_curl_remove_easy(mEasyHandle); if (debug) debug_curl_add_easy(mEasyHandle); mDebug = debug; }
#endif
private:
CURL* mEasyHandle;
CURLM* mActiveMultiHandle;
mutable char* mErrorBuffer;
AIPostFieldPtr mPostField; // This keeps the POSTFIELD data alive for as long as the easy handle exists.
bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal.
#ifdef DEBUG_CURLIO
bool mDebug;
#endif
#ifdef SHOW_ASSERT
public:
bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread.
@@ -269,11 +277,11 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven
// and the CurlEasyRequest destructed.
class CurlEasyRequest : public CurlEasyHandle {
private:
void setPost_raw(U32 size, char const* data);
void setPost_raw(U32 size, char const* data, bool keepalive);
public:
void setPost(U32 size) { setPost_raw(size, NULL); }
void setPost(AIPostFieldPtr const& postdata, U32 size);
void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); }
void setPost(U32 size, bool keepalive = true) { setPost_raw(size, NULL, keepalive); }
void setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive = true);
void setPost(char const* data, U32 size, bool keepalive = true) { setPost(new AIPostField(data), size, keepalive); }
void setoptString(CURLoption option, std::string const& value);
void addHeader(char const* str);
void addHeaders(AIHTTPHeaders const& headers);
@@ -412,6 +420,11 @@ class CurlEasyRequest : public CurlEasyHandle {
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
public:
/*virtual*/ void bad_file_descriptor(AICurlEasyRequest_wat& curl_easy_request_w);
#ifdef SHOW_ASSERT
/*virtual*/ void queued_for_removal(AICurlEasyRequest_wat& curl_easy_request_w);
#endif
};
// This class adds input/output buffers to the request and hooks up the libcurl callbacks to use those buffers.
@@ -430,6 +443,9 @@ class BufferedCurlEasyRequest : public CurlEasyRequest {
// Called if libcurl doesn't deliver within AIHTTPTimeoutPolicy::mMaximumTotalDelay seconds.
void timed_out(void);
// Called if the underlaying socket went bad (ie, when accidently closed by a buggy library).
void bad_socket(void);
// Called after removed_from_multi_handle was called.
void processOutput(void);

View File

@@ -286,14 +286,36 @@ enum refresh_t {
empty_and_complete = complete|empty
};
// A class with info for each socket that is in use by curl.
class CurlSocketInfo
{
public:
CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj);
~CurlSocketInfo();
void set_action(int action);
void mark_dead(void) { set_action(CURL_POLL_NONE); mDead = true; }
curl_socket_t getSocketFd(void) const { return mSocketFd; }
AICurlEasyRequest& getEasyRequest(void) { return mEasyRequest; }
private:
MultiHandle& mMultiHandle;
CURL const* mEasy;
curl_socket_t mSocketFd;
int mAction;
bool mDead;
AICurlEasyRequest mEasyRequest;
LLPointer<HTTPTimeout> mTimeout;
};
class PollSet
{
public:
PollSet(void);
// Add/remove a filedescriptor to/from mFileDescriptors.
void add(curl_socket_t s);
void remove(curl_socket_t s);
void add(CurlSocketInfo* sp);
void remove(CurlSocketInfo* sp);
// Copy mFileDescriptors to an internal fd_set that is returned by access().
// Returns if all fds could be copied (complete) and/or if the resulting fd_set is empty.
@@ -307,8 +329,8 @@ class PollSet
curl_socket_t get_max_fd(void) const { return mMaxFdSet; }
#endif
// Return true if a filedescriptor is set in mFileDescriptors (used for debugging).
bool contains(curl_socket_t s) const;
// Return a pointer to the corresponding CurlSocketInfo if a filedescriptor is set in mFileDescriptors, or NULL if s is not set.
CurlSocketInfo* contains(curl_socket_t s) const;
// Return true if a filedescriptor is set in mFdSet.
bool is_set(curl_socket_t s) const;
@@ -323,7 +345,7 @@ class PollSet
void next(void); // Advance to next filedescriptor.
private:
curl_socket_t* mFileDescriptors;
CurlSocketInfo** mFileDescriptors;
int mNrFds; // The number of filedescriptors in the array.
int mNext; // The index of the first file descriptor to start copying, the next call to refresh().
@@ -332,8 +354,8 @@ class PollSet
#if !WINDOWS_CODE
curl_socket_t mMaxFd; // The largest filedescriptor in the array, or CURL_SOCKET_BAD when it is empty.
curl_socket_t mMaxFdSet; // The largest filedescriptor set in mFdSet by refresh(), or CURL_SOCKET_BAD when it was empty.
std::vector<curl_socket_t> mCopiedFileDescriptors; // Filedescriptors copied by refresh to mFdSet.
std::vector<curl_socket_t>::iterator mIter; // Index into mCopiedFileDescriptors for next(); loop variable.
std::vector<CurlSocketInfo*> mCopiedFileDescriptors; // Filedescriptors copied by refresh to mFdSet.
std::vector<CurlSocketInfo*>::iterator mIter; // Index into mCopiedFileDescriptors for next(); loop variable.
#else
unsigned int mIter; // Index into fd_set::fd_array.
#endif
@@ -359,7 +381,7 @@ class PollSet
static size_t const MAXSIZE = llmax(1024, FD_SETSIZE);
// Create an empty PollSet.
PollSet::PollSet(void) : mFileDescriptors(new curl_socket_t [MAXSIZE]),
PollSet::PollSet(void) : mFileDescriptors(new CurlSocketInfo* [MAXSIZE]),
mNrFds(0), mNext(0)
#if !WINDOWS_CODE
, mMaxFd(-1), mMaxFdSet(-1)
@@ -369,17 +391,17 @@ PollSet::PollSet(void) : mFileDescriptors(new curl_socket_t [MAXSIZE]),
}
// Add filedescriptor s to the PollSet.
void PollSet::add(curl_socket_t s)
void PollSet::add(CurlSocketInfo* sp)
{
llassert_always(mNrFds < (int)MAXSIZE);
mFileDescriptors[mNrFds++] = s;
mFileDescriptors[mNrFds++] = sp;
#if !WINDOWS_CODE
mMaxFd = llmax(mMaxFd, s);
mMaxFd = llmax(mMaxFd, sp->getSocketFd());
#endif
}
// Remove filedescriptor s from the PollSet.
void PollSet::remove(curl_socket_t s)
void PollSet::remove(CurlSocketInfo* sp)
{
// The number of open filedescriptors is relatively small,
// and on top of that we rather do something CPU intensive
@@ -391,15 +413,15 @@ void PollSet::remove(curl_socket_t s)
// back, keeping it compact and keeping the filedescriptors
// in the same order (which is supposedly their priority).
//
// The general case is where mFileDescriptors contains s at an index
// The general case is where mFileDescriptors contains sp at an index
// between 0 and mNrFds:
// mNrFds = 6
// v
// index: 0 1 2 3 4 5
// a b c s d e
// This function should never be called unless s is actually in mFileDescriptors,
// as a result of a previous call to PollSet::add().
// This function should never be called unless sp is actually in mFileDescriptors,
// as a result of a previous call to PollSet::add(sp).
llassert(mNrFds > 0);
// Correct mNrFds for when the descriptor is removed.
@@ -409,17 +431,18 @@ void PollSet::remove(curl_socket_t s)
// v
// index: 0 1 2 3 4 5
// a b c s d e
curl_socket_t cur = mFileDescriptors[i]; // cur = 'e'
curl_socket_t const s = sp->getSocketFd();
CurlSocketInfo* cur = mFileDescriptors[i]; // cur = 'e'
#if !WINDOWS_CODE
curl_socket_t max = -1;
#endif
while (cur != s)
while (cur != sp)
{
llassert(i > 0);
curl_socket_t next = mFileDescriptors[--i]; // next = 'd'
CurlSocketInfo* next = mFileDescriptors[--i]; // next = 'd'
mFileDescriptors[i] = cur; // Overwrite 'd' with 'e'.
#if !WINDOWS_CODE
max = llmax(max, cur); // max is the maximum value in 'i' or higher.
max = llmax(max, cur->getSocketFd()); // max is the maximum value in 'i' or higher.
#endif
cur = next; // cur = 'd'
// i NrFds = 5
@@ -427,21 +450,21 @@ void PollSet::remove(curl_socket_t s)
// index: 0 1 2 3 4
// a b c s e // cur = 'd'
//
// Next loop iteration: next = 's', overwrite 's' with 'd', cur = 's'; loop terminates.
// Next loop iteration: next = 'sp', overwrite 'sp' with 'd', cur = 'sp'; loop terminates.
// i NrFds = 5
// v v
// index: 0 1 2 3 4
// a b c d e // cur = 's'
// a b c d e // cur = 'sp'
}
llassert(cur == s);
llassert(cur == sp);
// At this point i was decremented once more and points to the element before the old s.
// i NrFds = 5
// v v
// index: 0 1 2 3 4
// a b c d e // max = llmax('d', 'e')
// If mNext pointed to an element before s, it should be left alone. Otherwise, if mNext pointed
// to s it must now point to 'd', or if it pointed beyond 's' it must be decremented by 1.
// If mNext pointed to an element before sp, it should be left alone. Otherwise, if mNext pointed
// to sp it must now point to 'd', or if it pointed beyond 'sp' it must be decremented by 1.
if (mNext > i) // i is where s was.
--mNext;
@@ -451,8 +474,8 @@ void PollSet::remove(curl_socket_t s)
{
while (i > 0)
{
curl_socket_t next = mFileDescriptors[--i];
max = llmax(max, next);
CurlSocketInfo* next = mFileDescriptors[--i];
max = llmax(max, next->getSocketFd());
}
mMaxFd = max;
llassert(mMaxFd < s);
@@ -487,12 +510,12 @@ void PollSet::remove(curl_socket_t s)
#endif
}
bool PollSet::contains(curl_socket_t fd) const
CurlSocketInfo* PollSet::contains(curl_socket_t fd) const
{
for (int i = 0; i < mNrFds; ++i)
if (mFileDescriptors[i] == fd)
return true;
return false;
if (mFileDescriptors[i]->getSocketFd() == fd)
return mFileDescriptors[i];
return NULL;
}
inline bool PollSet::is_set(curl_socket_t fd) const
@@ -536,7 +559,7 @@ refresh_t PollSet::refresh(void)
// Calculate mMaxFdSet.
// Run over FD_SETSIZE - 1 elements, starting at mNext, wrapping to 0 when we reach the end.
int max = -1, i = mNext, count = 0;
while (++count < FD_SETSIZE) { max = llmax(max, mFileDescriptors[i]); if (++i == mNrFds) i = 0; }
while (++count < FD_SETSIZE) { max = llmax(max, mFileDescriptors[i]->getSocketFd()); if (++i == mNrFds) i = 0; }
mMaxFdSet = max;
#endif
}
@@ -556,7 +579,7 @@ refresh_t PollSet::refresh(void)
mNext = i;
return not_complete_not_empty;
}
FD_SET(mFileDescriptors[i], &mFdSet);
FD_SET(mFileDescriptors[i]->getSocketFd(), &mFdSet);
#if !WINDOWS_CODE
mCopiedFileDescriptors.push_back(mFileDescriptors[i]);
#endif
@@ -603,7 +626,7 @@ void PollSet::reset(void)
else
{
mIter = mCopiedFileDescriptors.begin();
if (!FD_ISSET(*mIter, &mFdSet))
if (!FD_ISSET((*mIter)->getSocketFd(), &mFdSet))
next();
}
#endif
@@ -614,7 +637,7 @@ inline curl_socket_t PollSet::get(void) const
#if WINDOWS_CODE
return (mIter >= mFdSet.fd_count) ? CURL_SOCKET_BAD : mFdSet.fd_array[mIter];
#else
return (mIter == mCopiedFileDescriptors.end()) ? CURL_SOCKET_BAD : *mIter;
return (mIter == mCopiedFileDescriptors.end()) ? CURL_SOCKET_BAD : (*mIter)->getSocketFd();
#endif
}
@@ -625,7 +648,7 @@ void PollSet::next(void)
++mIter;
#else
llassert(mIter != mCopiedFileDescriptors.end()); // Only call next() if the last call to get() didn't return -1.
while (++mIter != mCopiedFileDescriptors.end() && !FD_ISSET(*mIter, &mFdSet));
while (++mIter != mCopiedFileDescriptors.end() && !FD_ISSET((*mIter)->getSocketFd(), &mFdSet));
#endif
}
@@ -743,26 +766,8 @@ std::ostream& operator<<(std::ostream& os, DebugFdSet const& s)
}
#endif
// A class with info for each socket that is in use by curl.
class CurlSocketInfo
{
public:
CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj);
~CurlSocketInfo();
void set_action(int action);
private:
MultiHandle& mMultiHandle;
CURL const* mEasy;
curl_socket_t mSocketFd;
int mAction;
AICurlEasyRequest mEasyRequest;
LLPointer<HTTPTimeout> mTimeout;
};
CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socket_t s, int action, ThreadSafeBufferedCurlEasyRequest* lockobj) :
mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mEasyRequest(lockobj)
mMultiHandle(multi_handle), mEasy(easy), mSocketFd(s), mAction(CURL_POLL_NONE), mDead(false), mEasyRequest(lockobj)
{
llassert(*AICurlEasyRequest_wat(*mEasyRequest) == easy);
mMultiHandle.assign(s, this);
@@ -785,23 +790,28 @@ CurlSocketInfo::~CurlSocketInfo()
void CurlSocketInfo::set_action(int action)
{
if (mDead)
{
return;
}
Dout(dc::curl, "CurlSocketInfo::set_action(" << action_str(mAction) << " --> " << action_str(action) << ") [" << (void*)mEasyRequest.get_ptr().get() << "]");
int toggle_action = mAction ^ action;
mAction = action;
if ((toggle_action & CURL_POLL_IN))
{
if ((action & CURL_POLL_IN))
mMultiHandle.mReadPollSet->add(mSocketFd);
mMultiHandle.mReadPollSet->add(this);
else
mMultiHandle.mReadPollSet->remove(mSocketFd);
mMultiHandle.mReadPollSet->remove(this);
}
if ((toggle_action & CURL_POLL_OUT))
{
if ((action & CURL_POLL_OUT))
mMultiHandle.mWritePollSet->add(mSocketFd);
mMultiHandle.mWritePollSet->add(this);
else
{
mMultiHandle.mWritePollSet->remove(mSocketFd);
mMultiHandle.mWritePollSet->remove(this);
// The following is a bit of a hack, needed because of the lack of proper timeout callbacks in libcurl.
// The removal of CURL_POLL_OUT could be part of the SSL handshake, therefore check if we're already connected:
@@ -838,6 +848,9 @@ class AICurlThread : public LLThread
// MAIN-THREAD
void stop_thread(void) { mRunning = false; wakeup_thread(); }
// MAIN-THREAD
apr_status_t join_thread(void);
protected:
virtual void run(void);
void wakeup(AICurlMultiHandle_wat const& multi_handle_w);
@@ -1065,6 +1078,10 @@ void AICurlThread::wakeup_thread(void)
DoutEntering(dc::curl, "AICurlThread::wakeup_thread");
llassert(is_main_thread());
// If we are already exiting the viewer then return immediately.
if (!mRunning)
return;
// Try if curl thread is still awake and if so, pass the new commands directly.
if (mWakeUpMutex.tryLock())
{
@@ -1106,6 +1123,17 @@ void AICurlThread::wakeup_thread(void)
#endif
}
apr_status_t AICurlThread::join_thread(void)
{
apr_status_t retval = APR_SUCCESS;
if (sInstance)
{
apr_thread_join(&retval, sInstance->mAPRThreadp);
delete sInstance;
}
return retval;
}
void AICurlThread::wakeup(AICurlMultiHandle_wat const& multi_handle_w)
{
DoutEntering(dc::curl, "AICurlThread::wakeup");
@@ -1251,6 +1279,26 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w)
}
}
// Return true if fd is a 'bad' socket.
static bool is_bad(curl_socket_t fd, bool for_writing)
{
fd_set tmp;
FD_ZERO(&tmp);
FD_SET(fd, &tmp);
fd_set* readfds = for_writing ? NULL : &tmp;
fd_set* writefds = for_writing ? &tmp : NULL;
#if !WINDOWS_CODE
int nfds = fd + 1;
#else
int nfds = 64;
#endif
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10;
int ret = select(nfds, readfds, writefds, NULL, &timeout);
return ret == -1;
}
// The main loop of the curl thread.
void AICurlThread::run(void)
{
@@ -1262,7 +1310,7 @@ void AICurlThread::run(void)
{
// If mRunning is true then we can only get here if mWakeUpFd != CURL_SOCKET_BAD.
llassert(mWakeUpFd != CURL_SOCKET_BAD);
// Copy the next batch of file descriptors from the PollSets mFiledescriptors into their mFdSet.
// Copy the next batch of file descriptors from the PollSets mFileDescriptors into their mFdSet.
multi_handle_w->mReadPollSet->refresh();
refresh_t wres = multi_handle_w->mWritePollSet->refresh();
// Add wake up fd if any, and pass NULL to select() if a set is empty.
@@ -1379,6 +1427,51 @@ void AICurlThread::run(void)
if (ready == -1)
{
llwarns << "select() failed: " << errno << ", " << strerror(errno) << llendl;
if (errno == EBADF)
{
// Somewhere (fmodex?) one of our file descriptors was closed. Try to recover by finding out which.
llassert_always(!is_bad(mWakeUpFd, false)); // We can't recover from this.
PollSet* found = NULL;
// Run over all read file descriptors.
multi_handle_w->mReadPollSet->refresh();
multi_handle_w->mReadPollSet->reset();
curl_socket_t fd;
while ((fd = multi_handle_w->mReadPollSet->get()) != CURL_SOCKET_BAD)
{
if (is_bad(fd, false))
{
found = multi_handle_w->mReadPollSet;
break;
}
multi_handle_w->mReadPollSet->next();
}
if (!found)
{
// Try all write file descriptors.
refresh_t wres = multi_handle_w->mWritePollSet->refresh();
if (!(wres & empty))
{
multi_handle_w->mWritePollSet->reset();
while ((fd = multi_handle_w->mWritePollSet->get()) != CURL_SOCKET_BAD)
{
if (is_bad(fd, true))
{
found = multi_handle_w->mWritePollSet;
break;
}
multi_handle_w->mWritePollSet->next();
}
}
}
llassert_always(found); // It makes no sense to continue if we can't recover.
// Find the corresponding CurlSocketInfo
CurlSocketInfo* sp = found->contains(fd);
llassert_always(sp); // fd was just *read* from this sp.
sp->mark_dead(); // Make sure it's never used again.
AICurlEasyRequest_wat curl_easy_request_w(*sp->getEasyRequest());
curl_easy_request_w->pause(CURLPAUSE_ALL); // Keep libcurl at bay.
curl_easy_request_w->bad_file_descriptor(curl_easy_request_w); // Make the main thread cleanly terminate this transaction.
}
continue;
}
// Clock count used for timeouts.
@@ -1609,7 +1702,9 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons
ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get();
#endif
mAddedEasyRequests.erase(iter);
#if CWDEBUG
Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles.");
#endif
// Attempt to add a queued request, if any.
PerHostRequestQueue_wat(*per_host)->add_queued_to(this);
@@ -1816,7 +1911,7 @@ bool HTTPTimeout::data_received(size_t n)
// | | | | | | | | | | | | | |
bool HTTPTimeout::lowspeed(size_t bytes)
{
DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")");
//DoutCurlEntering("HTTPTimeout::lowspeed(" << bytes << ")"); commented out... too spammy for normal use.
// The algorithm to determine if we timed out if different from how libcurls CURLOPT_LOW_SPEED_TIME works.
//
@@ -1994,12 +2089,11 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
#if LOWRESTIMER
llinfos << "Hostname seems to have been still in the DNS cache." << llendl;
#else
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but DNS lookup did not occur according to timings. Expected CURLE_COULDNT_RESOLVE_PROXY or CURLE_COULDNT_RESOLVE_HOST!" << llendl;
llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and DNS lookup did not occur according to timings. Apparently the resolve attempt timed out (bad network?)" << llendl;
llassert(connect_time == 0);
llassert(appconnect_time == 0);
llassert(pretransfer_time == 0);
llassert(starttransfer_time == 0);
// Fatal error for diagnostics.
return;
#endif
}
@@ -2022,11 +2116,10 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch
#endif
)
{
llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but connection did not occur according to timings. Expected CURLE_COULDNT_CONNECT!" << llendl;
llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and connection did not occur according to timings: apparently the connect attempt timed out (bad network?)" << llendl;
llassert(appconnect_time == 0);
llassert(pretransfer_time == 0);
llassert(starttransfer_time == 0);
// Fatal error for diagnostics.
return;
}
// If connect_time is almost equal to namelookup_time, then it was just set because it was already connected.
@@ -2142,16 +2235,30 @@ void stopCurlThread(void)
if (AICurlThread::sInstance)
{
AICurlThread::sInstance->stop_thread();
int count = 101;
int count = 401;
while(--count && !AICurlThread::sInstance->isStopped())
{
ms_sleep(10);
}
Dout(dc::curl, "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((100 - count) * 10) << "ms.");
// Clear the command queue, for a cleaner cleanup.
if (AICurlThread::sInstance->isStopped())
{
// isStopped() returns true somewhere at the end of run(),
// but that doesn't mean the thread really stopped: it still
// needs to destroy it's static variables.
// If we don't join here, then there is a chance that the
// curl thread will crash when using globals that we (the
// main thread) will have destroyed before it REALLY finished.
AICurlThread::sInstance->join_thread(); // Wait till it is REALLY done.
}
llinfos << "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << llendl;
}
}
void clearCommandQueue(void)
{
// Clear the command queue now in order to avoid the global deinitialization order fiasco.
command_queue_wat command_queue_w(command_queue);
command_queue_w->clear();
}
}
//-----------------------------------------------------------------------------
@@ -2161,7 +2268,17 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const&
{
mStatus = status;
mReason = reason;
AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++;
if (status >= 100 && status < 600 && (status % 100) < 20)
{
// Only count statistic for sane values.
AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++;
}
// Sanity check. If the server replies with a redirect status then we better have that option turned on!
if ((status >= 300 && status < 400) && mResponder && !mResponder->redirect_status_ok())
{
llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl;
}
}
void BufferedCurlEasyRequest::processOutput(void)
@@ -2172,7 +2289,7 @@ void BufferedCurlEasyRequest::processOutput(void)
CURLcode code;
AITransferInfo info;
getResult(&code, &info);
if (code == CURLE_OK)
if (code == CURLE_OK && mStatus != HTTP_INTERNAL_ERROR)
{
getinfo(CURLINFO_RESPONSE_CODE, &responseCode);
// If getResult code is CURLE_OK then we should have decoded the first header line ourselves.
@@ -2185,7 +2302,7 @@ void BufferedCurlEasyRequest::processOutput(void)
else
{
responseCode = HTTP_INTERNAL_ERROR;
responseReason = curl_easy_strerror(code);
responseReason = (code == CURLE_OK) ? mReason : std::string(curl_easy_strerror(code));
setopt(CURLOPT_FRESH_CONNECT, TRUE);
}
@@ -2306,23 +2423,31 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
std::string::iterator pos2 = std::find(pos1, end, ' ');
if (pos2 != end) ++pos2;
std::string::iterator pos3 = std::find(pos2, end, '\r');
U32 status;
U32 status = 0;
std::string reason;
if (pos3 != end && std::isdigit(*pos1))
{
status = atoi(&header_line[pos1 - begin]);
reason.assign(pos2, pos3);
}
else
if (!(status >= 100 && status < 600 && (status % 100) < 20)) // Sanity check on the decoded status.
{
if (status == 0)
{
reason = "Header parse error.";
llwarns << "Received broken header line from server: \"" << header << "\"" << llendl;
}
else
{
reason = "Unexpected HTTP status.";
llwarns << "Received unexpected status value from server (" << status << "): \"" << header << "\"" << llendl;
}
// Either way, this status value is not understood (or taken into account).
// Set it to internal error so that the rest of code treats it as an error.
status = HTTP_INTERNAL_ERROR;
reason = "Header parse error.";
llwarns << "Received broken header line from server: \"" << header << "\"" << llendl;
}
{
self_w->received_HTTP_header();
self_w->setStatusAndReason(status, reason);
}
self_w->received_HTTP_header();
self_w->setStatusAndReason(status, reason);
return header_len;
}
@@ -2351,14 +2476,25 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size
}
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, void* user_ptr)
{
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
if (infotype == CURLINFO_HEADER_OUT && size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0))
{
request->mDebugIsHeadOrGetMethod = true;
}
#ifdef DEBUG_CURLIO
if (!debug_curl_print_debug(handle))
{
return 0;
}
#endif
#ifdef CWDEBUG
using namespace ::libcwd;
BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr;
std::ostringstream marker;
marker << (void*)request->get_lockobj();
marker << (void*)request->get_lockobj() << ' ';
libcw_do.push_marker();
libcw_do.marker().assign(marker.str().data(), marker.str().size());
if (!debug::channels::dc::curlio.is_on())
@@ -2382,8 +2518,6 @@ int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void*
break;
case CURLINFO_HEADER_OUT:
LibcwDoutStream << "H< ";
if (size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0))
request->mDebugIsHeadOrGetMethod = true;
break;
case CURLINFO_DATA_IN:
LibcwDoutStream << "D> ";
@@ -2557,6 +2691,14 @@ void AICurlEasyRequest::removeRequest(void)
}
}
}
{
AICurlEasyRequest_wat curl_easy_request_w(*get());
// As soon as the lock on the command queue is released, it could be picked up by
// the curl thread and executed. At that point it (already) demands that the easy
// request either timed out or is finished. So, to avoid race conditions that already
// has to be true right now. The call to queued_for_removal() checks this.
curl_easy_request_w->queued_for_removal(curl_easy_request_w);
}
#endif
// Add a command to remove this request from the multi session to the command queue.
command_queue_w->push_back(Command(*this, cmd_remove));

View File

@@ -107,6 +107,20 @@ void AIHTTPReceivedHeaders::addHeader(std::string const& key, std::string const&
{
mContainer = new Container;
}
else if (equal(key, "set-cookie"))
{
// If a cookie with this name already exists, replace it.
std::string const name = value.substr(0, value.find('='));
container_t::iterator const end = mContainer->mKeyValuePairs.end();
for (container_t::iterator header = mContainer->mKeyValuePairs.begin(); header != end; ++header)
{
if (equal(header->first, "set-cookie") && header->second.substr(0, header->second.find('=')) == name)
{
header->second = value;
return;
}
}
}
mContainer->mKeyValuePairs.insert(container_t::value_type(key, value));
}
@@ -151,3 +165,20 @@ std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers)
return os;
}
//static
bool AIHTTPReceivedHeaders::equal(std::string const& key1, std::string const& key2)
{
if (key1.length() != key2.length())
{
return false;
}
for (std::string::const_iterator i1 = key1.begin(), i2 = key2.begin(); i1 != key1.end(); ++i1, ++i2)
{
if ((*i1 ^ *i2) & 0xdf != 0)
{
return false;
}
}
return true;
}

View File

@@ -132,6 +132,9 @@ class AIHTTPReceivedHeaders {
// Add a header.
void addHeader(std::string const& key, std::string const& value);
// Swap headers with another container.
void swap(AIHTTPReceivedHeaders& headers) { LLPointer<Container>::swap(mContainer, headers.mContainer); }
// Return true if there are no headers associated with this object.
bool empty(void) const { return !mContainer || mContainer->mKeyValuePairs.empty(); }
@@ -147,6 +150,9 @@ class AIHTTPReceivedHeaders {
// For debug purposes.
friend std::ostream& operator<<(std::ostream& os, AIHTTPReceivedHeaders const& headers);
// Returns true if the two keys compare equal (ie, "Set-Cookie" == "set-cookie").
static bool equal(std::string const& key1, std::string const& key2);
private:
struct Container : public LLThreadSafeRefCount {
container_t mKeyValuePairs;

View File

@@ -646,6 +646,12 @@ AIHTTPTimeoutPolicyBase transfer_18s(AIHTTPTimeoutPolicyBase::getDebugSettingsCu
transactionOp18s
);
// This used to be '30 seconds'.
Transaction transactionOp30s(30);
AIHTTPTimeoutPolicyBase transfer_30s(AIHTTPTimeoutPolicyBase::getDebugSettingsCurlTimeout(),
transactionOp30s
);
// This used to be '300 seconds'. We derive this from the hardcoded result so users can't mess with it.
Transaction transactionOp300s(300);
AIHTTPTimeoutPolicyBase transfer_300s(HTTPTimeoutPolicy_default,
@@ -820,6 +826,7 @@ P(accountingCostResponder);
P(agentStateResponder);
P(assetUploadResponder);
P(asyncConsoleResponder);
P(avatarPickerResponder);
P(authHandler);
P(avatarNameResponder);
P2(baseCapabilitiesComplete, transfer_18s);
@@ -838,6 +845,7 @@ P(estateChangeInfoResponder);
P(eventPollResponder);
P(fetchInventoryResponder);
P(fnPtrResponder);
P2(groupMemberDataResponder, transfer_300s);
P2(groupProposalBallotResponder, transfer_300s);
P(homeLocationResponder);
P(HTTPGetResponder);
@@ -850,6 +858,7 @@ P(lcl_responder);
P(MPImportGetResponder);
P(MPImportPostResponder);
P(mapLayerResponder);
P2(maturityPreferences, transfer_30s);
P(mediaTypeResponder);
P(meshDecompositionResponder);
P(meshHeaderResponder);
@@ -889,6 +898,7 @@ P(viewerStatsResponder);
P(viewerVoiceAccountProvisionResponder);
P(voiceCallCapResponder);
P(voiceClientCapResponder);
P(webProfileResponders);
P(wholeModelFeeResponder);
P(wholeModelUploadResponder);
P2(XMLRPCResponder, connect_40s);

View File

@@ -6,6 +6,7 @@
#include <cstdlib>
#include <stdarg.h>
#include <cstring>
#include <algorithm>
#include "llpreprocessor.h"
#include <curl/curl.h>
#define COMPILING_DEBUG_LIBCURL_CC
@@ -528,19 +529,66 @@ std::ostream& operator<<(std::ostream& os, EvBitmask const& bitmask)
return os;
}
// Set this to limit the curl debug output to specific easy handles.
bool gDebugCurlTerse = false;
namespace {
std::vector<CURL*> handles;
inline bool print_debug(CURL* handle)
{
if (!gDebugCurlTerse)
return true;
return std::find(handles.begin(), handles.end(), handle) != handles.end();
}
} // namespace
void debug_curl_add_easy(CURL* handle)
{
std::vector<CURL*>::iterator iter = std::find(handles.begin(), handles.end(), handle);
if (iter == handles.end())
{
handles.push_back(handle);
Dout(dc::warning, "debug_curl_add_easy(" << (void*)handle << "): added");
}
llassert(print_debug(handle));
}
void debug_curl_remove_easy(CURL* handle)
{
std::vector<CURL*>::iterator iter = std::find(handles.begin(), handles.end(), handle);
if (iter != handles.end())
{
handles.erase(iter);
Dout(dc::warning, "debug_curl_remove_easy(" << (void*)handle << "): removed");
}
llassert(!print_debug(handle));
}
bool debug_curl_print_debug(CURL* handle)
{
return print_debug(handle);
}
extern "C" {
void debug_curl_easy_cleanup(CURL* handle)
{
curl_easy_cleanup(handle);
Dout(dc::curl, "curl_easy_cleanup(" << (AICURL*)handle << ")");
if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_cleanup(" << (AICURL*)handle << ")");
}
}
CURL* debug_curl_easy_duphandle(CURL* handle)
{
CURL* ret;
ret = curl_easy_duphandle(handle);
Dout(dc::curl, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret);
if (!print_debug(handle)) return ret;
Dout(dc::curltr, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret);
return ret;
}
@@ -548,11 +596,12 @@ char* debug_curl_easy_escape(CURL* curl, char* url, int length)
{
char* ret;
ret = curl_easy_escape(curl, url, length);
Dout(dc::curl, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"');
if (!print_debug(curl)) return ret;
Dout(dc::curltr, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"');
return ret;
}
CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...)
CURLcode debug_curl_easy_getinfo(CURL* handle, CURLINFO info, ...)
{
CURLcode ret;
va_list ap;
@@ -566,26 +615,27 @@ CURLcode debug_curl_easy_getinfo(CURL* curl, CURLINFO info, ...)
va_start(ap, info);
param.some_ptr = va_arg(ap, void*);
va_end(ap);
ret = curl_easy_getinfo(curl, info, param.some_ptr);
ret = curl_easy_getinfo(handle, info, param.some_ptr);
if (!print_debug(handle)) return ret;
if (info == CURLINFO_PRIVATE)
{
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret);
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret);
}
else
{
switch((info & CURLINFO_TYPEMASK))
{
case CURLINFO_STRING:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " <unchanged> ") << "\" }) = " << ret);
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " <unchanged> ") << "\" }) = " << ret);
break;
case CURLINFO_LONG:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret);
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret);
break;
case CURLINFO_DOUBLE:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret);
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret);
break;
case CURLINFO_SLIST:
Dout(dc::curl, "curl_easy_getinfo(" << (AICURL*)curl << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret);
Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret);
break;
}
}
@@ -596,7 +646,8 @@ CURL* debug_curl_easy_init(void)
{
CURL* ret;
ret = curl_easy_init();
Dout(dc::curl, "curl_easy_init() = " << (AICURL*)ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_easy_init() = " << (AICURL*)ret);
return ret;
}
@@ -604,7 +655,8 @@ CURLcode debug_curl_easy_pause(CURL* handle, int bitmask)
{
CURLcode ret;
ret = curl_easy_pause(handle, bitmask);
Dout(dc::curl, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret);
if (!print_debug(handle)) return ret;
Dout(dc::curltr, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret);
return ret;
}
@@ -612,19 +664,21 @@ CURLcode debug_curl_easy_perform(CURL* handle)
{
CURLcode ret;
ret = curl_easy_perform(handle);
Dout(dc::curl, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret);
if (!print_debug(handle)) return ret;
Dout(dc::curltr, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret);
return ret;
}
void debug_curl_easy_reset(CURL* handle)
{
curl_easy_reset(handle);
Dout(dc::curl, "curl_easy_reset(" << (AICURL*)handle << ")");
if (!print_debug(handle)) return;
Dout(dc::curltr, "curl_easy_reset(" << (AICURL*)handle << ")");
}
CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
{
CURLcode ret;
CURLcode ret = CURLE_OBSOLETE50; // Suppress compiler warning.
va_list ap;
union param_type {
long along;
@@ -656,7 +710,10 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
case CURLOPTTYPE_LONG:
{
ret = curl_easy_setopt(handle, option, param.along);
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret);
if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret);
}
if (option == CURLOPT_POSTFIELDSIZE)
{
postfieldsize = param.along;
@@ -666,7 +723,8 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
case CURLOPTTYPE_OBJECTPOINT:
{
ret = curl_easy_setopt(handle, option, param.ptr);
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curl)
if (!print_debug(handle)) break;
LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curltr)
LibcwDoutStream << "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", ";
// For a subset of all options that take a char*, print the string passed.
if (option == CURLOPT_PROXY || // Set HTTP proxy to use. The parameter should be a char* to a zero terminated string holding the host name or dotted IP address.
@@ -717,11 +775,11 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
if (option == CURLOPT_HTTPHEADER && param.ptr)
{
debug::Indent indent(2);
Dout(dc::curl, "HTTP Headers:");
Dout(dc::curltr, "HTTP Headers:");
struct curl_slist* list = (struct curl_slist*)param.ptr;
while (list)
{
Dout(dc::curl, '"' << list->data << '"');
Dout(dc::curltr, '"' << list->data << '"');
list = list->next;
}
}
@@ -729,12 +787,18 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...)
}
case CURLOPTTYPE_FUNCTIONPOINT:
ret = curl_easy_setopt(handle, option, param.ptr);
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
}
break;
case CURLOPTTYPE_OFF_T:
{
ret = curl_easy_setopt(handle, option, param.offset);
Dout(dc::curl, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
if (print_debug(handle))
{
Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
}
if (option == CURLOPT_POSTFIELDSIZE_LARGE)
{
postfieldsize = (long)param.offset;
@@ -751,7 +815,8 @@ char const* debug_curl_easy_strerror(CURLcode errornum)
{
char const* ret;
ret = curl_easy_strerror(errornum);
Dout(dc::curl, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"');
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"');
return ret;
}
@@ -759,35 +824,38 @@ char* debug_curl_easy_unescape(CURL* curl, char* url, int inlength, int* outleng
{
char* ret;
ret = curl_easy_unescape(curl, url, inlength, outlength);
Dout(dc::curl, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"');
if (!print_debug(curl)) return ret;
Dout(dc::curltr, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"');
return ret;
}
void debug_curl_free(char* ptr)
{
curl_free(ptr);
Dout(dc::curl, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")");
if (gDebugCurlTerse) return;
Dout(dc::curltr, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")");
}
time_t debug_curl_getdate(char const* datestring, time_t* now)
{
time_t ret;
ret = curl_getdate(datestring, now);
Dout(dc::curl, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "<erroneous non-NULL value for 'now'>") << ") = " << ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "<erroneous non-NULL value for 'now'>") << ") = " << ret);
return ret;
}
void debug_curl_global_cleanup(void)
{
curl_global_cleanup();
Dout(dc::curl, "curl_global_cleanup()");
Dout(dc::curltr, "curl_global_cleanup()");
}
CURLcode debug_curl_global_init(long flags)
{
CURLcode ret;
ret = curl_global_init(flags);
Dout(dc::curl, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret);
Dout(dc::curltr, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret);
return ret;
}
@@ -795,7 +863,8 @@ CURLMcode debug_curl_multi_add_handle(CURLM* multi_handle, CURL* easy_handle)
{
CURLMcode ret;
ret = curl_multi_add_handle(multi_handle, easy_handle);
Dout(dc::curl, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
return ret;
}
@@ -803,7 +872,8 @@ CURLMcode debug_curl_multi_assign(CURLM* multi_handle, curl_socket_t sockfd, voi
{
CURLMcode ret;
ret = curl_multi_assign(multi_handle, sockfd, sockptr);
Dout(dc::curl, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret);
return ret;
}
@@ -811,7 +881,8 @@ CURLMcode debug_curl_multi_cleanup(CURLM* multi_handle)
{
CURLMcode ret;
ret = curl_multi_cleanup(multi_handle);
Dout(dc::curl, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret);
return ret;
}
@@ -819,7 +890,8 @@ CURLMsg* debug_curl_multi_info_read(CURLM* multi_handle, int* msgs_in_queue)
{
CURLMsg* ret;
ret = curl_multi_info_read(multi_handle, msgs_in_queue);
Dout(dc::curl, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret);
return ret;
}
@@ -827,7 +899,8 @@ CURLM* debug_curl_multi_init(void)
{
CURLM* ret;
ret = curl_multi_init();
Dout(dc::curl, "curl_multi_init() = " << (AICURLM*)ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_init() = " << (AICURLM*)ret);
return ret;
}
@@ -835,13 +908,14 @@ CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle)
{
CURLMcode ret;
ret = curl_multi_remove_handle(multi_handle, easy_handle);
Dout(dc::curl, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
if (!print_debug(easy_handle)) return ret;
Dout(dc::curltr, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret);
return ret;
}
CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...)
{
CURLMcode ret;
CURLMcode ret = CURLM_UNKNOWN_OPTION; // Suppress compiler warning.
va_list ap;
union param_type {
long along;
@@ -871,19 +945,23 @@ CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...)
{
case CURLOPTTYPE_LONG:
ret = curl_multi_setopt(multi_handle, option, param.along);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret);
if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret);
break;
case CURLOPTTYPE_OBJECTPOINT:
ret = curl_multi_setopt(multi_handle, option, param.ptr);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
break;
case CURLOPTTYPE_FUNCTIONPOINT:
ret = curl_multi_setopt(multi_handle, option, param.ptr);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret);
break;
case CURLOPTTYPE_OFF_T:
ret = curl_multi_setopt(multi_handle, option, param.offset);
Dout(dc::curl, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
if (gDebugCurlTerse) break;
Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret);
break;
default: // Stop compiler complaining about no default.
break;
@@ -895,7 +973,8 @@ CURLMcode debug_curl_multi_socket_action(CURLM* multi_handle, curl_socket_t sock
{
CURLMcode ret;
ret = curl_multi_socket_action(multi_handle, sockfd, ev_bitmask, running_handles);
Dout(dc::curl, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) <<
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) <<
", " << EvBitmask(ev_bitmask) << ", {" << (ret == CURLM_OK ? *running_handles : 0) << "}) = " << ret);
return ret;
}
@@ -904,7 +983,8 @@ char const* debug_curl_multi_strerror(CURLMcode errornum)
{
char const* ret;
ret = curl_multi_strerror(errornum);
Dout(dc::curl, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"');
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"');
return ret;
}
@@ -912,21 +992,24 @@ struct curl_slist* debug_curl_slist_append(struct curl_slist* list, char const*
{
struct curl_slist* ret;
ret = curl_slist_append(list, string);
Dout(dc::curl, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret);
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret);
return ret;
}
void debug_curl_slist_free_all(struct curl_slist* list)
{
curl_slist_free_all(list);
Dout(dc::curl, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")");
if (gDebugCurlTerse) return;
Dout(dc::curltr, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")");
}
char* debug_curl_unescape(char const* url, int length)
{
char* ret;
ret = curl_unescape(url, length);
Dout(dc::curl, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"');
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"');
return ret;
}
@@ -934,7 +1017,8 @@ char* debug_curl_version(void)
{
char* ret;
ret = curl_version();
Dout(dc::curl, "curl_version() = \"" << ret << '"');
if (gDebugCurlTerse) return ret;
Dout(dc::curltr, "curl_version() = \"" << ret << '"');
return ret;
}

View File

@@ -86,4 +86,9 @@ extern char* debug_curl_version(void);
#endif // !COMPILING_DEBUG_LIBCURL_CC
extern bool gDebugCurlTerse; // With this set,
void debug_curl_add_easy(CURL* handle); // only output debug output for easy handles added with this function.
void debug_curl_remove_easy(CURL* handle);
bool debug_curl_print_debug(CURL* handle);
#endif // DEBUG_LIBCURL

View File

@@ -24,12 +24,12 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llavatarnamecache.h"
#include "llcachename.h" // we wrap this system
#include "llcontrol.h" // For LLCachedControl
#include "llframetimer.h"
#include "llhttpclient.h"
#include "llsd.h"
@@ -93,6 +93,9 @@ namespace LLAvatarNameCache
/// Time when unrefreshed cached names were checked last
static F64 sLastExpireCheck;
/// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
//-----------------------------------------------------------------------
// Internal methods
//-----------------------------------------------------------------------
@@ -291,13 +294,14 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
// Clear this agent from the pending list
LLAvatarNameCache::sPendingQueue.erase(agent_id);
const LLAvatarName& av_name = existing->second;
LLAvatarName& av_name = existing->second;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
<< agent_id
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest.
}
}
@@ -342,19 +346,23 @@ void LLAvatarNameCache::requestNamesViaCapability()
// http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0
//
// Apache can handle URLs of 4096 chars, but let's be conservative
const U32 NAME_URL_MAX = 4096;
const U32 NAME_URL_SEND_THRESHOLD = 3000;
static const U32 NAME_URL_MAX = 4096;
static const U32 NAME_URL_SEND_THRESHOLD = 3500;
std::string url;
url.reserve(NAME_URL_MAX);
std::vector<LLUUID> agent_ids;
agent_ids.reserve(128);
U32 id_total = sAskQueue.size();
U32 ids = 0;
ask_queue_t::const_iterator it = sAskQueue.begin();
for ( ; it != sAskQueue.end(); ++it)
ask_queue_t::const_iterator it;
while(!sAskQueue.empty())
{
it = sAskQueue.begin();
const LLUUID& agent_id = *it;
sAskQueue.erase(it);
if (url.empty())
{
@@ -377,27 +385,17 @@ void LLAvatarNameCache::requestNamesViaCapability()
if (url.size() > NAME_URL_SEND_THRESHOLD)
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first "
<< ids << " ids"
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
break;
}
}
if (!url.empty())
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all "
<< ids << " ids"
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested "
<< ids << "/" << id_total << "ids "
<< LL_ENDL;
LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids));
url.clear();
agent_ids.clear();
}
// We've moved all asks to the pending request queue
sAskQueue.clear();
}
void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
@@ -414,20 +412,25 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
<< LL_ENDL;
buildLegacyName(full_name, &av_name);
// Don't add to cache, the data already exists in the legacy name system
// cache and we don't want or need duplicate storage, because keeping the
// two copies in sync is complex.
processName(agent_id, av_name, false);
// Add to cache, because if we don't we'll keep rerequesting the
// same record forever. buildLegacyName should always guarantee
// that these records expire reasonably soon
// (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due
// to something temporary we will eventually request and get the right data.
processName(agent_id, av_name, true);
}
void LLAvatarNameCache::requestNamesViaLegacy()
{
static const S32 MAX_REQUESTS = 100;
F64 now = LLFrameTimer::getTotalSeconds();
std::string full_name;
ask_queue_t::const_iterator it = sAskQueue.begin();
for (; it != sAskQueue.end(); ++it)
ask_queue_t::const_iterator it;
for (S32 requests = 0; !sAskQueue.empty() && requests < MAX_REQUESTS; ++requests)
{
it = sAskQueue.begin();
const LLUUID& agent_id = *it;
sAskQueue.erase(it);
// Mark as pending first, just in case the callback is immediately
// invoked below. This should never happen in practice.
@@ -439,10 +442,6 @@ void LLAvatarNameCache::requestNamesViaLegacy()
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
}
// We've either answered immediately or moved all asks to the
// pending queue
sAskQueue.clear();
}
void LLAvatarNameCache::initClass(bool running)
@@ -519,11 +518,11 @@ void LLAvatarNameCache::idle()
// *TODO: Possibly re-enabled this based on People API load measurements
// 100 ms is the threshold for "user speed" operations, so we can
// stall for about that long to batch up requests.
//const F32 SECS_BETWEEN_REQUESTS = 0.1f;
//if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
//{
// return;
//}
const F32 SECS_BETWEEN_REQUESTS = 0.1f;
if (!sRequestTimer.hasExpired())
{
return;
}
if (!sAskQueue.empty())
{
@@ -538,6 +537,12 @@ void LLAvatarNameCache::idle()
}
}
if (sAskQueue.empty())
{
// cleared the list, reset the request timer.
sRequestTimer.reset(SECS_BETWEEN_REQUESTS);
}
// erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME
eraseUnrefreshed();
}
@@ -595,7 +600,7 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
av_name->mIsTemporaryName = true;
av_name->mExpires = F64_MAX; // not used because these are not cached
av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
<< full_name
<< LL_ENDL;
@@ -619,7 +624,6 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
// ...only do immediate lookups when cache is running
if (useDisplayNames())
{
// ...use display names cache
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
@@ -664,6 +668,29 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
return false;
}
// Return true when name has been set to Phoenix Name System Name, if not return false.
bool LLAvatarNameCache::getPNSName(const LLUUID& agent_id, std::string& name)
{
LLAvatarName avatar_name;
if (get(agent_id, &avatar_name))
getPNSName(avatar_name, name);
else return false;
return true;
}
// get() with callback compatible version of getPNSName
void LLAvatarNameCache::getPNSName(const LLAvatarName& avatar_name, std::string& name)
{
static LLCachedControl<S32> phoenix_name_system("PhoenixNameSystem", 0);
switch (phoenix_name_system)
{
case 0 : name = avatar_name.getLegacyName(); break;
case 1 : name = avatar_name.getCompleteName(); break;
case 2 : name = avatar_name.mDisplayName; break;
default : name = avatar_name.getLegacyName(); break;
}
}
void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
const callback_slot_t& slot,
const LLAvatarName& av_name)
@@ -673,8 +700,10 @@ void LLAvatarNameCache::fireSignal(const LLUUID& agent_id,
signal(agent_id, av_name);
}
void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
callback_connection_t connection;
if (sRunning)
{
// ...only do immediate lookups when cache is running
@@ -690,7 +719,7 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
return;
return connection;
}
}
}
@@ -703,7 +732,7 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
LLAvatarName av_name;
buildLegacyName(full_name, &av_name);
fireSignal(agent_id, slot, av_name);
return;
return connection;
}
}
}
@@ -720,15 +749,17 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot)
{
// ...new callback for this id
callback_signal_t* signal = new callback_signal_t();
signal->connect(slot);
connection = signal->connect(slot);
sSignalMap[agent_id] = signal;
}
else
{
// ...existing callback, bind additional slot
callback_signal_t* signal = sig_it->second;
signal->connect(slot);
connection = signal->connect(slot);
}
return connection;
}
// [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c
@@ -774,12 +805,6 @@ void LLAvatarNameCache::erase(const LLUUID& agent_id)
sCache.erase(agent_id);
}
void LLAvatarNameCache::fetch(const LLUUID& agent_id)
{
// re-request, even if request is already pending
sAskQueue.insert(agent_id);
}
void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name)
{
// *TODO: update timestamp if zero?
@@ -788,26 +813,35 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na
F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPReceivedHeaders const& headers)
{
F64 expires;
expirationFromCacheControl(headers, &expires);
return expires;
F64 expires = 0.0;
if (expirationFromCacheControl(headers, &expires))
{
return expires;
}
else
{
// With no expiration info, default to an hour
const F64 DEFAULT_EXPIRES = 60.0 * 60.0;
F64 now = LLFrameTimer::getTotalSeconds();
return now + DEFAULT_EXPIRES;
}
}
bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const& headers, F64* expires)
{
bool fromCacheControl = false;
S32 max_age = 3600; // With no expiration info, default to an hour.
F64 now = LLFrameTimer::getTotalSeconds();
// Allow the header to override the default
std::string cache_control;
if (headers.getFirstValue("cache-control", cache_control))
{
S32 max_age = 0;
if (max_age_from_cache_control(cache_control, &max_age))
{
*expires = now + (F64)max_age;
fromCacheControl = true;
}
}
*expires = now + (F64)max_age;
LL_DEBUGS("AvNameCache")
<< ( fromCacheControl ? "expires based on cache control " : "default expiration " )
<< "in " << *expires - now << " seconds"

View File

@@ -65,16 +65,23 @@ namespace LLAvatarNameCache
// If name is in cache, returns true and fills in provided LLAvatarName
// otherwise returns false
bool get(const LLUUID& agent_id, LLAvatarName *av_name);
// If get() succeeds, returns true and fills in name string
// via void function below, otherwise returns false
bool getPNSName(const LLUUID& agent_id, std::string& name);
// Perform a filling of name string according to Phoenix Name System,
// when we have an LLAvatarName already.
void getPNSName(const LLAvatarName& avatar_name, std::string& name);
// Callback types for get() below
typedef boost::signals2::signal<
void (const LLUUID& agent_id, const LLAvatarName& av_name)>
callback_signal_t;
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
// Fetches name information and calls callback.
// If name information is in cache, callback will be called immediately.
void get(const LLUUID& agent_id, callback_slot_t slot);
callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot);
// Allow display names to be explicitly disabled for testing.
void setUseDisplayNames(bool use);
@@ -90,10 +97,6 @@ namespace LLAvatarNameCache
/// Provide some fallback for agents that return errors
void handleAgentError(const LLUUID& agent_id);
// Force a re-fetch of the most recent data, but keep the current
// data in cache
void fetch(const LLUUID& agent_id);
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
// Compute name expiration time from HTTP Cache-Control header,

View File

@@ -200,7 +200,9 @@ static void request(
LLURLRequest::ERequestAction method,
Injector* body_injector,
LLHTTPClient::ResponderPtr responder,
AIHTTPHeaders& headers,
AIHTTPHeaders& headers/*,*/
DEBUG_CURLIO_PARAM(EDebugCurl debug),
EKeepAlive keepalive = keep_alive,
bool is_auth = false,
bool no_compression = false)
{
@@ -213,7 +215,10 @@ static void request(
LLURLRequest* req;
try
{
req = new LLURLRequest(method, url, body_injector, responder, headers, is_auth, no_compression);
req = new LLURLRequest(method, url, body_injector, responder, headers, keepalive, is_auth, no_compression);
#ifdef DEBUG_CURLIO
req->mCurlEasyRequest.debug(debug);
#endif
}
catch(AICurlNoEasyHandle& error)
{
@@ -225,36 +230,36 @@ static void request(
req->run();
}
void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
if(offset > 0 || bytes > 0)
{
headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1));
}
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers);
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers)
void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers);
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers);
request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers)
void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers);
request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
LLURI uri;
uri = LLURI::buildHTTP(url, LLSD::emptyArray(), query);
get(uri.asString(), responder, headers);
get(uri.asString(), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
//=============================================================================
@@ -362,6 +367,22 @@ void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const&
}
}
std::string const& LLHTTPClient::ResponderBase::get_cookie(std::string const& key)
{
AIHTTPReceivedHeaders::range_type cookies;
mReceivedHeaders.getValues("set-cookie", cookies);
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
if (key == cookie->second.substr(0, cookie->second.find('=')))
{
return cookie->second;
}
}
// Not found.
static std::string empty_dummy;
return empty_dummy;
}
// Called with HTML body.
// virtual
void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
@@ -554,7 +575,8 @@ enum EBlockingRequestAction {
static LLSD blocking_request(
std::string const& url,
EBlockingRequestAction method,
LLSD const& body) // Only used for HTTP_LLSD_POST
LLSD const& body/*,*/ // Only used for HTTP_LLSD_POST
DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
lldebugs << "blockingRequest of " << url << llendl;
@@ -563,17 +585,17 @@ static LLSD blocking_request(
if (method == HTTP_LLSD_POST)
{
responder = new BlockingLLSDPostResponder;
LLHTTPClient::post(url, body, responder, headers);
LLHTTPClient::post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
else if (method == HTTP_LLSD_GET)
{
responder = new BlockingLLSDGetResponder;
LLHTTPClient::get(url, responder, headers);
LLHTTPClient::get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
else // method == HTTP_RAW_GET
{
responder = new BlockingRawGetResponder;
LLHTTPClient::get(url, responder, headers);
LLHTTPClient::get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
responder->wait();
@@ -635,39 +657,39 @@ static LLSD blocking_request(
return response;
}
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)
LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
return blocking_request(url, HTTP_LLSD_POST, body);
return blocking_request(url, HTTP_LLSD_POST, body/*,*/ DEBUG_CURLIO_PARAM(debug));
}
LLSD LLHTTPClient::blockingGet(const std::string& url)
LLSD LLHTTPClient::blockingGet(const std::string& url/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
return blocking_request(url, HTTP_LLSD_GET, LLSD());
return blocking_request(url, HTTP_LLSD_GET, LLSD()/*,*/ DEBUG_CURLIO_PARAM(debug));
}
U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body)
U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD());
LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD()/*,*/ DEBUG_CURLIO_PARAM(debug));
body = result["body"].asString();
return result["status"].asInteger();
}
void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers);
request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers);
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
}
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, false); // Does use compression.
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, false); // Does use compression.
}
void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{
XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew();
XMLRPC_RequestSetMethodName(xmlrpc_request, method);
@@ -675,33 +697,33 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC
XMLRPC_RequestSetData(xmlrpc_request, value);
// XMLRPCInjector takes ownership of xmlrpc_request and will free it when done.
// LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done.
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression.
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, true); // Does not use compression.
}
void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers);
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
}
void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{
request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers);
request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
}
void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive)
{
request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers);
request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive);
}
// static
void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers);
request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}
// static
void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers)
void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
{
headers.addHeader("Destination", destination);
request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers);
request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug));
}

View File

@@ -66,6 +66,21 @@ struct AIBufferedCurlEasyRequestEvents {
virtual void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) = 0; // Transaction completed.
};
enum EKeepAlive {
no_keep_alive = 0,
keep_alive
};
#ifdef DEBUG_CURLIO
enum EDebugCurl {
debug_off = 0,
debug_on
};
#define DEBUG_CURLIO_PARAM(p) ,p
#else
#define DEBUG_CURLIO_PARAM(p)
#endif
class LLHTTPClient {
public:
@@ -140,7 +155,16 @@ public:
{
// It's possible that this page was moved (302), so we already saw headers
// from the 302 page and are starting over on the new page now.
mReceivedHeaders.clear();
// Erase all headers EXCEPT the cookies.
AIHTTPReceivedHeaders set_cookie_headers;
AIHTTPReceivedHeaders::range_type cookies;
mReceivedHeaders.getValues("set-cookie", cookies);
for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie)
{
set_cookie_headers.addHeader(cookie->first, cookie->second);
}
// Replace headers with just the cookie headers.
mReceivedHeaders.swap(set_cookie_headers);
}
// Called for all remaining headers.
@@ -155,13 +179,19 @@ public:
completedHeaders(status, reason, mReceivedHeaders);
}
// Extract cookie 'key' from mReceivedHeaders and return the string 'key=value', or an empty string if key does not exists.
std::string const& get_cookie(std::string const& key);
public:
// Derived classes that implement completed_headers()/completedHeaders() should return true here.
virtual bool needsHeaders(void) const { return false; }
// A derived class should return true if curl should follow redirections.
// The default is not to follow redirections.
virtual bool followRedir(void) { return false; }
virtual bool followRedir(void) const { return false; }
// If this function returns false then we generate an error when a redirect status (300..399) is received.
virtual bool redirect_status_ok(void) const { return followRedir(); }
// Timeout policy to use.
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0;
@@ -188,6 +218,7 @@ public:
class ResponderHeadersOnly : public ResponderBase {
private:
/*virtual*/ bool needsHeaders(void) const { return true; }
/*virtual*/ bool followRedir(void) const { return true; }
protected:
// ResponderBase event
@@ -357,59 +388,59 @@ public:
/** @name non-blocking API */
//@{
static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers);
static void head(std::string const& url, ResponderHeadersOnly* responder)
{ AIHTTPHeaders headers; head(url, responder, headers); }
static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void head(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; head(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers);
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder)
{ AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers); }
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers);
static void get(std::string const& url, ResponderPtr responder)
{ AIHTTPHeaders headers; get(url, responder, headers); }
static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void get(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; get(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers);
static void get(std::string const& url, LLSD const& query, ResponderPtr responder)
{ AIHTTPHeaders headers; get(url, query, responder, headers); }
static void get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void get(std::string const& url, LLSD const& query, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; get(url, query, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers);
static void put(std::string const& url, LLSD const& body, ResponderPtr responder)
{ AIHTTPHeaders headers; put(url, body, responder, headers); }
static void put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void put(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; put(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers);
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder)
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); }
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; getHeaderOnly(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers);
static void post(std::string const& url, LLSD const& body, ResponderPtr responder)
{ AIHTTPHeaders headers; post(url, body, responder, headers); }
static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void post(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
/** Takes ownership of request and deletes it when sent */
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers);
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder)
{ AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers); }
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers);
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder)
{ AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); }
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
/** Takes ownership of data and deletes it when sent */
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers);
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder)
{ AIHTTPHeaders headers; postRaw(url, data, size, responder, headers); }
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postRaw(url, data, size, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers);
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder)
{ AIHTTPHeaders headers; postFile(url, filename, responder, headers); }
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postFile(url, filename, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers);
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder)
{ AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers); }
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive);
static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive)
{ AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); }
static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers);
static void del(std::string const& url, ResponderPtr responder)
{ AIHTTPHeaders headers; del(url, responder, headers); }
static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void del(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; del(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
///< sends a DELETE method, but we can't call it delete in c++
@@ -422,9 +453,9 @@ public:
* @param headers A map of key:value headers to pass to the request
* @param timeout The number of seconds to give the server to respond.
*/
static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers);
static void move(std::string const& url, std::string const& destination, ResponderPtr responder)
{ AIHTTPHeaders headers; move(url, destination, responder, headers); }
static void move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
static void move(std::string const& url, std::string const& destination, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
{ AIHTTPHeaders headers; move(url, destination, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
//@}
@@ -434,7 +465,7 @@ public:
* @param url the complete serialized (and escaped) url to get
* @return An LLSD of { 'status':status, 'body':payload }
*/
static LLSD blockingGet(std::string const& url);
static LLSD blockingGet(std::string const& url/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
/**
* @brief Blocking HTTP GET that returns the raw body.
@@ -443,7 +474,7 @@ public:
* @param result the target string to write the body to
* @return HTTP status
*/
static U32 blockingGetRaw(const std::string& url, std::string& result);
static U32 blockingGetRaw(const std::string& url, std::string& result/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
/**
* @brief Blocking HTTP POST that returns an LLSD map of status and body.
@@ -452,7 +483,7 @@ public:
* @param body the LLSD post body
* @return An LLSD of { 'status':status (an int), 'body':payload (an LLSD) }
*/
static LLSD blockingPost(std::string const& url, LLSD const& body);
static LLSD blockingPost(std::string const& url, LLSD const& body/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
};
#endif // LL_LLHTTPCLIENT_H

View File

@@ -77,19 +77,14 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
// This might throw AICurlNoEasyHandle.
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body,
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) :
mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression),
LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression) :
mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(no_compression),
mBody(body), mResponder(responder), mHeaders(headers)
{
}
void LLURLRequest::initialize_impl(void)
{
if (mHeaders.hasHeader("Cookie"))
{
allowCookies();
}
// If the header is "Pragma" with no value, the caller intends to
// force libcurl to drop the Pragma header it so gratuitously inserts.
// Before inserting the header, force libcurl to not use the proxy.
@@ -105,7 +100,7 @@ void LLURLRequest::initialize_impl(void)
// but if they did not specify a Content-Type, then ask the injector.
mHeaders.addHeader("Content-Type", mBody->contentType(), AIHTTPHeaders::keep_existing_header);
}
else
else if (mAction != HTTP_HEAD)
{
// Check to see if we have already set Accept or not. If no one
// set it, set it to application/llsd+xml since that's what we
@@ -199,12 +194,6 @@ void LLURLRequest::useProxy(const std::string &proxy)
}
#endif
void LLURLRequest::allowCookies()
{
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, "");
}
bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
{
bool rv = false;
@@ -213,13 +202,11 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
{
case HTTP_HEAD:
curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1);
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
rv = true;
break;
case HTTP_GET:
curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1);
curlEasyRequest_w->setopt(CURLOPT_FOLLOWLOCATION, 1);
// Set Accept-Encoding to allow response compression
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : "");
@@ -239,7 +226,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w)
case HTTP_POST:
{
// Set the handle for an http post
curlEasyRequest_w->setPost(mBodySize);
curlEasyRequest_w->setPost(mBodySize, mKeepAlive);
// Set Accept-Encoding to allow response compression
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : "");

View File

@@ -77,18 +77,13 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
* @param action One of the ERequestAction enumerations.
* @param url The url of the request. It should already be encoded.
*/
LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression);
LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression);
protected:
// Call abort(), not delete.
/*virtual*/ ~LLURLRequest() { }
public:
/**
* @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE.
*/
void allowCookies(void);
/**
* @ brief Turn off (or on) the CURLOPT_PROXY header.
*/
@@ -116,6 +111,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine {
private:
ERequestAction mAction;
std::string mURL;
bool mKeepAlive; // Set to false only when explicitely requested.
bool mIsAuth; // Set for authentication messages (login, buy land, buy currency).
bool mNoCompression; // Set to disable using gzip.
Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT.

View File

@@ -1027,7 +1027,8 @@ void LLModel::setVolumeFaceData(
if (tc.get())
{
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), num_verts*2*sizeof(F32));
U32 tex_size = (num_verts*2*sizeof(F32)+0xF)&~0xF;
LLVector4a::memcpyNonAliased16((F32*) face.mTexCoords, (F32*) tc.get(), tex_size);
}
else
{

View File

@@ -71,7 +71,7 @@ void LLStyle::drawControl(ControlElement element, const QStyleOption *option, QP
QPlastiqueStyle::drawControl(element, &localOption, painter, widget);
return;
}
default:
break;
}

View File

@@ -935,7 +935,7 @@ void LLGLManager::initExtensions()
mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
mHasTransformFeedback = mGLVersion >= 4.f || ExtensionExists("GL_EXT_transform_feedback", gGLHExts.mSysExts);
#if !LL_DARWIN
mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif

View File

@@ -1329,6 +1329,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
llassert(mCurrentDiscardLevel >= 0);
discard_level = mCurrentDiscardLevel;
}
discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
{
@@ -1586,7 +1587,18 @@ void LLImageGL::destroyGLTexture()
}
}
//force to invalidate the gl texture, most likely a sculpty texture
void LLImageGL::forceToInvalidateGLTexture()
{
if (mTexName != 0)
{
destroyGLTexture();
}
else
{
mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
}
}
//----------------------------------------------------------------------------

View File

@@ -119,6 +119,7 @@ public:
// Read back a raw image for this discard level, if it exists
BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok);
void destroyGLTexture();
void forceToInvalidateGLTexture();
void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
void setComponents(S8 ncomponents) { mComponents = ncomponents; }

View File

@@ -49,12 +49,63 @@ extern LLGLSLShader gPostNightVisionProgram;
extern LLGLSLShader gPostGaussianBlurProgram;
extern LLGLSLShader gPostPosterizeProgram;
extern LLGLSLShader gPostMotionBlurProgram;
extern LLGLSLShader gPostVignetteProgram;
static const unsigned int NOISE_SIZE = 512;
static const char * const XML_FILENAME = "postprocesseffects.xml";
template<> LLSD LLPostProcessShader::LLShaderSetting<LLVector4>::getDefaultValue()
class LLPostProcessShader : public IPostProcessShader, public LLRefCount
{
public:
LLPostProcessShader(const std::string& enable_name, LLGLSLShader& shader, bool enabled = false) :
mShader(shader), mEnabled(enable_name,enabled)
{
addSetting(mEnabled);
}
/*virtual*/ bool isEnabled() const {return mShader.mProgramObject && mEnabled;}
/*virtual*/ void bindShader() {mShader.bind();}
/*virtual*/ void unbindShader() {mShader.unbind();}
/*virtual*/ LLGLSLShader& getShader() {return mShader;}
/*virtual*/ LLSD getDefaults(); //See IPostProcessShader::getDefaults
/*virtual*/ void loadSettings(const LLSD& settings); //See IPostProcessShader::loadSettings
/*virtual*/ void addSetting(IShaderSettingBase& setting) { mSettings.push_back(&setting); }
protected:
template<typename T>
struct LLShaderSetting : public IShaderSettingBase
{
LLShaderSetting(const std::string& name, T def) :
mValue(def), mDefault(def), mSettingName(name) {}
operator T() const { return mValue; }
T get() const { return mValue; }
/*virtual*/ const std::string& getName() const { return mSettingName; } //See LLShaderSettingBase::getName
/*virtual*/ LLSD getDefaultValue() const { return mDefault; } //See LLShaderSettingBase::getDefaultValue
/*virtual*/ void setValue(const LLSD& value) { mValue = value; } //See LLShaderSettingBase::setValue
private:
const std::string mSettingName; //LLSD key names as found in postprocesseffects.xml. eg 'contrast_base'
T mValue; //The member variable mentioned above.
T mDefault; //Set via ctor. Value is inserted into the defaults LLSD list if absent from postprocesseffects.xml
};
private:
std::vector<IShaderSettingBase*> mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor.
LLGLSLShader& mShader;
LLShaderSetting<bool> mEnabled;
};
//helpers
class LLPostProcessSinglePassColorShader : public LLPostProcessShader
{
public:
LLPostProcessSinglePassColorShader(const std::string& enable_name, LLGLSLShader& shader, bool enabled = false) :
LLPostProcessShader(enable_name, shader, enabled) {}
/*virtual*/ S32 getColorChannel() const {return 0;}
/*virtual*/ S32 getDepthChannel() const {return -1;}
/*virtual*/ bool draw(U32 pass) {return pass == 1;}
/*virtual*/ void postDraw() {}
};
template<> LLSD LLPostProcessShader::LLShaderSetting<LLVector4>::getDefaultValue() const
{
return mDefault.getValue();
}
@@ -66,223 +117,175 @@ template<> void LLPostProcessShader::LLShaderSetting<LLVector4>::setValue(const
LLSD LLPostProcessShader::getDefaults()
{
LLSD defaults;
for(std::vector<LLShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
for(std::vector<IShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
{
defaults[(*it)->mSettingName]=(*it)->getDefaultValue();
defaults[(*it)->getName()]=(*it)->getDefaultValue();
}
return defaults;
}
void LLPostProcessShader::loadSettings(const LLSD& settings)
{
for(std::vector<LLShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
for(std::vector<IShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
{
LLSD value = settings[(*it)->mSettingName];
LLSD value = settings[(*it)->getName()];
(*it)->setValue(value);
}
}
class LLColorFilterShader : public LLPostProcessShader
class LLColorFilterShader : public LLPostProcessSinglePassColorShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<F32> mGamma, mBrightness, mContrast, mSaturation;
LLShaderSetting<LLVector4> mContrastBase;
public:
LLColorFilterShader() :
mEnabled("enable_color_filter",false),
LLColorFilterShader() :
LLPostProcessSinglePassColorShader("enable_color_filter",gPostColorFilterProgram),
mGamma("gamma",1.f),
mBrightness("brightness",1.f),
mContrast("contrast",1.f),
mSaturation("saturation",1.f),
mContrastBase("contrast_base",LLVector4(1.f,1.f,1.f,0.5f))
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mGamma);
mSettings.push_back(&mBrightness);
mSettings.push_back(&mContrast);
mSettings.push_back(&mSaturation);
mSettings.push_back(&mContrastBase);
addSetting(mGamma);
addSetting(mBrightness);
addSetting(mContrast);
addSetting(mSaturation);
addSetting(mContrastBase);
}
bool isEnabled() { return mEnabled && gPostColorFilterProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
/*virtual*/ QuadType preDraw()
{
if(!isEnabled())
return QUAD_NONE;
getShader().uniform1f("gamma", mGamma);
getShader().uniform1f("brightness", mBrightness);
getShader().uniform1f("contrast", mContrast);
float baseI = (mContrastBase.get()[VX] + mContrastBase.get()[VY] + mContrastBase.get()[VZ]) / 3.0f;
baseI = mContrastBase.get()[VW] / llmax(baseI,0.001f);
float baseR = mContrastBase.get()[VX] * baseI;
float baseG = mContrastBase.get()[VY] * baseI;
float baseB = mContrastBase.get()[VZ] * baseI;
getShader().uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV);
getShader().uniform1f("saturation", mSaturation);
/// CALCULATING LUMINANCE (Using NTSC lum weights)
/// http://en.wikipedia.org/wiki/Luma_%28video%29
static const float LUMINANCE_R = 0.299f;
static const float LUMINANCE_G = 0.587f;
static const float LUMINANCE_B = 0.114f;
gPostColorFilterProgram.bind();
gPostColorFilterProgram.uniform1f("gamma", mGamma);
gPostColorFilterProgram.uniform1f("brightness", mBrightness);
gPostColorFilterProgram.uniform1f("contrast", mContrast);
float baseI = (mContrastBase.mValue[VX] + mContrastBase.mValue[VY] + mContrastBase.mValue[VZ]) / 3.0f;
baseI = mContrastBase.mValue[VW] / ((baseI < 0.001f) ? 0.001f : baseI);
float baseR = mContrastBase.mValue[VX] * baseI;
float baseG = mContrastBase.mValue[VY] * baseI;
float baseB = mContrastBase.mValue[VZ] * baseI;
gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV);
gPostColorFilterProgram.uniform1f("saturation", mSaturation);
gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV);
return QUAD_NORMAL;
}
bool draw(U32 pass) {return pass == 1;}
void unbind()
{
gPostColorFilterProgram.unbind();
}
};
class LLNightVisionShader : public LLPostProcessShader
class LLNightVisionShader : public LLPostProcessSinglePassColorShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<F32> mBrightnessMult, mNoiseStrength;
public:
LLNightVisionShader() :
mEnabled("enable_night_vision",false),
LLPostProcessSinglePassColorShader("enable_night_vision",gPostNightVisionProgram),
mBrightnessMult("brightness_multiplier",3.f),
mNoiseStrength("noise_strength",.4f)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mBrightnessMult);
mSettings.push_back(&mNoiseStrength);
addSetting(mBrightnessMult);
addSetting(mNoiseStrength);
}
bool isEnabled() { return mEnabled && gPostNightVisionProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
/*virtual*/ QuadType preDraw()
{
if(!isEnabled())
return QUAD_NONE;
gPostNightVisionProgram.bind();
LLPostProcess::getInstance()->bindNoise(1);
gPostNightVisionProgram.uniform1f("brightMult", mBrightnessMult);
gPostNightVisionProgram.uniform1f("noiseStrength", mNoiseStrength);
getShader().uniform1f("brightMult", mBrightnessMult);
getShader().uniform1f("noiseStrength", mNoiseStrength);
return QUAD_NOISE;
}
bool draw(U32 pass) {return pass == 1;}
void unbind()
};
class LLPosterizeShader : public LLPostProcessSinglePassColorShader
{
private:
LLShaderSetting<S32> mNumLayers;
public:
LLPosterizeShader() : LLPostProcessSinglePassColorShader("enable_posterize",gPostPosterizeProgram),
mNumLayers("posterize_layers",2)
{
gPostNightVisionProgram.unbind();
addSetting(mNumLayers);
}
/*virtual*/ QuadType preDraw()
{
getShader().uniform1i("layerCount", mNumLayers);
return QUAD_NORMAL;
}
};
class LLVignetteShader : public LLPostProcessSinglePassColorShader
{
private:
LLShaderSetting<F32> mStrength, mRadius, mDarkness, mDesaturation, mChromaticAberration;
public:
LLVignetteShader() : LLPostProcessSinglePassColorShader("enable_vignette",gPostVignetteProgram),
mStrength("vignette_strength",.85f),
mRadius("vignette_radius",.7f),
mDarkness("vignette_darkness",1.f),
mDesaturation("vignette_desaturation",1.5f),
mChromaticAberration("vignette_chromatic_aberration",.05f)
{
addSetting(mStrength);
addSetting(mRadius);
addSetting(mDarkness);
addSetting(mDesaturation);
addSetting(mChromaticAberration);
}
/*virtual*/ QuadType preDraw()
{
LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions();
getShader().uniform1f("vignette_strength", mStrength);
getShader().uniform1f("vignette_radius", mRadius);
getShader().uniform1f("vignette_darkness", mDarkness);
getShader().uniform1f("vignette_desaturation", mDesaturation);
getShader().uniform1f("vignette_chromatic_aberration", mChromaticAberration);
getShader().uniform2fv("screen_res", 1, screen_rect.mV);
return QUAD_NORMAL;
}
};
class LLGaussBlurShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<S32> mNumPasses;
GLint mPassLoc;
public:
LLGaussBlurShader() :
mEnabled("enable_gauss_blur",false),
LLGaussBlurShader() : LLPostProcessShader("enable_gauss_blur",gPostGaussianBlurProgram),
mNumPasses("gauss_blur_passes",2),
mPassLoc(0)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mNumPasses);
addSetting(mNumPasses);
}
bool isEnabled() { return mEnabled && mNumPasses && gPostGaussianBlurProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
/*virtual*/ bool isEnabled() const { return LLPostProcessShader::isEnabled() && mNumPasses.get(); }
/*virtual*/ S32 getColorChannel() const { return 0; }
/*virtual*/ S32 getDepthChannel() const { return -1; }
/*virtual*/ QuadType preDraw()
{
if(!isEnabled())
return QUAD_NONE;
gPostGaussianBlurProgram.bind();
mPassLoc = gPostGaussianBlurProgram.getUniformLocation("horizontalPass");
mPassLoc = getShader().getUniformLocation("horizontalPass");
return QUAD_NORMAL;
}
bool draw(U32 pass)
/*virtual*/ bool draw(U32 pass)
{
if((S32)pass > mNumPasses*2)
return false;
glUniform1iARB(mPassLoc, (pass-1) % 2);
return true;
}
void unbind()
{
gPostGaussianBlurProgram.unbind();
}
};
class LLPosterizeShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<S32> mNumLayers;
public:
LLPosterizeShader() :
mEnabled("enable_posterize",false),
mNumLayers("posterize_layers",2)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mNumLayers);
}
bool isEnabled() { return mEnabled && gPostPosterizeProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
{
if(!isEnabled())
return QUAD_NONE;
gPostPosterizeProgram.bind();
gPostPosterizeProgram.uniform1i("layerCount", mNumLayers);
return QUAD_NORMAL;
}
bool draw(U32 pass)
{
return pass == 1;
}
void unbind()
{
gPostPosterizeProgram.unbind();
}
/*virtual*/ void postDraw() {}
};
class LLMotionShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<S32> mStrength;
public:
LLMotionShader() :
mEnabled("enable_motionblur",false),
mStrength("blur_strength",false)
LLMotionShader() : LLPostProcessShader("enable_motionblur",gPostMotionBlurProgram),
mStrength("blur_strength",1)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mStrength);
addSetting(mStrength);
}
bool isEnabled() { return mEnabled && gPostMotionBlurProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return 1; }
QuadType bind()
/*virtual*/ S32 getColorChannel() const { return 0; }
/*virtual*/ S32 getDepthChannel() const { return 1; }
/*virtual*/ QuadType preDraw()
{
if(!isEnabled())
{
return QUAD_NONE;
}
glh::matrix4f inv_proj(gGLModelView);
inv_proj.mult_left(gGLProjection);
inv_proj = inv_proj.inverse();
@@ -291,22 +294,18 @@ public:
LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions();
gPostMotionBlurProgram.bind();
gPostMotionBlurProgram.uniformMatrix4fv("prev_proj", 1, GL_FALSE, prev_proj.m);
gPostMotionBlurProgram.uniformMatrix4fv("inv_proj", 1, GL_FALSE, inv_proj.m);
gPostMotionBlurProgram.uniform2fv("screen_res", 1, screen_rect.mV);
gPostMotionBlurProgram.uniform1i("blur_strength", mStrength);
getShader().uniformMatrix4fv("prev_proj", 1, GL_FALSE, prev_proj.m);
getShader().uniformMatrix4fv("inv_proj", 1, GL_FALSE, inv_proj.m);
getShader().uniform2fv("screen_res", 1, screen_rect.mV);
getShader().uniform1i("blur_strength", mStrength);
return QUAD_NORMAL;
}
bool draw(U32 pass)
/*virtual*/ bool draw(U32 pass)
{
return pass == 1;
}
void unbind()
{
gPostMotionBlurProgram.unbind();
}
/*virtual*/ void postDraw() {}
};
LLPostProcess::LLPostProcess(void) :
@@ -320,12 +319,12 @@ LLPostProcess::LLPostProcess(void) :
mAllEffectInfo(LLSD::emptyMap())
{
mShaders.push_back(new LLMotionShader());
mShaders.push_back(new LLVignetteShader());
mShaders.push_back(new LLColorFilterShader());
mShaders.push_back(new LLNightVisionShader());
mShaders.push_back(new LLGaussBlurShader());
mShaders.push_back(new LLPosterizeShader());
/* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/
std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL;
@@ -547,20 +546,19 @@ void LLPostProcess::doEffects(void)
void LLPostProcess::applyShaders(void)
{
QuadType quad;
bool primary_rendertarget = 1;
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
if((quad = (*it)->bind()) != QUAD_NONE)
if((*it)->isEnabled())
{
S32 color_channel = (*it)->getColorChannel();
S32 depth_channel = (*it)->getDepthChannel();
if(depth_channel >= 0)
gGL.getTexUnit(depth_channel)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture);
U32 pass = 1;
(*it)->bindShader();
QuadType quad = (*it)->preDraw();
while((*it)->draw(pass++))
{
mRenderTarget[!primary_rendertarget].bindTarget();
@@ -573,7 +571,8 @@ void LLPostProcess::applyShaders(void)
if(mRenderTarget[0].getFBO())
primary_rendertarget = !primary_rendertarget;
}
(*it)->unbind();
(*it)->postDraw();
(*it)->unbindShader();
}
}
//Only need to copy to framebuffer if FBOs are supported, else we've already been drawing to the framebuffer to begin with.

View File

@@ -38,57 +38,48 @@
#include "llrendertarget.h"
class LLSD;
class LLGLSLShader;
typedef enum _QuadType {
QUAD_NONE,
QUAD_NORMAL,
QUAD_NOISE
} QuadType;
//LLPostProcessShader is an attempt to encapsulate the shaders a little better.
class LLPostProcessShader : public LLRefCount //Abstract. PostProcess shaders derive off of this common base.
class IPostProcessShader //Abstract. PostProcess shaders derive off of this common base.
{
protected:
//LLShaderSetting is used to associate key names to member variables to avoid LLSD lookups when drawing.
//It also facilitates automating the assigning of defaults to, as well as parsing from, the effects LLSD list.
//This replaces the entire old PostProcessTweaks structure. More will be done in the future to move into a more
//xml-driven configuration.
struct LLShaderSettingBase
struct IShaderSettingBase
{
LLShaderSettingBase(const char* name) : mSettingName(name) {}
const char* mSettingName; //LLSD key names as found in postprocesseffects.xml. eg 'contrast_base'
virtual LLSD getDefaultValue() = 0; //Converts the member variable as an LLSD. Used to set defaults absent in postprocesseffects.xml
virtual ~IShaderSettingBase() {} //virtual dtor.
virtual const std::string& getName() const = 0; //Returns the name of this setting
virtual LLSD getDefaultValue() const = 0; //Converts the member variable as an LLSD. Used to set defaults absent in postprocesseffects.xml
virtual void setValue(const LLSD& value) = 0; //Connects the LLSD element to the member variable. Used when loading effects (such as default)
};
template<typename T>
struct LLShaderSetting : public LLShaderSettingBase
{
LLShaderSetting(const char* setting_name, T def) : LLShaderSettingBase(setting_name), mValue(def), mDefault(def) {}
T mValue; //The member variable mentioned above.
T mDefault; //Set via ctor. Value is inserted into the defaults LLSD list if absent from postprocesseffects.xml
LLSD getDefaultValue() { return mDefault; } //See LLShaderSettingBase::getDefaultValue
void setValue(const LLSD& value) { mValue = value; } //See LLShaderSettingBase::setValue
operator T() { return mValue; } //Typecast operator overload so this object can be handled as if it was whatever T represents.
};
std::vector<LLShaderSettingBase*> mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor.
public:
virtual ~LLPostProcessShader() {};
virtual bool isEnabled() = 0; //Returning false avoids bind/draw/unbind calls. If no shaders are enabled, framebuffer copying is skipped.
virtual S32 getColorChannel() = 0; //If color buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer.
virtual S32 getDepthChannel() = 0; //If depth buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer.
virtual QuadType bind() = 0; //Bind shader and textures, set up attribs. Returns the 'type' of quad to be drawn.
virtual ~IPostProcessShader() {} //virtual dtor.
virtual bool isEnabled() const = 0; //Returning false avoids bind/draw/unbind calls. If no shaders are enabled, framebuffer copying is skipped.
virtual S32 getColorChannel() const = 0; //If color buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer.
virtual S32 getDepthChannel() const = 0; //If depth buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer.
virtual void bindShader() = 0;
virtual void unbindShader() = 0;
virtual LLGLSLShader& getShader() = 0;
virtual QuadType preDraw() = 0; //Bind shader and textures, set up attribs. Returns the 'type' of quad to be drawn.
virtual bool draw(U32 pass) = 0; //returning false means finished. Used to update per-pass attributes and such. LLPostProcess will call
//drawOrthoQuad when this returns true, increment pass, then call this again, and keep repeating this until false is returned.
virtual void unbind() = 0; //Unbind shader and textures.
virtual void postDraw() = 0; //Done drawing..
LLSD getDefaults(); //Returns a full LLSD kvp list filled with default values.
void loadSettings(const LLSD& settings); //Parses the effects LLSD list and sets the member variables linked to them (via LLShaderSetting::setValue())
virtual LLSD getDefaults() = 0; //Returns a full LLSD kvp list filled with default values.
virtual void loadSettings(const LLSD& settings) = 0; //Parses the effects LLSD list and sets the member variables linked to them (via LLShaderSetting::setValue())
virtual void addSetting(IShaderSettingBase& setting) = 0;
};
//LLVector4 does not implicitly convert to and from LLSD, so template specilizations are necessary.
template<> LLSD LLPostProcessShader::LLShaderSetting<LLVector4>::getDefaultValue();
template<> void LLPostProcessShader::LLShaderSetting<LLVector4>::setValue(const LLSD& value);
class LLPostProcessShader;
class LLPostProcess : public LLSingleton<LLPostProcess>
{
private:

View File

@@ -229,8 +229,6 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
stop_glerror();
if (mIndex < 0) return false;
gGL.flush();
LLImageGL* gl_tex = NULL ;
if (texture == NULL || !(gl_tex = texture->getGLTexture()))
{
@@ -258,6 +256,7 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
}
if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
{
gGL.flush();
activate();
enable(gl_tex->getTarget());
mCurrTexture = gl_tex->getTexName();
@@ -1120,6 +1119,9 @@ void LLRender::refreshState(void)
setAlphaRejectSettings(mCurrAlphaFunc, mCurrAlphaFuncVal);
//Singu note: Also reset glBlendFunc
blendFunc(mCurrBlendColorSFactor,mCurrBlendColorDFactor,mCurrBlendAlphaSFactor,mCurrBlendAlphaDFactor);
mDirty = false;
}
@@ -1510,20 +1512,26 @@ void LLRender::pushUIMatrix()
{
if (mUIOffset.empty())
{
mUIOffset.push_back(new LLVector4a(0.f));
mUIOffset.push_back(static_cast<LLVector4a*>(ll_aligned_malloc_16(sizeof(LLVector4a))));
mUIOffset.back()->splat(0.f);
}
else
{
mUIOffset.push_back(new LLVector4a(*mUIOffset.back()));
const LLVector4a* last_entry = mUIOffset.back();
mUIOffset.push_back(static_cast<LLVector4a*>(ll_aligned_malloc_16(sizeof(LLVector4a))));
*mUIOffset.back() = *last_entry;
}
if (mUIScale.empty())
{
mUIScale.push_back(new LLVector4a(1.f));
mUIScale.push_back(static_cast<LLVector4a*>(ll_aligned_malloc_16(sizeof(LLVector4a))));
mUIScale.back()->splat(1.f);
}
else
{
mUIScale.push_back(new LLVector4a(*mUIScale.back()));
const LLVector4a* last_entry = mUIScale.back();
mUIScale.push_back(static_cast<LLVector4a*>(ll_aligned_malloc_16(sizeof(LLVector4a))));
*mUIScale.back() = *last_entry;
}
}
@@ -1533,9 +1541,9 @@ void LLRender::popUIMatrix()
{
llerrs << "UI offset stack blown." << llendl;
}
delete mUIOffset.back();
ll_aligned_free_16(mUIOffset.back());
mUIOffset.pop_back();
delete mUIScale.back();
ll_aligned_free_16(mUIScale.back());
mUIScale.pop_back();
}
@@ -1580,7 +1588,7 @@ void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB
if (mCurrColorMask[0] != writeColorR ||
mCurrColorMask[1] != writeColorG ||
mCurrColorMask[2] != writeColorB ||
mCurrColorMask[3] != writeAlpha)
mCurrColorMask[3] != writeAlpha || mDirty)
{
mCurrColorMask[0] = writeColorR;
mCurrColorMask[1] = writeColorG;
@@ -1635,7 +1643,7 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value)
}
if (mCurrAlphaFunc != func ||
mCurrAlphaFuncVal != value)
mCurrAlphaFuncVal != value || mDirty)
{
mCurrAlphaFunc = func;
mCurrAlphaFuncVal = value;
@@ -1679,7 +1687,7 @@ void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
llassert(sfactor < BF_UNDEF);
llassert(dfactor < BF_UNDEF);
if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor ||
mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor)
mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor || mDirty)
{
mCurrBlendColorSFactor = sfactor;
mCurrBlendAlphaSFactor = sfactor;
@@ -1704,7 +1712,7 @@ void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
return;
}
if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor ||
mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor)
mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor || mDirty)
{
mCurrBlendColorSFactor = color_sfactor;
mCurrBlendAlphaSFactor = alpha_sfactor;

View File

@@ -813,7 +813,6 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mDepth);
}
check_framebuffer_status();
}
stop_glerror();

View File

@@ -25,6 +25,7 @@
*/
#include "linden_common.h"
#include <boost/filesystem.hpp> //First, because glh_linear #defines equivalent.. which boost uses internally
#include "llshadermgr.h"
@@ -53,6 +54,17 @@ LLShaderMgr * LLShaderMgr::sInstance = NULL;
LLShaderMgr::LLShaderMgr()
{
{
const std::string dumpdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"shader_dump")+gDirUtilp->getDirDelimiter();
try
{
boost::filesystem::remove_all(dumpdir);
}
catch(const boost::filesystem::filesystem_error& e)
{
llinfos << "boost::filesystem::remove_all(\""+dumpdir+"\") failed: '" + e.code().message() + "'" << llendl;
}
}
}
@@ -660,6 +672,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
}
}
static const LLCachedControl<bool> SHPackDeferredNormals("SHPackDeferredNormals",false);
if(SHPackDeferredNormals)
text[count++] = strdup("#define PACK_NORMALS\n");
//copy preprocessor definitions into buffer
for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
{
@@ -1116,7 +1132,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("ssao_max_radius");
mReservedUniforms.push_back("ssao_factor");
mReservedUniforms.push_back("ssao_factor_inv");
mReservedUniforms.push_back("ssao_effect_mat");
mReservedUniforms.push_back("ssao_effect");
mReservedUniforms.push_back("screen_res");
mReservedUniforms.push_back("near_clip");
mReservedUniforms.push_back("shadow_offset");

View File

@@ -120,7 +120,7 @@ public:
DEFERRED_SSAO_MAX_RADIUS,
DEFERRED_SSAO_FACTOR,
DEFERRED_SSAO_FACTOR_INV,
DEFERRED_SSAO_EFFECT_MAT,
DEFERRED_SSAO_EFFECT,
DEFERRED_SCREEN_RES,
DEFERRED_NEAR_CLIP,
DEFERRED_SHADOW_OFFSET,

View File

@@ -2083,6 +2083,16 @@ void LLVertexBuffer::flush()
}
}
// bind for transform feedback (quick 'n dirty)
void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count)
{
#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
U32 offset = mOffsets[type] + sTypeSize[type]*index;
U32 size= (sTypeSize[type]*count);
glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size);
#endif
}
// Set for rendering
void LLVertexBuffer::setBuffer(U32 data_mask)
{

View File

@@ -202,16 +202,18 @@ protected:
void destroyGLIndices();
void updateNumVerts(S32 nverts);
void updateNumIndices(S32 nindices);
bool useVBOs() const;
void unmapBuffer();
public:
LLVertexBuffer(U32 typemask, S32 usage);
// map for data access
volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range);
void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
// set for rendering
virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0
void flush(); //flush pending data to GL memory
@@ -240,6 +242,7 @@ public:
bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
bool useVBOs() const;
bool isEmpty() const { return mEmpty; }
bool isLocked() const { return mVertexLocked || mIndexLocked; }
S32 getNumVerts() const { return mNumVerts; }

Some files were not shown because too many files have changed in this diff Show More