Commits

Yuri Chebotarev  committed 9bb9b04

fix for EXT-4082 Normal Uploading huge image crashes viewer
https://codereview.productengine.com/secondlife/r/11/
reviewed Tofu Linden

  • Participants
  • Parent commits 522e2fe
  • Branches product-engine

Comments (0)

Files changed (7)

File indra/llimage/CMakeLists.txt

 set(llimage_SOURCE_FILES
     llimagebmp.cpp
     llimage.cpp
+    llimagedimensionsinfo.cpp
     llimagedxt.cpp
     llimagej2c.cpp
     llimagejpeg.cpp
 
     llimage.h
     llimagebmp.h
+    llimagedimensionsinfo.h
     llimagedxt.h
     llimagej2c.h
     llimagejpeg.h

File indra/llimage/llimagedimensionsinfo.cpp

+/** 
+ * @file llimagedimensionsinfo.cpp
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "stdtypes.h"
+
+#include "llimagejpeg.h"
+
+#include "llimagedimensionsinfo.h"
+
+bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
+{
+	clean();
+
+	mSrcFilename = src_filename;
+
+	S32 file_size = 0;
+	apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size);
+
+	if (s != APR_SUCCESS)
+	{
+		setLastError("Unable to open file for reading", src_filename);
+		return false;
+	}
+
+	if (file_size == 0)
+	{
+		setLastError("File is empty",src_filename);
+		return false;
+	}
+
+	switch (codec)
+	{
+	case IMG_CODEC_BMP:
+		return getImageDimensionsBmp();
+	case IMG_CODEC_TGA:
+		return getImageDimensionsTga();
+	case IMG_CODEC_JPEG:
+		return getImageDimensionsJpeg();
+	case IMG_CODEC_PNG:
+		return getImageDimensionsPng();
+	default:
+		return false;
+
+	}
+}
+
+
+bool LLImageDimensionsInfo::getImageDimensionsBmp()
+{
+	const S32 BMP_FILE_HEADER_SIZE = 14;
+
+	mInfile.seek(APR_CUR,BMP_FILE_HEADER_SIZE+4);
+	mWidth = read_reverse_s32();
+	mHeight = read_reverse_s32();
+
+	return true;
+}
+
+bool LLImageDimensionsInfo::getImageDimensionsTga()
+{
+	const S32 TGA_FILE_HEADER_SIZE = 12;
+
+	mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE);
+	mWidth = read_byte() | read_byte() << 8;
+	mHeight = read_byte() | read_byte() << 8;
+
+	return true;
+}
+
+bool LLImageDimensionsInfo::getImageDimensionsPng()
+{
+	const S32 PNG_FILE_MARKER_SIZE = 8;
+
+	mInfile.seek(APR_CUR,PNG_FILE_MARKER_SIZE + 8/*header offset+chunk length+chunk type*/);
+	mWidth = read_s32();
+	mHeight = read_s32();
+
+	return true;
+}
+
+
+bool LLImageDimensionsInfo::getImageDimensionsJpeg()
+{
+	clean();
+	FILE *fp = fopen (mSrcFilename.c_str(), "rb");
+	if (fp == NULL) 
+	{
+		setLastError("Unable to open file for reading", mSrcFilename);
+		return false;
+	}
+	/* Init jpeg */
+	jpeg_error_mgr jerr;
+	jpeg_decompress_struct cinfo;
+	cinfo.err = jpeg_std_error(&jerr);
+
+	jpeg_create_decompress	(&cinfo);
+	jpeg_stdio_src		(&cinfo, fp);
+	jpeg_read_header	(&cinfo, TRUE);
+	cinfo.out_color_space = JCS_RGB;
+	jpeg_start_decompress	(&cinfo);
+
+	mHeight = cinfo.output_width;
+	mHeight = cinfo.output_height;
+
+	jpeg_destroy_decompress(&cinfo);
+	fclose(fp);
+
+	return true;
+}
+

File indra/llimage/llimagedimensionsinfo.h

+/** 
+ * @file llimagedimentionsinfo.h
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ * 
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_LLIMAGEDIMENSIONSINFO_H
+#define LL_LLIMAGEDIMENSIONSINFO_H
+
+//-----------------------------------------------------------------------------
+// LLImageDimensionsInfo
+// helper class to get image dimensions WITHOUT loading image to memore
+// usefull when image may be too large...
+//-----------------------------------------------------------------------------
+class LLImageDimensionsInfo
+{
+public:
+	LLImageDimensionsInfo():
+		mData(NULL)
+		,mHeight(0)
+		,mWidth(0)
+	{}
+	~LLImageDimensionsInfo()
+	{
+		clean();
+	}
+
+	bool load(const std::string& src_filename,U32 codec);
+	S32 getWidth() const { return mWidth;}
+	S32 getHeight() const { return mHeight;}
+
+	const std::string& getLastError()
+	{
+		return mLastError;
+	}
+protected:
+
+	void clean()
+	{
+		mInfile.close();
+		delete[] mData;
+		mData = NULL;
+		mWidth = 0;
+		mHeight = 0;
+	}
+
+	U8* getData()
+	{
+		return mData;
+	}
+
+
+	void setLastError(const std::string& message, const std::string& filename)
+	{
+		std::string error = message;
+		if (!filename.empty())
+			error += std::string(" FILE: ") + filename;
+		mLastError = error;
+	}
+
+
+	bool getImageDimensionsBmp();
+	bool getImageDimensionsTga();
+	bool getImageDimensionsPng();
+	bool getImageDimensionsJpeg();
+	
+	S32 read_s32()
+	{
+		char p[4];
+		mInfile.read(&p[0],4);
+		S32 temp =	(((S32)p[3])       & 0x000000FF) |
+					(((S32)p[2] << 8 ) & 0x0000FF00) |
+					(((S32)p[1] << 16) & 0x00FF0000) |
+					(((S32)p[0] << 24) & 0xFF000000);
+
+		return temp;
+	}
+	S32 read_reverse_s32()
+	{
+		char p[4];
+		mInfile.read(&p[0],4);
+		S32 temp =	(((S32)p[0])       & 0x000000FF) |
+					(((S32)p[1] << 8 ) & 0x0000FF00) |
+					(((S32)p[2] << 16) & 0x00FF0000) |
+					(((S32)p[3] << 24) & 0xFF000000);
+
+		return temp;
+	}
+
+	U8 read_byte()
+	{
+		U8 bt;
+		mInfile.read(&bt,1);
+		return bt;
+	}
+
+	U16 read_short()
+	{
+		return read_byte() << 8 | read_byte();
+	}
+
+protected:
+	LLAPRFile mInfile ;
+	std::string mSrcFilename;
+
+	std::string mLastError;
+
+	U8* mData;
+
+	S32 mWidth;
+	S32 mHeight;
+};
+#endif

File indra/newview/app_settings/settings.xml

       <key>Value</key>
       <integer>0</integer>
     </map>
-  
+    <key>max_texture_dimension_X</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum texture width for user uploaded textures</string>
+      <key>Persist</key>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>2048</integer>
+    </map>
+    <key>max_texture_dimension_Y</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum texture height for user uploaded textures</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>2048</integer>
+    </map>
     <!-- End of back compatibility settings -->
 </map>
 </llsd>

File indra/newview/llfloaterimagepreview.cpp

 #include "llviewertexturelist.h"
 #include "llstring.h"
 
+#include "llendianswizzle.h"
+
+#include "llviewercontrol.h"
+#include "lltrans.h"
+#include "llimagedimensionsinfo.h"
+
 const S32 PREVIEW_BORDER_WIDTH = 2;
 const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
 const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
 const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
 const S32 PREVIEW_TEXTURE_HEIGHT = 300;
 
-
 //-----------------------------------------------------------------------------
 // LLFloaterImagePreview()
 //-----------------------------------------------------------------------------
 		childShow("bad_image_text");
 		childDisable("clothing_type_combo");
 		childDisable("ok_btn");
+
+		if(!mImageLoadError.empty())
+		{
+			childSetValue("bad_image_text",mImageLoadError.c_str());
+		}
 	}
 	
 	getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this));
 		codec = IMG_CODEC_PNG;
 	}
 
+	LLImageDimensionsInfo image_info;
+	if(!image_info.load(src_filename,codec))
+	{
+		mImageLoadError = image_info.getLastError();
+		return false;
+	}
+
+	S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
+	S32 max_heigh = gSavedSettings.getS32("max_texture_dimension_Y");
+
+	if(image_info.getWidth() > max_width|| image_info.getHeight() > max_heigh)
+	{
+		LLStringUtil::format_map_t args;
+		args["WIDTH"] = llformat("%d", max_width);
+		args["HEIGHT"] = llformat("%d", max_heigh);
+
+		mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
+		return false;
+	}
+	
+
 	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
 
 	switch (codec)

File indra/newview/llfloaterimagepreview.h

 	LLRect			mPreviewRect;
 	LLRectf			mPreviewImageRect;
 	LLPointer<LLViewerTexture> mImagep ;
-
+	
+	std::string mImageLoadError;
 };
 
 #endif  // LL_LLFLOATERIMAGEPREVIEW_H

File indra/newview/skins/default/xui/en/strings.xml

   <!-- birth date format shared by avatar inspector and profile panels -->
   <string name="AvatarBirthDateFormat">[mthnum,datetime,slt]/[day,datetime,slt]/[year,datetime,slt]</string>
 
+  <string name="texture_load_dimensions_error">Can't load images larger then [WIDTH]*[HEIGHT]</string>
+
 </strings>