160b4ad09SPeter Avalos /*-
260b4ad09SPeter Avalos  * Copyright (c) 2003-2007 Tim Kientzle
360b4ad09SPeter Avalos  * All rights reserved.
460b4ad09SPeter Avalos  *
560b4ad09SPeter Avalos  * Redistribution and use in source and binary forms, with or without
660b4ad09SPeter Avalos  * modification, are permitted provided that the following conditions
760b4ad09SPeter Avalos  * are met:
860b4ad09SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
960b4ad09SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1060b4ad09SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1160b4ad09SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1260b4ad09SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1360b4ad09SPeter Avalos  *
1460b4ad09SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1560b4ad09SPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1660b4ad09SPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1760b4ad09SPeter Avalos  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1860b4ad09SPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1960b4ad09SPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2060b4ad09SPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2160b4ad09SPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2260b4ad09SPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2360b4ad09SPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2460b4ad09SPeter Avalos  */
2560b4ad09SPeter Avalos 
2660b4ad09SPeter Avalos #include "archive_platform.h"
2760b4ad09SPeter Avalos __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/06 15:51:59 kientzle Exp $");
2860b4ad09SPeter Avalos 
2960b4ad09SPeter Avalos #include <errno.h>
3060b4ad09SPeter Avalos #include <stdlib.h>
3160b4ad09SPeter Avalos #include <string.h>
3260b4ad09SPeter Avalos 
3360b4ad09SPeter Avalos #include "archive.h"
3460b4ad09SPeter Avalos 
3560b4ad09SPeter Avalos /*
3660b4ad09SPeter Avalos  * Glue to read an archive from a block of memory.
3760b4ad09SPeter Avalos  *
3860b4ad09SPeter Avalos  * This is mostly a huge help in building test harnesses;
3960b4ad09SPeter Avalos  * test programs can build archives in memory and read them
4060b4ad09SPeter Avalos  * back again without having to mess with files on disk.
4160b4ad09SPeter Avalos  */
4260b4ad09SPeter Avalos 
4360b4ad09SPeter Avalos struct read_memory_data {
446b384f39SPeter Avalos 	const unsigned char	*start;
456b384f39SPeter Avalos 	const unsigned char	*p;
466b384f39SPeter Avalos 	const unsigned char	*end;
4760b4ad09SPeter Avalos 	ssize_t	 read_size;
4860b4ad09SPeter Avalos };
4960b4ad09SPeter Avalos 
5060b4ad09SPeter Avalos static int	memory_read_close(struct archive *, void *);
5160b4ad09SPeter Avalos static int	memory_read_open(struct archive *, void *);
52c09f92d2SPeter Avalos static int64_t	memory_read_seek(struct archive *, void *, int64_t offset, int whence);
53c09f92d2SPeter Avalos static int64_t	memory_read_skip(struct archive *, void *, int64_t request);
5460b4ad09SPeter Avalos static ssize_t	memory_read(struct archive *, void *, const void **buff);
5560b4ad09SPeter Avalos 
5660b4ad09SPeter Avalos int
archive_read_open_memory(struct archive * a,const void * buff,size_t size)576b384f39SPeter Avalos archive_read_open_memory(struct archive *a, const void *buff, size_t size)
5860b4ad09SPeter Avalos {
5960b4ad09SPeter Avalos 	return archive_read_open_memory2(a, buff, size, size);
6060b4ad09SPeter Avalos }
6160b4ad09SPeter Avalos 
6260b4ad09SPeter Avalos /*
6360b4ad09SPeter Avalos  * Don't use _open_memory2() in production code; the archive_read_open_memory()
6460b4ad09SPeter Avalos  * version is the one you really want.  This is just here so that
6560b4ad09SPeter Avalos  * test harnesses can exercise block operations inside the library.
6660b4ad09SPeter Avalos  */
6760b4ad09SPeter Avalos int
archive_read_open_memory2(struct archive * a,const void * buff,size_t size,size_t read_size)686b384f39SPeter Avalos archive_read_open_memory2(struct archive *a, const void *buff,
6960b4ad09SPeter Avalos     size_t size, size_t read_size)
7060b4ad09SPeter Avalos {
7160b4ad09SPeter Avalos 	struct read_memory_data *mine;
7260b4ad09SPeter Avalos 
73e95abc47Szrj 	mine = (struct read_memory_data *)calloc(1, sizeof(*mine));
7460b4ad09SPeter Avalos 	if (mine == NULL) {
7560b4ad09SPeter Avalos 		archive_set_error(a, ENOMEM, "No memory");
7660b4ad09SPeter Avalos 		return (ARCHIVE_FATAL);
7760b4ad09SPeter Avalos 	}
786b384f39SPeter Avalos 	mine->start = mine->p = (const unsigned char *)buff;
79c09f92d2SPeter Avalos 	mine->end = mine->start + size;
8060b4ad09SPeter Avalos 	mine->read_size = read_size;
81c09f92d2SPeter Avalos 	archive_read_set_open_callback(a, memory_read_open);
82c09f92d2SPeter Avalos 	archive_read_set_read_callback(a, memory_read);
83c09f92d2SPeter Avalos 	archive_read_set_seek_callback(a, memory_read_seek);
84c09f92d2SPeter Avalos 	archive_read_set_skip_callback(a, memory_read_skip);
85c09f92d2SPeter Avalos 	archive_read_set_close_callback(a, memory_read_close);
86c09f92d2SPeter Avalos 	archive_read_set_callback_data(a, mine);
87c09f92d2SPeter Avalos 	return (archive_read_open1(a));
8860b4ad09SPeter Avalos }
8960b4ad09SPeter Avalos 
9060b4ad09SPeter Avalos /*
9160b4ad09SPeter Avalos  * There's nothing to open.
9260b4ad09SPeter Avalos  */
9360b4ad09SPeter Avalos static int
memory_read_open(struct archive * a,void * client_data)9460b4ad09SPeter Avalos memory_read_open(struct archive *a, void *client_data)
9560b4ad09SPeter Avalos {
9660b4ad09SPeter Avalos 	(void)a; /* UNUSED */
9760b4ad09SPeter Avalos 	(void)client_data; /* UNUSED */
9860b4ad09SPeter Avalos 	return (ARCHIVE_OK);
9960b4ad09SPeter Avalos }
10060b4ad09SPeter Avalos 
10160b4ad09SPeter Avalos /*
10260b4ad09SPeter Avalos  * This is scary simple:  Just advance a pointer.  Limiting
10360b4ad09SPeter Avalos  * to read_size is not technically necessary, but it exercises
10460b4ad09SPeter Avalos  * more of the internal logic when used with a small block size
10560b4ad09SPeter Avalos  * in a test harness.  Production use should not specify a block
10660b4ad09SPeter Avalos  * size; then this is much faster.
10760b4ad09SPeter Avalos  */
10860b4ad09SPeter Avalos static ssize_t
memory_read(struct archive * a,void * client_data,const void ** buff)10960b4ad09SPeter Avalos memory_read(struct archive *a, void *client_data, const void **buff)
11060b4ad09SPeter Avalos {
11160b4ad09SPeter Avalos 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
11260b4ad09SPeter Avalos 	ssize_t size;
11360b4ad09SPeter Avalos 
11460b4ad09SPeter Avalos 	(void)a; /* UNUSED */
115c09f92d2SPeter Avalos 	*buff = mine->p;
116c09f92d2SPeter Avalos 	size = mine->end - mine->p;
11760b4ad09SPeter Avalos 	if (size > mine->read_size)
11860b4ad09SPeter Avalos 		size = mine->read_size;
119c09f92d2SPeter Avalos         mine->p += size;
12060b4ad09SPeter Avalos 	return (size);
12160b4ad09SPeter Avalos }
12260b4ad09SPeter Avalos 
12360b4ad09SPeter Avalos /*
12460b4ad09SPeter Avalos  * Advancing is just as simple.  Again, this is doing more than
12560b4ad09SPeter Avalos  * necessary in order to better exercise internal code when used
12660b4ad09SPeter Avalos  * as a test harness.
12760b4ad09SPeter Avalos  */
128c09f92d2SPeter Avalos static int64_t
memory_read_skip(struct archive * a,void * client_data,int64_t skip)129c09f92d2SPeter Avalos memory_read_skip(struct archive *a, void *client_data, int64_t skip)
13060b4ad09SPeter Avalos {
13160b4ad09SPeter Avalos 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
13260b4ad09SPeter Avalos 
13360b4ad09SPeter Avalos 	(void)a; /* UNUSED */
134c09f92d2SPeter Avalos 	if ((int64_t)skip > (int64_t)(mine->end - mine->p))
135c09f92d2SPeter Avalos 		skip = mine->end - mine->p;
13660b4ad09SPeter Avalos 	/* Round down to block size. */
13760b4ad09SPeter Avalos 	skip /= mine->read_size;
13860b4ad09SPeter Avalos 	skip *= mine->read_size;
139c09f92d2SPeter Avalos 	mine->p += skip;
14060b4ad09SPeter Avalos 	return (skip);
14160b4ad09SPeter Avalos }
14260b4ad09SPeter Avalos 
14360b4ad09SPeter Avalos /*
144c09f92d2SPeter Avalos  * Seeking.
145c09f92d2SPeter Avalos  */
146c09f92d2SPeter Avalos static int64_t
memory_read_seek(struct archive * a,void * client_data,int64_t offset,int whence)147c09f92d2SPeter Avalos memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)
148c09f92d2SPeter Avalos {
149c09f92d2SPeter Avalos 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
150c09f92d2SPeter Avalos 
15159bf7050SPeter Avalos 	(void)a; /* UNUSED */
152c09f92d2SPeter Avalos 	switch (whence) {
153c09f92d2SPeter Avalos 	case SEEK_SET:
154c09f92d2SPeter Avalos 		mine->p = mine->start + offset;
155c09f92d2SPeter Avalos 		break;
156c09f92d2SPeter Avalos 	case SEEK_CUR:
157c09f92d2SPeter Avalos 		mine->p += offset;
158c09f92d2SPeter Avalos 		break;
159c09f92d2SPeter Avalos 	case SEEK_END:
160c09f92d2SPeter Avalos 		mine->p = mine->end + offset;
161c09f92d2SPeter Avalos 		break;
162c09f92d2SPeter Avalos 	default:
163c09f92d2SPeter Avalos 		return ARCHIVE_FATAL;
164c09f92d2SPeter Avalos 	}
165c09f92d2SPeter Avalos 	if (mine->p < mine->start) {
166c09f92d2SPeter Avalos 		mine->p = mine->start;
167c09f92d2SPeter Avalos 		return ARCHIVE_FAILED;
168c09f92d2SPeter Avalos 	}
169c09f92d2SPeter Avalos 	if (mine->p > mine->end) {
170c09f92d2SPeter Avalos 		mine->p = mine->end;
171c09f92d2SPeter Avalos 		return ARCHIVE_FAILED;
172c09f92d2SPeter Avalos 	}
173c09f92d2SPeter Avalos 	return (mine->p - mine->start);
174c09f92d2SPeter Avalos }
175c09f92d2SPeter Avalos 
176c09f92d2SPeter Avalos /*
17760b4ad09SPeter Avalos  * Close is just cleaning up our one small bit of data.
17860b4ad09SPeter Avalos  */
17960b4ad09SPeter Avalos static int
memory_read_close(struct archive * a,void * client_data)18060b4ad09SPeter Avalos memory_read_close(struct archive *a, void *client_data)
18160b4ad09SPeter Avalos {
18260b4ad09SPeter Avalos 	struct read_memory_data *mine = (struct read_memory_data *)client_data;
18360b4ad09SPeter Avalos 	(void)a; /* UNUSED */
18460b4ad09SPeter Avalos 	free(mine);
18560b4ad09SPeter Avalos 	return (ARCHIVE_OK);
18660b4ad09SPeter Avalos }
187