/* | |
* RLE decoding routine | |
* | |
* Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org> | |
* | |
* This program is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU General Public License version 2 as published | |
* by the Free Software Foundation. | |
*/ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/rle.h> | |
int rle_decode(const unsigned char *src, size_t srclen, | |
unsigned char *dst, size_t dstlen, | |
size_t *src_done, size_t *dst_done) | |
{ | |
size_t srcpos, dstpos; | |
int ret; | |
srcpos = 0; | |
dstpos = 0; | |
ret = -EINVAL; | |
/* sanity checks */ | |
if (!src || !srclen || !dst || !dstlen) | |
goto out; | |
while (1) { | |
char count; | |
if (srcpos >= srclen) | |
break; | |
count = (char) src[srcpos++]; | |
if (count == 0) { | |
ret = 0; | |
break; | |
} | |
if (count > 0) { | |
unsigned char c; | |
if (srcpos >= srclen) | |
break; | |
c = src[srcpos++]; | |
while (count--) { | |
if (dstpos >= dstlen) | |
break; | |
dst[dstpos++] = c; | |
} | |
} else { | |
count *= -1; | |
while (count--) { | |
if (srcpos >= srclen) | |
break; | |
if (dstpos >= dstlen) | |
break; | |
dst[dstpos++] = src[srcpos++]; | |
} | |
} | |
} | |
out: | |
if (src_done) | |
*src_done = srcpos; | |
if (dst_done) | |
*dst_done = dstpos; | |
return ret; | |
} | |
EXPORT_SYMBOL_GPL(rle_decode); |