int IODeviceProvider_PipeConnection::peek(void *data, int len)
{
	if (peeked_data.get_size() >= len)
	{
		memcpy(data, peeked_data.get_data(), len);
		return len;
	}
	else
	{
		int old_size = peeked_data.get_size();
		try
		{
			peeked_data.set_size(len);
			int bytes_read = lowlevel_read(peeked_data.get_data()+old_size, len-old_size, false);
			peeked_data.set_size(old_size+bytes_read);
			memcpy(data, peeked_data.get_data(), peeked_data.get_size());
			return peeked_data.get_size();
		}
		catch (const Exception& e)
		{
			peeked_data.set_size(old_size);
			throw;
		}
	}
}
int CL_ZipIODevice_FileEntry::receive(void *buffer, int size, bool receive_all)
{
	if (size == 0)
		return 0;
	if (peeked_data.get_size() > 0)
	{
		int peek_amount = cl_min(size, peeked_data.get_size());
		memcpy(buffer, peeked_data.get_data(), peek_amount);
		memmove(peeked_data.get_data(), peeked_data.get_data()+peek_amount, peeked_data.get_size()-peek_amount);
		peeked_data.set_size(peeked_data.get_size()-peek_amount);
		if (peek_amount <= size)
			return peek_amount + receive((char*) buffer+peek_amount, size-peek_amount, receive_all);
	}

	return lowlevel_read(buffer, size, receive_all);
}
int IODeviceProvider_PipeConnection::receive(void *buffer, int size, bool receive_all)
{
	if (size == 0)
		return 0;
	if (peeked_data.get_size() > 0)
	{
		int peek_amount = min(size, peeked_data.get_size());
		memcpy(buffer, peeked_data.get_data(), peek_amount);
		memmove(peeked_data.get_data(), peeked_data.get_data()+peek_amount, peeked_data.get_size()-peek_amount);
		peeked_data.set_size(peeked_data.get_size()-peek_amount);
		if (peek_amount <= size)
			return peek_amount + receive((char*) buffer+peek_amount, size-peek_amount, receive_all);
	}

	return lowlevel_read(buffer, size, receive_all);
}
int CL_IODeviceProvider_File::read(void *buffer, int size, bool read_all)
{
	if (size == 0)
		return 0;
	if (peeked_data.get_size() > 0)
	{
		#define cl_min(a,b) ((a)<(b)?(a):(b))
		int peek_amount = cl_min(size, peeked_data.get_size());
		memcpy(buffer, peeked_data.get_data(), peek_amount);
		memmove(peeked_data.get_data(), peeked_data.get_data()+peek_amount, peeked_data.get_size()-peek_amount);
		peeked_data.set_size(peeked_data.get_size()-peek_amount);
		if (peek_amount <= size)
			return peek_amount + read((char*) buffer+peek_amount, size-peek_amount, read_all);
	}

	return lowlevel_read(buffer, size, read_all);
}