xref: /freebsd/sys/dev/cxgbe/cudbg/fastlz_api.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1f856f099SNavdeep Parhar /*
2f856f099SNavdeep Parhar    FastLZ - lightning-fast lossless compression library
3f856f099SNavdeep Parhar 
4f856f099SNavdeep Parhar    Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
5f856f099SNavdeep Parhar    Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
6f856f099SNavdeep Parhar    Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
7f856f099SNavdeep Parhar 
8f856f099SNavdeep Parhar    Permission is hereby granted, free of charge, to any person obtaining a copy
9f856f099SNavdeep Parhar    of this software and associated documentation files (the "Software"), to deal
10f856f099SNavdeep Parhar    in the Software without restriction, including without limitation the rights
11f856f099SNavdeep Parhar    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12f856f099SNavdeep Parhar    copies of the Software, and to permit persons to whom the Software is
13f856f099SNavdeep Parhar    furnished to do so, subject to the following conditions:
14f856f099SNavdeep Parhar 
15f856f099SNavdeep Parhar    The above copyright notice and this permission notice shall be included in
16f856f099SNavdeep Parhar    all copies or substantial portions of the Software.
17f856f099SNavdeep Parhar 
18f856f099SNavdeep Parhar    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19f856f099SNavdeep Parhar    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20f856f099SNavdeep Parhar    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21f856f099SNavdeep Parhar    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22f856f099SNavdeep Parhar    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23f856f099SNavdeep Parhar    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24f856f099SNavdeep Parhar    THE SOFTWARE.
25f856f099SNavdeep Parhar    */
26f856f099SNavdeep Parhar #include <sys/cdefs.h>
27f856f099SNavdeep Parhar #include "osdep.h"
28f856f099SNavdeep Parhar #include "cudbg.h"
29f856f099SNavdeep Parhar #include "cudbg_lib_common.h"
30f856f099SNavdeep Parhar #include "fastlz.h"
31f856f099SNavdeep Parhar 
32f856f099SNavdeep Parhar static unsigned char sixpack_magic[8] = {137, '6', 'P', 'K', 13, 10, 26, 10};
33f856f099SNavdeep Parhar 
34f856f099SNavdeep Parhar #define CUDBG_BLOCK_SIZE      (63*1024)
35f856f099SNavdeep Parhar #define CUDBG_CHUNK_BUF_LEN   16
36f856f099SNavdeep Parhar #define CUDBG_MIN_COMPR_LEN   32	/*min data length for applying compression*/
37f856f099SNavdeep Parhar 
38f856f099SNavdeep Parhar /* for Adler-32 checksum algorithm, see RFC 1950 Section 8.2 */
39f856f099SNavdeep Parhar 
40f856f099SNavdeep Parhar #define ADLER32_BASE 65521
41f856f099SNavdeep Parhar 
update_adler32(unsigned long checksum,const void * buf,int len)42f856f099SNavdeep Parhar static inline unsigned long update_adler32(unsigned long checksum,
43f856f099SNavdeep Parhar 					   const void *buf, int len)
44f856f099SNavdeep Parhar {
45f856f099SNavdeep Parhar 	const unsigned char *ptr = (const unsigned char *)buf;
46f856f099SNavdeep Parhar 	unsigned long s1 = checksum & 0xffff;
47f856f099SNavdeep Parhar 	unsigned long s2 = (checksum >> 16) & 0xffff;
48f856f099SNavdeep Parhar 
49f856f099SNavdeep Parhar 	while (len > 0) {
50f856f099SNavdeep Parhar 		unsigned k = len < 5552 ? len : 5552;
51f856f099SNavdeep Parhar 		len -= k;
52f856f099SNavdeep Parhar 
53f856f099SNavdeep Parhar 		while (k >= 8) {
54f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
55f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
56f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
57f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
58f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
59f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
60f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
61f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
62f856f099SNavdeep Parhar 			k -= 8;
63f856f099SNavdeep Parhar 		}
64f856f099SNavdeep Parhar 
65f856f099SNavdeep Parhar 		while (k-- > 0) {
66f856f099SNavdeep Parhar 			s1 += *ptr++; s2 += s1;
67f856f099SNavdeep Parhar 		}
68f856f099SNavdeep Parhar 		s1 = s1 % ADLER32_BASE;
69f856f099SNavdeep Parhar 		s2 = s2 % ADLER32_BASE;
70f856f099SNavdeep Parhar 	}
71f856f099SNavdeep Parhar 	return (s2 << 16) + s1;
72f856f099SNavdeep Parhar }
73f856f099SNavdeep Parhar 
write_magic(struct cudbg_buffer * _out_buff)74f856f099SNavdeep Parhar int write_magic(struct cudbg_buffer *_out_buff)
75f856f099SNavdeep Parhar {
76f856f099SNavdeep Parhar 	int rc;
77f856f099SNavdeep Parhar 
78f856f099SNavdeep Parhar 	rc = write_to_buf(_out_buff->data, _out_buff->size, &_out_buff->offset,
79f856f099SNavdeep Parhar 			  sixpack_magic, 8);
80f856f099SNavdeep Parhar 
81f856f099SNavdeep Parhar 	return rc;
82f856f099SNavdeep Parhar }
83f856f099SNavdeep Parhar 
write_to_buf(void * out_buf,u32 out_buf_size,u32 * offset,void * in_buf,u32 in_buf_size)84f856f099SNavdeep Parhar int write_to_buf(void *out_buf, u32 out_buf_size, u32 *offset, void *in_buf,
85f856f099SNavdeep Parhar 		 u32 in_buf_size)
86f856f099SNavdeep Parhar {
87f856f099SNavdeep Parhar 	int rc = 0;
88f856f099SNavdeep Parhar 
89f856f099SNavdeep Parhar 	if (*offset >= out_buf_size) {
90f856f099SNavdeep Parhar 		rc = CUDBG_STATUS_OUTBUFF_OVERFLOW;
91f856f099SNavdeep Parhar 		goto err;
92f856f099SNavdeep Parhar 	}
93f856f099SNavdeep Parhar 
94f856f099SNavdeep Parhar 	memcpy((char *)out_buf + *offset, in_buf, in_buf_size);
95f856f099SNavdeep Parhar 	*offset = *offset + in_buf_size;
96f856f099SNavdeep Parhar 
97f856f099SNavdeep Parhar err:
98f856f099SNavdeep Parhar 	return rc;
99f856f099SNavdeep Parhar }
100f856f099SNavdeep Parhar 
read_from_buf(void * in_buf,u32 in_buf_size,u32 * offset,void * out_buf,u32 out_buf_size)101f856f099SNavdeep Parhar int read_from_buf(void *in_buf, u32 in_buf_size, u32 *offset, void *out_buf,
102f856f099SNavdeep Parhar 		  u32 out_buf_size)
103f856f099SNavdeep Parhar {
104f856f099SNavdeep Parhar 	if (in_buf_size - *offset < out_buf_size)
105f856f099SNavdeep Parhar 		return 0;
106f856f099SNavdeep Parhar 
107f856f099SNavdeep Parhar 	memcpy((char *)out_buf, (char *)in_buf + *offset, out_buf_size);
108f856f099SNavdeep Parhar 	*offset =  *offset + out_buf_size;
109f856f099SNavdeep Parhar 	return out_buf_size;
110f856f099SNavdeep Parhar }
111f856f099SNavdeep Parhar 
write_chunk_header(struct cudbg_buffer * _outbuf,int id,int options,unsigned long size,unsigned long checksum,unsigned long extra)112f856f099SNavdeep Parhar int write_chunk_header(struct cudbg_buffer *_outbuf, int id, int options,
113f856f099SNavdeep Parhar 		       unsigned long size, unsigned long checksum,
114f856f099SNavdeep Parhar 		       unsigned long extra)
115f856f099SNavdeep Parhar {
116f856f099SNavdeep Parhar 	unsigned char buffer[CUDBG_CHUNK_BUF_LEN];
117f856f099SNavdeep Parhar 	int rc = 0;
118f856f099SNavdeep Parhar 
119f856f099SNavdeep Parhar 	buffer[0] = id & 255;
120f856f099SNavdeep Parhar 	buffer[1] = (unsigned char)(id >> 8);
121f856f099SNavdeep Parhar 	buffer[2] = options & 255;
122f856f099SNavdeep Parhar 	buffer[3] = (unsigned char)(options >> 8);
123f856f099SNavdeep Parhar 	buffer[4] = size & 255;
124f856f099SNavdeep Parhar 	buffer[5] = (size >> 8) & 255;
125f856f099SNavdeep Parhar 	buffer[6] = (size >> 16) & 255;
126f856f099SNavdeep Parhar 	buffer[7] = (size >> 24) & 255;
127f856f099SNavdeep Parhar 	buffer[8] = checksum & 255;
128f856f099SNavdeep Parhar 	buffer[9] = (checksum >> 8) & 255;
129f856f099SNavdeep Parhar 	buffer[10] = (checksum >> 16) & 255;
130f856f099SNavdeep Parhar 	buffer[11] = (checksum >> 24) & 255;
131f856f099SNavdeep Parhar 	buffer[12] = extra & 255;
132f856f099SNavdeep Parhar 	buffer[13] = (extra >> 8) & 255;
133f856f099SNavdeep Parhar 	buffer[14] = (extra >> 16) & 255;
134f856f099SNavdeep Parhar 	buffer[15] = (extra >> 24) & 255;
135f856f099SNavdeep Parhar 
136f856f099SNavdeep Parhar 	rc = write_to_buf(_outbuf->data, _outbuf->size, &_outbuf->offset,
137f856f099SNavdeep Parhar 			  buffer, 16);
138f856f099SNavdeep Parhar 
139f856f099SNavdeep Parhar 	return rc;
140f856f099SNavdeep Parhar }
141f856f099SNavdeep Parhar 
write_compression_hdr(struct cudbg_buffer * pin_buff,struct cudbg_buffer * pout_buff)142f856f099SNavdeep Parhar int write_compression_hdr(struct cudbg_buffer *pin_buff,
143f856f099SNavdeep Parhar 			  struct cudbg_buffer *pout_buff)
144f856f099SNavdeep Parhar {
145f856f099SNavdeep Parhar 	struct cudbg_buffer tmp_buffer;
146f856f099SNavdeep Parhar 	unsigned long fsize = pin_buff->size;
147f856f099SNavdeep Parhar 	unsigned char *buffer;
148f856f099SNavdeep Parhar 	unsigned long checksum;
149f856f099SNavdeep Parhar 	int rc;
150f856f099SNavdeep Parhar 	char *shown_name = "abc";
151f856f099SNavdeep Parhar 
152f856f099SNavdeep Parhar 	/* Always release inner scratch buffer, before releasing outer. */
153f856f099SNavdeep Parhar 	rc = get_scratch_buff(pout_buff, 10, &tmp_buffer);
154f856f099SNavdeep Parhar 
155f856f099SNavdeep Parhar 	if (rc)
156f856f099SNavdeep Parhar 		goto err;
157f856f099SNavdeep Parhar 
158f856f099SNavdeep Parhar 	buffer = (unsigned char *)tmp_buffer.data;
159f856f099SNavdeep Parhar 
160f856f099SNavdeep Parhar 	rc = write_magic(pout_buff);
161f856f099SNavdeep Parhar 
162f856f099SNavdeep Parhar 	if (rc)
163f856f099SNavdeep Parhar 		goto err1;
164f856f099SNavdeep Parhar 
165f856f099SNavdeep Parhar 	/* chunk for File Entry */
166f856f099SNavdeep Parhar 	buffer[0] = fsize & 255;
167f856f099SNavdeep Parhar 	buffer[1] = (fsize >> 8) & 255;
168f856f099SNavdeep Parhar 	buffer[2] = (fsize >> 16) & 255;
169f856f099SNavdeep Parhar 	buffer[3] = (fsize >> 24) & 255;
170f856f099SNavdeep Parhar 	buffer[4] = 0;
171f856f099SNavdeep Parhar 	buffer[5] = 0;
172f856f099SNavdeep Parhar 	buffer[6] = 0;
173f856f099SNavdeep Parhar 	buffer[7] = 0;
174f856f099SNavdeep Parhar 	buffer[8] = (strlen(shown_name)+1) & 255;
175f856f099SNavdeep Parhar 	buffer[9] = (unsigned char)((strlen(shown_name)+1) >> 8);
176f856f099SNavdeep Parhar 	checksum = 1L;
177f856f099SNavdeep Parhar 	checksum = update_adler32(checksum, buffer, 10);
178f856f099SNavdeep Parhar 	checksum = update_adler32(checksum, shown_name,
179f856f099SNavdeep Parhar 				  (int)strlen(shown_name)+1);
180f856f099SNavdeep Parhar 
181f856f099SNavdeep Parhar 	rc = write_chunk_header(pout_buff, 1, 0,
182f856f099SNavdeep Parhar 				10+(unsigned long)strlen(shown_name)+1,
183f856f099SNavdeep Parhar 				checksum, 0);
184f856f099SNavdeep Parhar 
185f856f099SNavdeep Parhar 	if (rc)
186f856f099SNavdeep Parhar 		goto err1;
187f856f099SNavdeep Parhar 
188f856f099SNavdeep Parhar 	rc = write_to_buf(pout_buff->data, pout_buff->size,
189f856f099SNavdeep Parhar 			  &(pout_buff->offset), buffer, 10);
190f856f099SNavdeep Parhar 
191f856f099SNavdeep Parhar 	if (rc)
192f856f099SNavdeep Parhar 		goto err1;
193f856f099SNavdeep Parhar 
194f856f099SNavdeep Parhar 	rc = write_to_buf(pout_buff->data, pout_buff->size,
195f856f099SNavdeep Parhar 			   &(pout_buff->offset), shown_name,
196f856f099SNavdeep Parhar 			   (u32)strlen(shown_name)+1);
197f856f099SNavdeep Parhar 
198f856f099SNavdeep Parhar 	if (rc)
199f856f099SNavdeep Parhar 		goto err1;
200f856f099SNavdeep Parhar 
201f856f099SNavdeep Parhar err1:
202f856f099SNavdeep Parhar 	release_scratch_buff(&tmp_buffer, pout_buff);
203f856f099SNavdeep Parhar err:
204f856f099SNavdeep Parhar 	return rc;
205f856f099SNavdeep Parhar }
206f856f099SNavdeep Parhar 
compress_buff(struct cudbg_buffer * pin_buff,struct cudbg_buffer * pout_buff)207f856f099SNavdeep Parhar int compress_buff(struct cudbg_buffer *pin_buff, struct cudbg_buffer *pout_buff)
208f856f099SNavdeep Parhar {
209f856f099SNavdeep Parhar 	struct cudbg_buffer tmp_buffer;
210f856f099SNavdeep Parhar 	struct cudbg_hdr *cudbg_hdr;
211f856f099SNavdeep Parhar 	unsigned long checksum;
212f856f099SNavdeep Parhar 	unsigned char *result;
213f856f099SNavdeep Parhar 	unsigned int bytes_read;
214f856f099SNavdeep Parhar 	int chunk_size, level = 2, rc = 0;
215f856f099SNavdeep Parhar 	int compress_method = 1;
216f856f099SNavdeep Parhar 
217f856f099SNavdeep Parhar 	bytes_read = pin_buff->size;
218f856f099SNavdeep Parhar 	rc = get_scratch_buff(pout_buff, CUDBG_BLOCK_SIZE, &tmp_buffer);
219f856f099SNavdeep Parhar 
220f856f099SNavdeep Parhar 	if (rc)
221f856f099SNavdeep Parhar 		goto err;
222f856f099SNavdeep Parhar 
223f856f099SNavdeep Parhar 	result = (unsigned char *)tmp_buffer.data;
224f856f099SNavdeep Parhar 
225f856f099SNavdeep Parhar 	if (bytes_read < 32)
226f856f099SNavdeep Parhar 		compress_method = 0;
227f856f099SNavdeep Parhar 
228f856f099SNavdeep Parhar 	cudbg_hdr = (struct cudbg_hdr *)  pout_buff->data;
229f856f099SNavdeep Parhar 
230f856f099SNavdeep Parhar 	switch (compress_method) {
231f856f099SNavdeep Parhar 	case 1:
232f856f099SNavdeep Parhar 		chunk_size = fastlz_compress_level(level, pin_buff->data,
233f856f099SNavdeep Parhar 						   bytes_read, result);
234f856f099SNavdeep Parhar 
235f856f099SNavdeep Parhar 		checksum = update_adler32(1L, result, chunk_size);
236f856f099SNavdeep Parhar 
237f856f099SNavdeep Parhar 		if ((chunk_size > 62000) && (cudbg_hdr->reserved[7] < (u32)
238f856f099SNavdeep Parhar 		    chunk_size))   /* 64512 */
239f856f099SNavdeep Parhar 			cudbg_hdr->reserved[7] = (u32) chunk_size;
240f856f099SNavdeep Parhar 
241f856f099SNavdeep Parhar 		rc = write_chunk_header(pout_buff, 17, 1, chunk_size, checksum,
242f856f099SNavdeep Parhar 					bytes_read);
243f856f099SNavdeep Parhar 
244f856f099SNavdeep Parhar 		if (rc)
245f856f099SNavdeep Parhar 			goto err_put_buff;
246f856f099SNavdeep Parhar 
247f856f099SNavdeep Parhar 		rc = write_to_buf(pout_buff->data, pout_buff->size,
248f856f099SNavdeep Parhar 				  &pout_buff->offset, result, chunk_size);
249f856f099SNavdeep Parhar 
250f856f099SNavdeep Parhar 		if (rc)
251f856f099SNavdeep Parhar 			goto err_put_buff;
252f856f099SNavdeep Parhar 
253f856f099SNavdeep Parhar 		break;
254f856f099SNavdeep Parhar 
255f856f099SNavdeep Parhar 		/* uncompressed, also fallback method */
256f856f099SNavdeep Parhar 	case 0:
257f856f099SNavdeep Parhar 	default:
258f856f099SNavdeep Parhar 		checksum = update_adler32(1L, pin_buff->data, bytes_read);
259f856f099SNavdeep Parhar 
260f856f099SNavdeep Parhar 		rc = write_chunk_header(pout_buff, 17, 0, bytes_read, checksum,
261f856f099SNavdeep Parhar 					bytes_read);
262f856f099SNavdeep Parhar 
263f856f099SNavdeep Parhar 		if (rc)
264f856f099SNavdeep Parhar 			goto err_put_buff;
265f856f099SNavdeep Parhar 
266f856f099SNavdeep Parhar 		rc = write_to_buf(pout_buff->data, pout_buff->size,
267f856f099SNavdeep Parhar 				  &pout_buff->offset, pin_buff->data,
268f856f099SNavdeep Parhar 				  bytes_read);
269f856f099SNavdeep Parhar 		if (rc)
270f856f099SNavdeep Parhar 			goto err_put_buff;
271f856f099SNavdeep Parhar 
272f856f099SNavdeep Parhar 		break;
273f856f099SNavdeep Parhar 	}
274f856f099SNavdeep Parhar 
275f856f099SNavdeep Parhar err_put_buff:
276f856f099SNavdeep Parhar 	release_scratch_buff(&tmp_buffer, pout_buff);
277f856f099SNavdeep Parhar err:
278f856f099SNavdeep Parhar 	return rc;
279f856f099SNavdeep Parhar }
280f856f099SNavdeep Parhar 
281f856f099SNavdeep Parhar /* return non-zero if magic sequence is detected */
282f856f099SNavdeep Parhar /* warning: reset the read pointer to the beginning of the file */
detect_magic(struct cudbg_buffer * _c_buff)283f856f099SNavdeep Parhar int detect_magic(struct cudbg_buffer *_c_buff)
284f856f099SNavdeep Parhar {
285f856f099SNavdeep Parhar 	unsigned char buffer[8];
286f856f099SNavdeep Parhar 	size_t bytes_read;
287f856f099SNavdeep Parhar 	int c;
288f856f099SNavdeep Parhar 
289f856f099SNavdeep Parhar 	bytes_read = read_from_buf(_c_buff->data, _c_buff->size,
290f856f099SNavdeep Parhar 				   &_c_buff->offset, buffer, 8);
291f856f099SNavdeep Parhar 
292f856f099SNavdeep Parhar 	if (bytes_read < 8)
293f856f099SNavdeep Parhar 		return 0;
294f856f099SNavdeep Parhar 
295f856f099SNavdeep Parhar 	for (c = 0; c < 8; c++)
296f856f099SNavdeep Parhar 		if (buffer[c] != sixpack_magic[c])
297f856f099SNavdeep Parhar 			return 0;
298f856f099SNavdeep Parhar 
299f856f099SNavdeep Parhar 	return -1;
300f856f099SNavdeep Parhar }
301f856f099SNavdeep Parhar 
readU16(const unsigned char * ptr)302f856f099SNavdeep Parhar static inline unsigned long readU16(const unsigned char *ptr)
303f856f099SNavdeep Parhar {
304f856f099SNavdeep Parhar 	return ptr[0]+(ptr[1]<<8);
305f856f099SNavdeep Parhar }
306f856f099SNavdeep Parhar 
readU32(const unsigned char * ptr)307f856f099SNavdeep Parhar static inline unsigned long readU32(const unsigned char *ptr)
308f856f099SNavdeep Parhar {
309f856f099SNavdeep Parhar 	return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
310f856f099SNavdeep Parhar }
311f856f099SNavdeep Parhar 
read_chunk_header(struct cudbg_buffer * pc_buff,int * pid,int * poptions,unsigned long * psize,unsigned long * pchecksum,unsigned long * pextra)312f856f099SNavdeep Parhar int read_chunk_header(struct cudbg_buffer *pc_buff, int *pid, int *poptions,
313f856f099SNavdeep Parhar 		      unsigned long *psize, unsigned long *pchecksum,
314f856f099SNavdeep Parhar 		      unsigned long *pextra)
315f856f099SNavdeep Parhar {
316f856f099SNavdeep Parhar 	unsigned char buffer[CUDBG_CHUNK_BUF_LEN];
317f856f099SNavdeep Parhar 	int byte_r = read_from_buf(pc_buff->data, pc_buff->size,
318f856f099SNavdeep Parhar 				   &pc_buff->offset, buffer, 16);
319f856f099SNavdeep Parhar 	if (byte_r == 0)
320f856f099SNavdeep Parhar 		return 0;
321f856f099SNavdeep Parhar 
322f856f099SNavdeep Parhar 	*pid = readU16(buffer) & 0xffff;
323f856f099SNavdeep Parhar 	*poptions = readU16(buffer+2) & 0xffff;
324f856f099SNavdeep Parhar 	*psize = readU32(buffer+4) & 0xffffffff;
325f856f099SNavdeep Parhar 	*pchecksum = readU32(buffer+8) & 0xffffffff;
326f856f099SNavdeep Parhar 	*pextra = readU32(buffer+12) & 0xffffffff;
327f856f099SNavdeep Parhar 	return 0;
328f856f099SNavdeep Parhar }
329f856f099SNavdeep Parhar 
validate_buffer(struct cudbg_buffer * compressed_buffer)330f856f099SNavdeep Parhar int validate_buffer(struct cudbg_buffer *compressed_buffer)
331f856f099SNavdeep Parhar {
332f856f099SNavdeep Parhar 	if (!detect_magic(compressed_buffer))
333f856f099SNavdeep Parhar 		return CUDBG_STATUS_INVALID_BUFF;
334f856f099SNavdeep Parhar 
335f856f099SNavdeep Parhar 	return 0;
336f856f099SNavdeep Parhar }
337f856f099SNavdeep Parhar 
decompress_buffer(struct cudbg_buffer * pc_buff,struct cudbg_buffer * pd_buff)338f856f099SNavdeep Parhar int decompress_buffer(struct cudbg_buffer *pc_buff,
339f856f099SNavdeep Parhar 		      struct cudbg_buffer *pd_buff)
340f856f099SNavdeep Parhar {
341f856f099SNavdeep Parhar 	struct cudbg_buffer tmp_compressed_buffer;
342f856f099SNavdeep Parhar 	struct cudbg_buffer tmp_decompressed_buffer;
343f856f099SNavdeep Parhar 	unsigned char *compressed_buffer;
344f856f099SNavdeep Parhar 	unsigned char *decompressed_buffer;
345f856f099SNavdeep Parhar 	unsigned char buffer[CUDBG_MIN_COMPR_LEN];
346f856f099SNavdeep Parhar 	unsigned long chunk_size;
347f856f099SNavdeep Parhar 	unsigned long chunk_checksum;
348f856f099SNavdeep Parhar 	unsigned long chunk_extra;
349f856f099SNavdeep Parhar 	unsigned long checksum;
350f856f099SNavdeep Parhar 	unsigned long r;
351f856f099SNavdeep Parhar 	unsigned long remaining;
352f856f099SNavdeep Parhar 	unsigned long bytes_read;
353f856f099SNavdeep Parhar 	u32 decompressed_size = 0;
354f856f099SNavdeep Parhar 	int chunk_id, chunk_options, rc;
355f856f099SNavdeep Parhar 
356f856f099SNavdeep Parhar 	if (pd_buff->size < 2 * CUDBG_BLOCK_SIZE)
357f856f099SNavdeep Parhar 		return CUDBG_STATUS_SMALL_BUFF;
358f856f099SNavdeep Parhar 
359f856f099SNavdeep Parhar 	rc = get_scratch_buff(pd_buff, CUDBG_BLOCK_SIZE,
360f856f099SNavdeep Parhar 			      &tmp_compressed_buffer);
361f856f099SNavdeep Parhar 
362f856f099SNavdeep Parhar 	if (rc)
363f856f099SNavdeep Parhar 		goto err_cbuff;
364f856f099SNavdeep Parhar 
365f856f099SNavdeep Parhar 	rc = get_scratch_buff(pd_buff, CUDBG_BLOCK_SIZE,
366f856f099SNavdeep Parhar 			      &tmp_decompressed_buffer);
367f856f099SNavdeep Parhar 	if (rc)
368f856f099SNavdeep Parhar 		goto err_dcbuff;
369f856f099SNavdeep Parhar 
370f856f099SNavdeep Parhar 	compressed_buffer = (unsigned char *)tmp_compressed_buffer.data;
371f856f099SNavdeep Parhar 	decompressed_buffer = (unsigned char *)tmp_decompressed_buffer.data;
372f856f099SNavdeep Parhar 
373f856f099SNavdeep Parhar 	/* main loop */
374f856f099SNavdeep Parhar 
375f856f099SNavdeep Parhar 	for (;;) {
376f856f099SNavdeep Parhar 		if (pc_buff->offset > pc_buff->size)
377f856f099SNavdeep Parhar 			break;
378f856f099SNavdeep Parhar 
379f856f099SNavdeep Parhar 		rc =  read_chunk_header(pc_buff, &chunk_id, &chunk_options,
380f856f099SNavdeep Parhar 					&chunk_size, &chunk_checksum,
381f856f099SNavdeep Parhar 					&chunk_extra);
382f856f099SNavdeep Parhar 		if (rc != 0)
383f856f099SNavdeep Parhar 			break;
384f856f099SNavdeep Parhar 
385f856f099SNavdeep Parhar 		/* skip 8+16 */
386f856f099SNavdeep Parhar 		if ((chunk_id == 1) && (chunk_size > 10) &&
387f856f099SNavdeep Parhar 		    (chunk_size < CUDBG_BLOCK_SIZE)) {
388f856f099SNavdeep Parhar 
389f856f099SNavdeep Parhar 			bytes_read = read_from_buf(pc_buff->data, pc_buff->size,
390f856f099SNavdeep Parhar 						   &pc_buff->offset, buffer,
391f856f099SNavdeep Parhar 						   chunk_size);
392f856f099SNavdeep Parhar 
393f856f099SNavdeep Parhar 			if (bytes_read == 0)
394f856f099SNavdeep Parhar 				return 0;
395f856f099SNavdeep Parhar 
396f856f099SNavdeep Parhar 			checksum = update_adler32(1L, buffer, chunk_size);
397f856f099SNavdeep Parhar 			if (checksum != chunk_checksum)
398f856f099SNavdeep Parhar 				return CUDBG_STATUS_CHKSUM_MISSMATCH;
399f856f099SNavdeep Parhar 
400f856f099SNavdeep Parhar 			decompressed_size = (u32)readU32(buffer);
401f856f099SNavdeep Parhar 
402f856f099SNavdeep Parhar 			if (pd_buff->size < decompressed_size) {
403f856f099SNavdeep Parhar 
404f856f099SNavdeep Parhar 				pd_buff->size = 2 * CUDBG_BLOCK_SIZE +
405f856f099SNavdeep Parhar 						decompressed_size;
406f856f099SNavdeep Parhar 				pc_buff->offset -= chunk_size + 16;
407f856f099SNavdeep Parhar 				return CUDBG_STATUS_SMALL_BUFF;
408f856f099SNavdeep Parhar 			}
409f856f099SNavdeep Parhar 		}
410f856f099SNavdeep Parhar 
411f856f099SNavdeep Parhar 		if (chunk_size > CUDBG_BLOCK_SIZE) {
412f856f099SNavdeep Parhar 			/* Release old allocated memory */
413f856f099SNavdeep Parhar 			release_scratch_buff(&tmp_decompressed_buffer, pd_buff);
414f856f099SNavdeep Parhar 			release_scratch_buff(&tmp_compressed_buffer, pd_buff);
415f856f099SNavdeep Parhar 
416f856f099SNavdeep Parhar 			/* allocate new memory with chunk_size size */
417f856f099SNavdeep Parhar 			rc = get_scratch_buff(pd_buff, chunk_size,
418f856f099SNavdeep Parhar 					      &tmp_compressed_buffer);
419f856f099SNavdeep Parhar 			if (rc)
420f856f099SNavdeep Parhar 				goto err_cbuff;
421f856f099SNavdeep Parhar 
422f856f099SNavdeep Parhar 			rc = get_scratch_buff(pd_buff, chunk_size,
423f856f099SNavdeep Parhar 					      &tmp_decompressed_buffer);
424f856f099SNavdeep Parhar 			if (rc)
425f856f099SNavdeep Parhar 				goto err_dcbuff;
426f856f099SNavdeep Parhar 
427f856f099SNavdeep Parhar 			compressed_buffer = (unsigned char *)tmp_compressed_buffer.data;
428f856f099SNavdeep Parhar 			decompressed_buffer = (unsigned char *)tmp_decompressed_buffer.data;
429f856f099SNavdeep Parhar 		}
430f856f099SNavdeep Parhar 
431f856f099SNavdeep Parhar 		if ((chunk_id == 17) && decompressed_size) {
432f856f099SNavdeep Parhar 			/* uncompressed */
433f856f099SNavdeep Parhar 			switch (chunk_options) {
434f856f099SNavdeep Parhar 				/* stored, simply copy to output */
435f856f099SNavdeep Parhar 			case 0:
436f856f099SNavdeep Parhar 				remaining = chunk_size;
437f856f099SNavdeep Parhar 				checksum = 1L;
438f856f099SNavdeep Parhar 				for (;;) {
439*5bdf58e1SGordon Bergling 					/* Write a function for this */
440f856f099SNavdeep Parhar 					r = (CUDBG_BLOCK_SIZE < remaining) ?
441f856f099SNavdeep Parhar 					    CUDBG_BLOCK_SIZE : remaining;
442f856f099SNavdeep Parhar 					bytes_read =
443f856f099SNavdeep Parhar 					read_from_buf(pc_buff->data,
444f856f099SNavdeep Parhar 						      pc_buff->size,
445f856f099SNavdeep Parhar 						      &pc_buff->offset, buffer,
446f856f099SNavdeep Parhar 						      r);
447f856f099SNavdeep Parhar 
448f856f099SNavdeep Parhar 					if (bytes_read == 0)
449f856f099SNavdeep Parhar 						return 0;
450f856f099SNavdeep Parhar 
451f856f099SNavdeep Parhar 					write_to_buf(pd_buff->data,
452f856f099SNavdeep Parhar 						     pd_buff->size,
453f856f099SNavdeep Parhar 						     &pd_buff->offset, buffer,
454f856f099SNavdeep Parhar 						     bytes_read);
455f856f099SNavdeep Parhar 					checksum = update_adler32(checksum,
456f856f099SNavdeep Parhar 								  buffer,
457f856f099SNavdeep Parhar 								  bytes_read);
458f856f099SNavdeep Parhar 					remaining -= bytes_read;
459f856f099SNavdeep Parhar 
460f856f099SNavdeep Parhar 					/* verify everything is written
461f856f099SNavdeep Parhar 					 * correctly */
462f856f099SNavdeep Parhar 					if (checksum != chunk_checksum)
463f856f099SNavdeep Parhar 						return
464f856f099SNavdeep Parhar 						CUDBG_STATUS_CHKSUM_MISSMATCH;
465f856f099SNavdeep Parhar 				}
466f856f099SNavdeep Parhar 
467f856f099SNavdeep Parhar 				break;
468f856f099SNavdeep Parhar 
469f856f099SNavdeep Parhar 				/* compressed using FastLZ */
470f856f099SNavdeep Parhar 			case 1:
471f856f099SNavdeep Parhar 				bytes_read = read_from_buf(pc_buff->data,
472f856f099SNavdeep Parhar 							   pc_buff->size,
473f856f099SNavdeep Parhar 							   &pc_buff->offset,
474f856f099SNavdeep Parhar 							   compressed_buffer,
475f856f099SNavdeep Parhar 							   chunk_size);
476f856f099SNavdeep Parhar 
477f856f099SNavdeep Parhar 				if (bytes_read == 0)
478f856f099SNavdeep Parhar 					return 0;
479f856f099SNavdeep Parhar 
480f856f099SNavdeep Parhar 				checksum = update_adler32(1L, compressed_buffer,
481f856f099SNavdeep Parhar 							  chunk_size);
482f856f099SNavdeep Parhar 
483f856f099SNavdeep Parhar 				/* verify that the chunk data is correct */
484f856f099SNavdeep Parhar 				if (checksum != chunk_checksum) {
485f856f099SNavdeep Parhar 					return CUDBG_STATUS_CHKSUM_MISSMATCH;
486f856f099SNavdeep Parhar 				} else {
487f856f099SNavdeep Parhar 					/* decompress and verify */
488f856f099SNavdeep Parhar 					remaining =
489f856f099SNavdeep Parhar 					fastlz_decompress(compressed_buffer,
490f856f099SNavdeep Parhar 							  chunk_size,
491f856f099SNavdeep Parhar 							  decompressed_buffer,
492f856f099SNavdeep Parhar 							  chunk_extra);
493f856f099SNavdeep Parhar 
494f856f099SNavdeep Parhar 					if (remaining != chunk_extra) {
495f856f099SNavdeep Parhar 						rc =
496f856f099SNavdeep Parhar 						CUDBG_STATUS_DECOMPRESS_FAIL;
497f856f099SNavdeep Parhar 						goto err;
498f856f099SNavdeep Parhar 					} else {
499f856f099SNavdeep Parhar 						write_to_buf(pd_buff->data,
500f856f099SNavdeep Parhar 							     pd_buff->size,
501f856f099SNavdeep Parhar 							     &pd_buff->offset,
502f856f099SNavdeep Parhar 							     decompressed_buffer,
503f856f099SNavdeep Parhar 							     chunk_extra);
504f856f099SNavdeep Parhar 					}
505f856f099SNavdeep Parhar 				}
506f856f099SNavdeep Parhar 				break;
507f856f099SNavdeep Parhar 
508f856f099SNavdeep Parhar 			default:
509f856f099SNavdeep Parhar 				break;
510f856f099SNavdeep Parhar 			}
511f856f099SNavdeep Parhar 
512f856f099SNavdeep Parhar 		}
513f856f099SNavdeep Parhar 
514f856f099SNavdeep Parhar 	}
515f856f099SNavdeep Parhar 
516f856f099SNavdeep Parhar err:
517f856f099SNavdeep Parhar 	release_scratch_buff(&tmp_decompressed_buffer, pd_buff);
518f856f099SNavdeep Parhar err_dcbuff:
519f856f099SNavdeep Parhar 	release_scratch_buff(&tmp_compressed_buffer, pd_buff);
520f856f099SNavdeep Parhar 
521f856f099SNavdeep Parhar err_cbuff:
522f856f099SNavdeep Parhar 	return rc;
523f856f099SNavdeep Parhar }
524f856f099SNavdeep Parhar 
525