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