odd pointer error

Started by
2 comments, last by Enigma 17 years, 10 months ago
ok this is a error with a .tga loader function i have written. The problem i am haveing is pointer related, I think. First off is the code (tga struct and function).


#define TGA_RGB		 2		// This tells us it's a normal RGB (really BGR) file
#define TGA_A		 3		// This tells us it's a ALPHA file
#define TGA_RLE		10		// This tells us that the targa is Run-Length Encoded (RLE)

typedef unsigned char byte;	
	struct  TGAFILE {

		unsigned short int ImageWidth;
		unsigned short int ImageHight;
		unsigned short int channels;

		unsigned char *Image;

	};

	TGAFILE *LoadTGA(const char *filename);





TGAFILE *LoadTGA(const char *filename) {

	TGAFILE *		tgafile = NULL;
	std::ifstream	read;
	byte			length, ImageType, bits;
	WORD			width = 0, height = 0;
	int				stride = 0, channels = 0, i = 0;

	read.open(filename, std::ios::binary);

	tgafile = new TGAFILE;
	
	read.read((char *)&length, sizeof(length));
	read.ignore(1);
	read.read((char *)&ImageType, sizeof(ImageType));
	read.ignore(9);//ignore everything until we get to width
	read.read((char *)&width, sizeof(width));
	read.read((char *)&height, sizeof(height));
	read.read((char *)&bits, sizeof(bits));
	read.ignore(length + 1);//now move to the image data

	if(ImageType != TGA_RLE) {
		if(bits == 24 || bits == 32) {

			channels	= bits/8;
			stride		= channels * width;

			tgafile->Image = new byte[stride * height];

			int x, y;

			//read the data into row data
			for(y = 0; y < height; y++) {

				//get the current line of the image we are on
				byte * line = &(tgafile->Image[stride * y]);

				//now read the image data into the line buffer
				for(x = 0; x < stride; x++) {

					read.read((char *)&line[x], sizeof(byte));
				}//end x for

				//now swap the red and blue values so its in RBG format
				for(i = 0; i < stride; i += channels) {

					int temp    = line;
					line     = line;
					line = temp;
				}<span class="cpp-comment">//end i for</span>
			}<span class="cpp-comment">//end y for</span>
		}<span class="cpp-comment">//end bits == 24 || bits == 32 if</span>

		<span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span>(bits == <span class="cpp-number">16</span>) {
	
			<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">short</span> pixels = <span class="cpp-number">0</span>;
			<span class="cpp-keyword">int</span> r = <span class="cpp-number">0</span>, g = <span class="cpp-number">0</span>, b = <span class="cpp-number">0</span>;

			channels	= bits/<span class="cpp-number">8</span>;
			stride		= channels * width;

			tgafile-&gt;Image = <span class="cpp-keyword">new</span> byte[stride * height];

			<span class="cpp-keyword">for</span>(i = <span class="cpp-number">0</span>; i &lt; (width * height); i++) {

				<span class="cpp-comment">//read data a pixel at a time and then swap the values</span>
				read.read((<span class="cpp-keyword">char</span> *)&amp;pixels, <span class="cpp-keyword">sizeof</span>(pixels));

				b = (pixels &amp; 0x1f) &lt;&lt; <span class="cpp-number">3</span>;
				g = ((pixels &gt;&gt; <span class="cpp-number">5</span>) &amp; 0x1f) &lt;&lt; <span class="cpp-number">3</span>;
				r = ((pixels &gt;&gt; <span class="cpp-number">10</span>) &amp; 0x1f) &lt;&lt; <span class="cpp-number">3</span>;

				<span class="cpp-comment">//now assigne them to the image data</span>
				tgafile-&gt;Image = r;
				tgafile-&gt;Image = g;
				tgafile-&gt;Image = b;

			}<span class="cpp-comment">//end i for</span>
		}<span class="cpp-comment">//end bits == 16 else if</span>

		<span class="cpp-comment">//if its not any of the above then its a unknown</span>
		<span class="cpp-comment">// type and we must exit</span>
		<span class="cpp-keyword">else</span> {

			<span class="cpp-keyword">return</span> NULL;
		}<span class="cpp-comment">//end else</span>
	}<span class="cpp-comment">//end ImageType != TGA_RLE if</span>

	<span class="cpp-keyword">else</span> {<span class="cpp-comment">//if it gets here then the file is RLE</span>

		byte rleID = <span class="cpp-number">0</span>;
		<span class="cpp-keyword">int</span> colorsRead = <span class="cpp-number">0</span>;
		channels = bits/<span class="cpp-number">8</span>;
		stride = channels * width;
		<span class="cpp-keyword">bool</span> iseof = <span class="cpp-keyword">false</span>;

		tgafile-&gt;Image = <span class="cpp-keyword">new</span> byte[stride * height];
		byte * Colors = <span class="cpp-keyword">new</span> byte[channels];

		<span class="cpp-comment">//now load the data</span>
		<span class="cpp-keyword">while</span>(i &lt; (width * height)) {

			read.read((<span class="cpp-keyword">char</span> *)&amp;rleID, <span class="cpp-keyword">sizeof</span>(rleID));

			<span class="cpp-keyword">if</span>(rleID &lt; <span class="cpp-number">128</span>) {

				rleID++;

				<span class="cpp-keyword">while</span>(rleID) {

					read.read((<span class="cpp-keyword">char</span> *)&amp;Colors, (<span class="cpp-keyword">sizeof</span>(byte) * channels));



					<span class="cpp-comment">// Store the current pixel in our image array</span>
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">0</span>] = Colors[<span class="cpp-number">2</span>];
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">1</span>] = Colors[<span class="cpp-number">1</span>];
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">2</span>] = Colors[<span class="cpp-number">0</span>];

					<span class="cpp-comment">// If we have a 4 channel 32-bit image, assign one more for the alpha</span>
					<span class="cpp-keyword">if</span>(bits == <span class="cpp-number">32</span>) {

						tgafile-&gt;Image[colorsRead + <span class="cpp-number">3</span>] = Colors[<span class="cpp-number">3</span>];
					}<span class="cpp-comment">//end bits == 32 if</span>

					<span class="cpp-comment">// Increase the current pixels read, decrease the amount</span>
					<span class="cpp-comment">// of pixels left, and increase the starting index for the next pixel.</span>
					i++;
					rleID–;
					colorsRead += channels;

				}<span class="cpp-comment">//end rleID while</span>
			}<span class="cpp-comment">//end rleID &lt; 128 if</span>

			<span class="cpp-keyword">else</span> {

				<span class="cpp-comment">// Minus the 128 ID + 1 (127) to get the color count that needs to be read</span>
				rleID -= <span class="cpp-number">127</span>;

				read.read((<span class="cpp-keyword">char</span> *)&amp;Colors, (<span class="cpp-keyword">sizeof</span>(byte) * channels));

				<span class="cpp-keyword">while</span>(rleID) {

					<span class="cpp-comment">// Assign the current pixel to the current index in our pixel array</span>
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">0</span>] = Colors[<span class="cpp-number">2</span>];
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">1</span>] = Colors[<span class="cpp-number">1</span>];
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">2</span>] = Colors[<span class="cpp-number">0</span>];

					<span class="cpp-comment">// If we have a 4 channel 32-bit image, assign one more for the alpha</span>
					<span class="cpp-keyword">if</span>(bits == <span class="cpp-number">32</span>)
						tgafile-&gt;Image[colorsRead + <span class="cpp-number">3</span>] = Colors[<span class="cpp-number">3</span>];

					<span class="cpp-comment">// Increase the current pixels read, decrease the amount</span>
					<span class="cpp-comment">// of pixels left, and increase the starting index for the next pixel.</span>
					i++;
					rleID–;
					colorsRead += channels;
				}<span class="cpp-comment">//end rleID while</span>
			}<span class="cpp-comment">//end rleID &lt; 128 else</span>
		}<span class="cpp-comment">//end i while</span>
	}<span class="cpp-comment">//end ImageType == TGA_RLE else</span>

	read.close();

	tgafile-&gt;channels = channels;
	tgafile-&gt;ImageWidth = width;
	tgafile-&gt;ImageHight = height;

	<span class="cpp-keyword">return</span> tgafile;
	
}<span class="cpp-comment">//end LoadTGA</span>



</pre></div><!–ENDSCRIPT–>


     Now the problem is after 18 loops though this part of the code:

<!–STARTSCRIPT–><!–source lang="cpp"–><div class="source"><pre>

<span class="cpp-keyword">while</span>(rleID) {

					read.read((<span class="cpp-keyword">char</span> *)&amp;Colors, (<span class="cpp-keyword">sizeof</span>(byte) * channels));

					iseof = read.eof();

					<span class="cpp-comment">// Store the current pixel in our image array</span>
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">0</span>] = Colors[<span class="cpp-number">2</span>];
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">1</span>] = Colors[<span class="cpp-number">1</span>];
					tgafile-&gt;Image[colorsRead + <span class="cpp-number">2</span>] = Colors[<span class="cpp-number">0</span>];

					<span class="cpp-comment">// If we have a 4 channel 32-bit image, assign one more for the alpha</span>
					<span class="cpp-keyword">if</span>(bits == <span class="cpp-number">32</span>) {

						tgafile-&gt;Image[colorsRead + <span class="cpp-number">3</span>] = Colors[<span class="cpp-number">3</span>];
					}<span class="cpp-comment">//end bits == 32 if</span>

					<span class="cpp-comment">// Increase the current pixels read, decrease the amount</span>
					<span class="cpp-comment">// of pixels left, and increase the starting index for the next pixel.</span>
					i++;
					rleID–;
					colorsRead += channels;

				}<span class="cpp-comment">//end rleID while</span>


</pre></div><!–ENDSCRIPT–>


   &#79;n the 18th loop after the call to read the debugger reads the pointer Colors as being a bad pointer. It also then gives CXX0030 error. personaly i am confused as to how this can happen when the past 17 loops worked fine and despite my best efforts i can come up with any further details or ideas as to what i am doing wrong here and any help is welcome.
Advertisement
While it's not your primary problem you never delete Colors; also, I had some trouble following your code since your naming randomly switches between no word seperation and camel notation.
I don't think this line does what you think it does:
read.read((char *)&Colors, (sizeof(byte) * channels));

This is writing the data to the address of Colors, and not the address that Colors points to. This is probably trashing the stack. Why it doesn't cause a problem in the first 17 loops is beyond me.
Well, it's such horrible code it took me a while to find your problem:

read.read((char *)&Colors, (sizeof(byte) * channels));

Colors is already a pointer. You're not reading into the array Colors points at, your overwriting the Colors pointer itself. Give me a moment and I'll rewrite your code so that it works, is readable, is exception-safe and doesn't leak memory like nobody's business.

EDIT: It's not perfect by a long shot, but it's a lot better than your version. There are probably bugs - I didn't test it very thoroughly:
#include <string>#include <vector>// We're more interested in tga as an Image than as a File, so// name the class to reflect thatclass TgaImage{	public:		// functions which create objects should usually be		// constructors		// std::string is better than char * because it allows		// clients to use either a char * or a std::string		// when creating a TgaImage, rather than only allowing		// a char *		TgaImage(std::string const & filename);		// we don't want clients to arbitrarily change the		// width, height or number of channels without actually		// changing the data correctly, so make those values		// read-only by encapsulating them and providing 'getters'		unsigned short height() const;		unsigned short number_of_channels() const;		unsigned short width() const;	private:		// some helper functions		void read_rle_tga_image(std::istream & reader);		void read_16_bit_raw_tga_image(std::istream & reader);		void read_24_or_32_bit_raw_tga_image(std::istream & reader);		typedef unsigned char byte;		unsigned short width_;		unsigned short height_;		unsigned short channels_;		// vector is a dynamic array class.  it's much easier		// to use than raw pointers		std::vector< byte > data_;};

#include "TgaImage.h"#include <cassert>#include <fstream>#include <stdexcept>// the unnamed namespace restricts the scope of variables and// functions to this translation unit (.cpp file) only.namespace{	typedef unsigned char byte;	// prefer constants to #defines	// constants respect scope, the preprocessor does not	const byte type_rgb = 2;	const byte type_alpha = 3;	const byte type_rle = 10;	// a simple templated function for binary file input	template < typename Type >	void read_binary(std::istream & reader, Type & value)	{		// prefer the C++ casts (static_cast, const_cast,		// reinterpret_cast and dynamic_cast) to C-style casts		// The C++ casts are more expressive, won't silently		// do the wrong thing depending on context and are easy		// to find		reader.read(reinterpret_cast< char * >(&value), sizeof(Type));		// error checking		if (reader.fail())		{			throw std::runtime_error("error reading file");		}	}	// a specialization of the template for reading into a vector	template < typename Type >	void read_binary(std::istream & reader, std::vector< Type > & vector)	{		// don't want to index into an empty vector		if (vector.empty())		{			return;		}		reader.read(reinterpret_cast< char * >(&vector[0]), vector.size() * sizeof(Type));		if (reader.fail())		{			throw std::runtime_error("error reading file");		}	}}TgaImage::TgaImage(std::string const & filename){	// restrict using statements to the smallest scope possible	using namespace std;	// initialize at time of construction - it's often more	// efficient and never less so.	ifstream reader(filename.c_str(), ios::binary);	// it is reasonable to expect loading a tga file to succeed	// therefore an exception is a sensible approach if the	// unexpected happens	if (!reader)	{		throw std::runtime_error(("could not find tga file \'" + filename + "\'").c_str());	}	// delay declaration of variables until they are needed	// this helps keep the source more readable	byte length;	read_binary(reader, length);	// i would prefer to use a symbolic constant here, but I don't	// know tga files so I haven't a clue what that '1' is!	reader.ignore(1);	byte image_type;	read_binary(reader, image_type);	reader.ignore(9);	// error checking - make sure that unsigned char really is	// 16 bits.  still not sufficient, since a byte on this	// platform may not be eight bits, but it'll do	assert(sizeof(width_) == 2 && sizeof(height_) == 2);	read_binary(reader, width_);	read_binary(reader, height_);	byte bpp;	read_binary(reader, bpp);	reader.ignore(length + 1);	if (bpp != 16 && bpp != 24 && bpp != 32)	{		throw std::runtime_error("could not load tga file - bits-per-pixel must be 16, 24 or 32");	}	// since 16 bpp is a packed format with three channels we	// have to correct this line.  since the meaning is not	// apparent from just reading the source a comment is	// essential	channels_ = std::max< byte >(bpp, 24) / 8;	unsigned int stride = width_ * channels_;	// allocate our image data array.  vector is an RAII wrapper	// it handles allocation and deallocation for us, so we can	// just 'allocate and forget'.	data_.resize(stride * height_);	if (image_type == type_rle)	{		// can't handle 16 bpp rle files, so error out		if (bpp == 16)		{			throw std::runtime_error("could not load tga file - rle image bits-per-pixel must be 24 or 32");		}		// this is a logical place to break the function and stop		// it getting too big and difficult to understand as a		// whole		read_rle_tga_image(reader);	}	else	{		if (bpp == 16)		{			read_16_bit_raw_tga_image(reader);		}		else		{			read_24_or_32_bit_raw_tga_image(reader);		}	}}unsigned short TgaImage::height() const{	return height_;}unsigned short TgaImage::number_of_channels() const{	return channels_;}unsigned short TgaImage::width() const{	return width_;}void TgaImage::read_rle_tga_image(std::istream & reader){	for (unsigned int i = 0; i < static_cast< unsigned int >(width_ * height_);)	{		byte rle_type;		read_binary(reader, rle_type);		if (rle_type < 128)		{			byte pixel_count = rle_type + 1;			reader.read(reinterpret_cast< char * >(&data_), pixel_count * channels_);<br>			<span class="cpp-keyword">if</span> (reader.fail())<br>			{<br>				<span class="cpp-keyword">throw</span> std::runtime_error(<span class="cpp-literal">"error reading file"</span>);<br>			}<br>			<span class="cpp-keyword">for</span> (<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">int</span> pixel = i * channels_; pixel &lt; (i + pixel_count) * channels_; pixel += channels_)<br>			{<br>				std::swap(data_[pixel], data_[pixel + <span class="cpp-number">2</span>]);<br>			}<br>			i += pixel_count;<br>		}<br>		<span class="cpp-keyword">else</span><br>		{<br>			byte run_length = rle_type - <span class="cpp-number">127</span>;<br>			byte colours[<span class="cpp-number">4</span>];<br>			reader.read(<span class="cpp-keyword">reinterpret_cast</span>&lt; <span class="cpp-keyword">char</span> * &gt;(&amp;colours), channels_);<br>			<span class="cpp-keyword">if</span> (reader.fail())<br>			{<br>				<span class="cpp-keyword">throw</span> std::runtime_error(<span class="cpp-literal">"error reading file"</span>);<br>			}<br>			<span class="cpp-keyword">for</span> (byte pixel = <span class="cpp-number">0</span>; pixel &lt; run_length; ++pixel)<br>			{<br>				data_[(i * channels_) + <span class="cpp-number">0</span>] = colours[<span class="cpp-number">2</span>];<br>				data_[(i * channels_) + <span class="cpp-number">1</span>] = colours[<span class="cpp-number">1</span>];<br>				data_[(i * channels_) + <span class="cpp-number">2</span>] = colours[<span class="cpp-number">0</span>];<br>				<span class="cpp-keyword">if</span> (channels_ == <span class="cpp-number">4</span>)<br>				{<br>					data_[(i * channels_) + <span class="cpp-number">3</span>] = colours[<span class="cpp-number">3</span>];<br>				}<br>				i += channels_;<br>			}<br>		}<br>	}<br>}<br><br><span class="cpp-keyword">void</span> TgaImage::read_16_bit_raw_tga_image(std::istream &amp; reader)<br>{<br>	<span class="cpp-keyword">for</span> (<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>; i &lt; <span class="cpp-keyword">static_cast</span>&lt; <span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">int</span> &gt;(width_ * height_); ++i)<br>	{<br>		<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">short</span> packed_pixel;<br>		read_binary(reader, packed_pixel);<br><br>		<span class="cpp-comment">// red component</span><br>		data_[(i * channels_) + <span class="cpp-number">0</span>] = ((packed_pixel &gt;&gt; <span class="cpp-number">10</span>) &amp; 0x1f) &lt;&lt; <span class="cpp-number">3</span>;<br><br>		<span class="cpp-comment">// green component</span><br>		data_[(i * channels_) + <span class="cpp-number">1</span>] = ((packed_pixel &gt;&gt;  <span class="cpp-number">5</span>) &amp; 0x1f) &lt;&lt; <span class="cpp-number">3</span>;<br><br>		<span class="cpp-comment">// blue component</span><br>		data_[(i * channels_) + <span class="cpp-number">2</span>] = ((packed_pixel &gt;&gt;  <span class="cpp-number">0</span>) &amp; 0x1f) &lt;&lt; <span class="cpp-number">3</span>;<br>	}<br>}<br><br><span class="cpp-keyword">void</span> TgaImage::read_24_or_32_bit_raw_tga_image(std::istream &amp; reader)<br>{<br>	read_binary(reader, data_);<br>	<span class="cpp-keyword">for</span> (<span class="cpp-keyword">unsigned</span> <span class="cpp-keyword">int</span> i = <span class="cpp-number">0</span>; i &lt; data_.size(); i += channels_)<br>	{<br>		std::swap(data_<span style="font-weight:bold;">, data_);<br>	}<br>}<br></pre></div><!–ENDSCRIPT–><br><br>&Sigma;nigma<br><br><!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - Enigma on June 12, 2006 5:22:37 PM]<!–EDIT–></span><!–/EDIT–>

This topic is closed to new replies.

Advertisement