18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
58c2ecf20Sopenharmony_ci * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Created by Arjan van de Ven <arjanv@redhat.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Very simple lz77-ish encoder.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Theory of operation: Both encoder and decoder have a list of "last
168c2ecf20Sopenharmony_ci * occurrences" for every possible source-value; after sending the
178c2ecf20Sopenharmony_ci * first source-byte, the second byte indicated the "run" length of
188c2ecf20Sopenharmony_ci * matches
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * The algorithm is intended to only send "whole bytes", no bit-messing.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/kernel.h>
258c2ecf20Sopenharmony_ci#include <linux/types.h>
268c2ecf20Sopenharmony_ci#include <linux/errno.h>
278c2ecf20Sopenharmony_ci#include <linux/string.h>
288c2ecf20Sopenharmony_ci#include <linux/jffs2.h>
298c2ecf20Sopenharmony_ci#include "compr.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* _compress returns the compressed size, -1 if bigger */
328c2ecf20Sopenharmony_cistatic int jffs2_rtime_compress(unsigned char *data_in,
338c2ecf20Sopenharmony_ci				unsigned char *cpage_out,
348c2ecf20Sopenharmony_ci				uint32_t *sourcelen, uint32_t *dstlen)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	unsigned short positions[256];
378c2ecf20Sopenharmony_ci	int outpos = 0;
388c2ecf20Sopenharmony_ci	int pos=0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (*dstlen <= 3)
418c2ecf20Sopenharmony_ci		return -1;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	memset(positions,0,sizeof(positions));
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
468c2ecf20Sopenharmony_ci		int backpos, runlen=0;
478c2ecf20Sopenharmony_ci		unsigned char value;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci		value = data_in[pos];
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci		cpage_out[outpos++] = data_in[pos++];
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci		backpos = positions[value];
548c2ecf20Sopenharmony_ci		positions[value]=pos;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		while ((backpos < pos) && (pos < (*sourcelen)) &&
578c2ecf20Sopenharmony_ci		       (data_in[pos]==data_in[backpos++]) && (runlen<255)) {
588c2ecf20Sopenharmony_ci			pos++;
598c2ecf20Sopenharmony_ci			runlen++;
608c2ecf20Sopenharmony_ci		}
618c2ecf20Sopenharmony_ci		cpage_out[outpos++] = runlen;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (outpos >= pos) {
658c2ecf20Sopenharmony_ci		/* We failed */
668c2ecf20Sopenharmony_ci		return -1;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* Tell the caller how much we managed to compress, and how much space it took */
708c2ecf20Sopenharmony_ci	*sourcelen = pos;
718c2ecf20Sopenharmony_ci	*dstlen = outpos;
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int jffs2_rtime_decompress(unsigned char *data_in,
778c2ecf20Sopenharmony_ci				  unsigned char *cpage_out,
788c2ecf20Sopenharmony_ci				  uint32_t srclen, uint32_t destlen)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	unsigned short positions[256];
818c2ecf20Sopenharmony_ci	int outpos = 0;
828c2ecf20Sopenharmony_ci	int pos=0;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	memset(positions,0,sizeof(positions));
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	while (outpos<destlen) {
878c2ecf20Sopenharmony_ci		unsigned char value;
888c2ecf20Sopenharmony_ci		int backoffs;
898c2ecf20Sopenharmony_ci		int repeat;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		value = data_in[pos++];
928c2ecf20Sopenharmony_ci		cpage_out[outpos++] = value; /* first the verbatim copied byte */
938c2ecf20Sopenharmony_ci		repeat = data_in[pos++];
948c2ecf20Sopenharmony_ci		backoffs = positions[value];
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		positions[value]=outpos;
978c2ecf20Sopenharmony_ci		if (repeat) {
988c2ecf20Sopenharmony_ci			if (backoffs + repeat >= outpos) {
998c2ecf20Sopenharmony_ci				while(repeat) {
1008c2ecf20Sopenharmony_ci					cpage_out[outpos++] = cpage_out[backoffs++];
1018c2ecf20Sopenharmony_ci					repeat--;
1028c2ecf20Sopenharmony_ci				}
1038c2ecf20Sopenharmony_ci			} else {
1048c2ecf20Sopenharmony_ci				memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
1058c2ecf20Sopenharmony_ci				outpos+=repeat;
1068c2ecf20Sopenharmony_ci			}
1078c2ecf20Sopenharmony_ci		}
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic struct jffs2_compressor jffs2_rtime_comp = {
1138c2ecf20Sopenharmony_ci    .priority = JFFS2_RTIME_PRIORITY,
1148c2ecf20Sopenharmony_ci    .name = "rtime",
1158c2ecf20Sopenharmony_ci    .compr = JFFS2_COMPR_RTIME,
1168c2ecf20Sopenharmony_ci    .compress = &jffs2_rtime_compress,
1178c2ecf20Sopenharmony_ci    .decompress = &jffs2_rtime_decompress,
1188c2ecf20Sopenharmony_ci#ifdef JFFS2_RTIME_DISABLED
1198c2ecf20Sopenharmony_ci    .disabled = 1,
1208c2ecf20Sopenharmony_ci#else
1218c2ecf20Sopenharmony_ci    .disabled = 0,
1228c2ecf20Sopenharmony_ci#endif
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciint jffs2_rtime_init(void)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci    return jffs2_register_compressor(&jffs2_rtime_comp);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_civoid jffs2_rtime_exit(void)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci    jffs2_unregister_compressor(&jffs2_rtime_comp);
1338c2ecf20Sopenharmony_ci}
134