1228753Smm/*-
2228753Smm * Copyright (c) 2003-2007 Tim Kientzle
3228753Smm * All rights reserved.
4228753Smm *
5228753Smm * Redistribution and use in source and binary forms, with or without
6228753Smm * modification, are permitted provided that the following conditions
7228753Smm * are met:
8228753Smm * 1. Redistributions of source code must retain the above copyright
9228753Smm *    notice, this list of conditions and the following disclaimer.
10228753Smm * 2. Redistributions in binary form must reproduce the above copyright
11228753Smm *    notice, this list of conditions and the following disclaimer in the
12228753Smm *    documentation and/or other materials provided with the distribution.
13228753Smm *
14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24228753Smm */
25228753Smm
26228753Smm#include "archive_platform.h"
27228763Smm__FBSDID("$FreeBSD$");
28228753Smm
29228753Smm#include <errno.h>
30228753Smm#include <stdlib.h>
31228753Smm#include <string.h>
32228753Smm
33228753Smm#include "archive.h"
34228753Smm
35228753Smm/*
36228753Smm * Glue to read an archive from a block of memory.
37228753Smm *
38228753Smm * This is mostly a huge help in building test harnesses;
39228753Smm * test programs can build archives in memory and read them
40228753Smm * back again without having to mess with files on disk.
41228753Smm */
42228753Smm
43228753Smmstruct read_memory_data {
44232153Smm	unsigned char	*start;
45232153Smm	unsigned char	*p;
46228753Smm	unsigned char	*end;
47228753Smm	ssize_t	 read_size;
48228753Smm};
49228753Smm
50228753Smmstatic int	memory_read_close(struct archive *, void *);
51228753Smmstatic int	memory_read_open(struct archive *, void *);
52232153Smmstatic int64_t	memory_read_seek(struct archive *, void *, int64_t offset, int whence);
53232153Smmstatic int64_t	memory_read_skip(struct archive *, void *, int64_t request);
54228753Smmstatic ssize_t	memory_read(struct archive *, void *, const void **buff);
55228753Smm
56228753Smmint
57228753Smmarchive_read_open_memory(struct archive *a, void *buff, size_t size)
58228753Smm{
59228753Smm	return archive_read_open_memory2(a, buff, size, size);
60228753Smm}
61228753Smm
62228753Smm/*
63228753Smm * Don't use _open_memory2() in production code; the archive_read_open_memory()
64228753Smm * version is the one you really want.  This is just here so that
65228753Smm * test harnesses can exercise block operations inside the library.
66228753Smm */
67228753Smmint
68228753Smmarchive_read_open_memory2(struct archive *a, void *buff,
69228753Smm    size_t size, size_t read_size)
70228753Smm{
71228753Smm	struct read_memory_data *mine;
72228753Smm
73228753Smm	mine = (struct read_memory_data *)malloc(sizeof(*mine));
74228753Smm	if (mine == NULL) {
75228753Smm		archive_set_error(a, ENOMEM, "No memory");
76228753Smm		return (ARCHIVE_FATAL);
77228753Smm	}
78228753Smm	memset(mine, 0, sizeof(*mine));
79232153Smm	mine->start = mine->p = (unsigned char *)buff;
80232153Smm	mine->end = mine->start + size;
81228753Smm	mine->read_size = read_size;
82232153Smm	archive_read_set_open_callback(a, memory_read_open);
83232153Smm	archive_read_set_read_callback(a, memory_read);
84232153Smm	archive_read_set_seek_callback(a, memory_read_seek);
85232153Smm	archive_read_set_skip_callback(a, memory_read_skip);
86232153Smm	archive_read_set_close_callback(a, memory_read_close);
87232153Smm	archive_read_set_callback_data(a, mine);
88232153Smm	return (archive_read_open1(a));
89228753Smm}
90228753Smm
91228753Smm/*
92228753Smm * There's nothing to open.
93228753Smm */
94228753Smmstatic int
95228753Smmmemory_read_open(struct archive *a, void *client_data)
96228753Smm{
97228753Smm	(void)a; /* UNUSED */
98228753Smm	(void)client_data; /* UNUSED */
99228753Smm	return (ARCHIVE_OK);
100228753Smm}
101228753Smm
102228753Smm/*
103228753Smm * This is scary simple:  Just advance a pointer.  Limiting
104228753Smm * to read_size is not technically necessary, but it exercises
105228753Smm * more of the internal logic when used with a small block size
106228753Smm * in a test harness.  Production use should not specify a block
107228753Smm * size; then this is much faster.
108228753Smm */
109228753Smmstatic ssize_t
110228753Smmmemory_read(struct archive *a, void *client_data, const void **buff)
111228753Smm{
112228753Smm	struct read_memory_data *mine = (struct read_memory_data *)client_data;
113228753Smm	ssize_t size;
114228753Smm
115228753Smm	(void)a; /* UNUSED */
116232153Smm	*buff = mine->p;
117232153Smm	size = mine->end - mine->p;
118228753Smm	if (size > mine->read_size)
119228753Smm		size = mine->read_size;
120232153Smm        mine->p += size;
121228753Smm	return (size);
122228753Smm}
123228753Smm
124228753Smm/*
125228753Smm * Advancing is just as simple.  Again, this is doing more than
126228753Smm * necessary in order to better exercise internal code when used
127228753Smm * as a test harness.
128228753Smm */
129232153Smmstatic int64_t
130232153Smmmemory_read_skip(struct archive *a, void *client_data, int64_t skip)
131228753Smm{
132228753Smm	struct read_memory_data *mine = (struct read_memory_data *)client_data;
133228753Smm
134228753Smm	(void)a; /* UNUSED */
135232153Smm	if ((int64_t)skip > (int64_t)(mine->end - mine->p))
136232153Smm		skip = mine->end - mine->p;
137228753Smm	/* Round down to block size. */
138228753Smm	skip /= mine->read_size;
139228753Smm	skip *= mine->read_size;
140232153Smm	mine->p += skip;
141228753Smm	return (skip);
142228753Smm}
143228753Smm
144228753Smm/*
145232153Smm * Seeking.
146232153Smm */
147232153Smmstatic int64_t
148232153Smmmemory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)
149232153Smm{
150232153Smm	struct read_memory_data *mine = (struct read_memory_data *)client_data;
151232153Smm
152232153Smm	(void)a; /* UNUSED */
153232153Smm	switch (whence) {
154232153Smm	case SEEK_SET:
155232153Smm		mine->p = mine->start + offset;
156232153Smm		break;
157232153Smm	case SEEK_CUR:
158232153Smm		mine->p += offset;
159232153Smm		break;
160232153Smm	case SEEK_END:
161232153Smm		mine->p = mine->end + offset;
162232153Smm		break;
163232153Smm	default:
164232153Smm		return ARCHIVE_FATAL;
165232153Smm	}
166232153Smm	if (mine->p < mine->start) {
167232153Smm		mine->p = mine->start;
168232153Smm		return ARCHIVE_FAILED;
169232153Smm	}
170232153Smm	if (mine->p > mine->end) {
171232153Smm		mine->p = mine->end;
172232153Smm		return ARCHIVE_FAILED;
173232153Smm	}
174232153Smm	return (mine->p - mine->start);
175232153Smm}
176232153Smm
177232153Smm/*
178228753Smm * Close is just cleaning up our one small bit of data.
179228753Smm */
180228753Smmstatic int
181228753Smmmemory_read_close(struct archive *a, void *client_data)
182228753Smm{
183228753Smm	struct read_memory_data *mine = (struct read_memory_data *)client_data;
184228753Smm	(void)a; /* UNUSED */
185228753Smm	free(mine);
186228753Smm	return (ARCHIVE_OK);
187228753Smm}
188