/*
 * include/linux/rle_defalte.c
 * 
 * rle deflate routine
 * 
 * Copyright 2005,2006 Sony Corporation
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 */
//#define DEBUG
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/rle.h>
EXPORT_SYMBOL(rle_deflate);
#else
#include <stdio.h>
#include <string.h>
#include "rle.h"
typedef unsigned char u8;
#endif

int rle_deflate(void *src, int sl, void *dst, int dl)
{
	unsigned char *s = src;
	unsigned char *d = dst;
	unsigned char *se = s+sl;
	unsigned char *m;
	unsigned char c=*s++;
	unsigned char state;

	*d++ = RLE_COMPRESSED;
	m=d++;
	while(s<se){
		int i=0;
		state = (c==*s);
		if(state){
			while(s<se && *s==c && i<127){
				s++;
				i++;
			}
			*m = (unsigned char)i;
			*m |= 0x80;
			*d++ = c;
			m = d++;
			if(s<se){
				c = *s++;
				if(s==se&&i==127){
					*m = 1;
					*d++ = c;
					m = d++;
				}
			}
		}
		else{
			*m = 0;
			*d++ = c;
			c = *s++;
			while(*s!=c && s<se && i<126){
				*d++ = c;
				c = *s++;
				i++;
			}
			*m = (i+1);
			m = d++;
		}
	}

	state = (s[-1]==s[-2]);
	*m = !state;
	if(!state){
		*d++ = c;
		*d++ = 0;
	}

        rle_printf("deflated %d:%d\n", sl, d-(unsigned char *)dst);

	if((d-(unsigned char *)dst)>sl){
		rle_printf("fall back to raw data!\n");
		d = dst;
		*d++ = RLE_RAW;
		d++;
		*d++ = sl&0xFF;
		*d++ = sl>>8;
		memcpy(d, src, sl);
		d += sl;
		
	}
	return (d-(unsigned char *)dst);
}

