unsigned int CL_SoundProvider_Wave_Impl::find_subchunk(const char *chunk, CL_IODevice &source, unsigned int file_offset, unsigned int max_offset )
{
	char subchunk1_id[4];

	max_offset -= 8;	// Each subchunk must contains at least name and size
	while(file_offset < max_offset)
	{
		source.seek(file_offset);
		source.read(subchunk1_id, 4);
		cl_ubyte32 subchunk1_size = source.read_uint32();
		if (!memcmp(subchunk1_id, chunk, 4))
		{
			// Found chunk
			return subchunk1_size;
		}
		file_offset += subchunk1_size + 8;
	}
	throw CL_Exception("Block not found!");

}
예제 #2
0
void CL_PCXProvider_Impl::read_pcx(
	CL_IODevice &_datafile)
{
	// Read the file header and initialize the variables
	// This method was created to breakup the PCX decoding code
	// so the initializing code was separated from the actual
	// decoding algorithm

	unsigned char header[128];  

	{
		int read = _datafile.read(header, 128);
		if (read != 128)
			throw CL_Exception("File not big enough to read the PCX header");
	}

	// only the useful fields that will be used more than once
	struct PCXHeader {
		unsigned char version;
		unsigned char encoding;
		unsigned char bits_per_pixel_per_plane;
		short xmin;
		short ymin;
		short xmax;
		short ymax;
		unsigned char color_map[48];
		unsigned char nplanes;
		unsigned short bytes_per_line;
	} pcx_header;

	if (header[0] != 10)
		throw CL_Exception("Not a PCX file");

	pcx_header.version = header[1];
	pcx_header.encoding = header[2];
	pcx_header.bits_per_pixel_per_plane = header[3];
	pcx_header.xmin = (header[5] << 8) | header[4];	
	pcx_header.ymin = (header[7] << 8) | header[6];
	pcx_header.xmax = (header[9] << 8) | header[8];
	pcx_header.ymax = (header[11] << 8) | header[10];

	const int width = (pcx_header.xmax - pcx_header.xmin) + 1;
	const int height = (pcx_header.ymax - pcx_header.ymin) + 1;

	memcpy(pcx_header.color_map, &header[16], sizeof(pcx_header.color_map));
	pcx_header.nplanes = header[65];
	pcx_header.bytes_per_line = (header[67] << 8) | header[66];

	// both 8bit with palette and 24bit rgb modes require version 5
	if (pcx_header.version < 5)
		throw CL_Exception("PCX version unsupported");

	const int total_line_bytes = pcx_header.bytes_per_line * pcx_header.nplanes;

	int pitch = 0;

	// decide which pixelformat to use (8 bit palette or 24 bit)
	if (pcx_header.nplanes == 3 && pcx_header.bits_per_pixel_per_plane == 8)
	{
		// 24 bit RGB mode
		pitch = width * 3;
		image = new unsigned char[pitch * height];
		if (image == 0)
			throw CL_Exception("Unable to allocate memory for pcx image");

		unsigned char *p = image;
		const int extra = total_line_bytes - pitch;

		// get the data
		if (!pcx_header.encoding)
		{
			// uncompressed
			for (int y = 0; y < height; y++)
			{
				_datafile.read(p, pitch);
				if (extra > 0)
					_datafile.seek(extra, CL_IODevice::seek_cur);
				p += pitch;
			}
		}
		else
		{
			// compressed
			for (int y = 0; y < height; y++)
			{
				int count;
				// first red component
				int x = 0, xx = 0, comp = 0;
				while (x < total_line_bytes)
				{
					int ch = _datafile.read_uint8();
					if ((ch & 0xC0) == 0xC0)
					{
						count = ch & 0x3F;
						ch = _datafile.read_uint8();
					}
					else
						count = 1;

					while (count--)
					{
						if (xx < width)
							image[(y * pitch) + ((xx * 3) + comp)] = ch;
						x++;
						if (x == pcx_header.bytes_per_line)
						{
							// blue component now
							comp = 1;
							xx = 0;
						}
						else if (x == pcx_header.bytes_per_line*2)
						{
							// green component now
							comp = 2;
							xx = 0;
						}
						else
							xx++;
					}
				}
			}
		}
		CL_PCXProvider_Impl::sized_format = cl_bgr8;
		CL_PCXProvider_Impl::pitch = pitch;
		CL_PCXProvider_Impl::width = width;
		CL_PCXProvider_Impl::height = height;
	}
	else if (pcx_header.nplanes == 1 && pcx_header.bits_per_pixel_per_plane == 8)
	{
		// 8 bit indexed mode
		pitch = width;
		image = new unsigned char[pitch * height];
		if (image == 0)
			throw CL_Exception("Unable to allocate memory for pcx image");

		unsigned char *p = image;
		const int extra = total_line_bytes - pitch;

		// get the data
		if (!pcx_header.encoding)
		{
			// uncompressed
			for (int y = 0; y < height; y++)
			{
				_datafile.read(p, pitch);
				if (extra > 0)
					_datafile.seek(extra, CL_IODevice::seek_cur);
				p += pitch;
			}
		}
		else
		{
			// compressed
			for (int y = 0; y < height; y++)
			{
				int count;
				int x = 0;
				while (x < total_line_bytes)
				{
					int ch = _datafile.read_uint8();
					if ((ch & 0xC0) == 0xC0)
					{
						count = ch & 0x3F;
						ch = _datafile.read_uint8();
					}
					else
						count = 1;
					
					while (count--)
					{
						if (x < width)
						{
							*p = ch;
							p++;
						}
						x++;
					}
				}
			}
		}

		// read the palette
		if (_datafile.read_int8() != 12)
		{
			delete[] image;
			throw CL_Exception("Palette not found");
		}
		for (int i = 0; i < 256; i++)
		{
			const int r = _datafile.read_uint8();
			const int g = _datafile.read_uint8();
			const int b = _datafile.read_uint8();
			palette[i].set_color(r, g, b);
		}

		CL_PCXProvider_Impl::sized_format = cl_color_index;
		CL_PCXProvider_Impl::pitch = pitch;
		CL_PCXProvider_Impl::width = width;
		CL_PCXProvider_Impl::height = height;
	}
	else
		throw CL_Exception("Unsupported PCX format");
}