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" 27229592Smm__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 { 44228753Smm unsigned char *buffer; 45228753Smm unsigned char *end; 46228753Smm ssize_t read_size; 47228753Smm}; 48228753Smm 49228753Smmstatic int memory_read_close(struct archive *, void *); 50228753Smmstatic int memory_read_open(struct archive *, void *); 51228753Smm#if ARCHIVE_API_VERSION < 2 52228753Smmstatic ssize_t memory_read_skip(struct archive *, void *, size_t request); 53228753Smm#else 54228753Smmstatic off_t memory_read_skip(struct archive *, void *, off_t request); 55228753Smm#endif 56228753Smmstatic ssize_t memory_read(struct archive *, void *, const void **buff); 57228753Smm 58228753Smmint 59228753Smmarchive_read_open_memory(struct archive *a, void *buff, size_t size) 60228753Smm{ 61228753Smm return archive_read_open_memory2(a, buff, size, size); 62228753Smm} 63228753Smm 64228753Smm/* 65228753Smm * Don't use _open_memory2() in production code; the archive_read_open_memory() 66228753Smm * version is the one you really want. This is just here so that 67228753Smm * test harnesses can exercise block operations inside the library. 68228753Smm */ 69228753Smmint 70228753Smmarchive_read_open_memory2(struct archive *a, void *buff, 71228753Smm size_t size, size_t read_size) 72228753Smm{ 73228753Smm struct read_memory_data *mine; 74228753Smm 75228753Smm mine = (struct read_memory_data *)malloc(sizeof(*mine)); 76228753Smm if (mine == NULL) { 77228753Smm archive_set_error(a, ENOMEM, "No memory"); 78228753Smm return (ARCHIVE_FATAL); 79228753Smm } 80228753Smm memset(mine, 0, sizeof(*mine)); 81228753Smm mine->buffer = (unsigned char *)buff; 82228753Smm mine->end = mine->buffer + size; 83228753Smm mine->read_size = read_size; 84228753Smm return (archive_read_open2(a, mine, memory_read_open, 85228753Smm memory_read, memory_read_skip, memory_read_close)); 86228753Smm} 87228753Smm 88228753Smm/* 89228753Smm * There's nothing to open. 90228753Smm */ 91228753Smmstatic int 92228753Smmmemory_read_open(struct archive *a, void *client_data) 93228753Smm{ 94228753Smm (void)a; /* UNUSED */ 95228753Smm (void)client_data; /* UNUSED */ 96228753Smm return (ARCHIVE_OK); 97228753Smm} 98228753Smm 99228753Smm/* 100228753Smm * This is scary simple: Just advance a pointer. Limiting 101228753Smm * to read_size is not technically necessary, but it exercises 102228753Smm * more of the internal logic when used with a small block size 103228753Smm * in a test harness. Production use should not specify a block 104228753Smm * size; then this is much faster. 105228753Smm */ 106228753Smmstatic ssize_t 107228753Smmmemory_read(struct archive *a, void *client_data, const void **buff) 108228753Smm{ 109228753Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 110228753Smm ssize_t size; 111228753Smm 112228753Smm (void)a; /* UNUSED */ 113228753Smm *buff = mine->buffer; 114228753Smm size = mine->end - mine->buffer; 115228753Smm if (size > mine->read_size) 116228753Smm size = mine->read_size; 117228753Smm mine->buffer += size; 118228753Smm return (size); 119228753Smm} 120228753Smm 121228753Smm/* 122228753Smm * Advancing is just as simple. Again, this is doing more than 123228753Smm * necessary in order to better exercise internal code when used 124228753Smm * as a test harness. 125228753Smm */ 126228753Smm#if ARCHIVE_API_VERSION < 2 127228753Smmstatic ssize_t 128228753Smmmemory_read_skip(struct archive *a, void *client_data, size_t skip) 129228753Smm#else 130228753Smmstatic off_t 131228753Smmmemory_read_skip(struct archive *a, void *client_data, off_t skip) 132228753Smm#endif 133228753Smm{ 134228753Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 135228753Smm 136228753Smm (void)a; /* UNUSED */ 137228753Smm if ((off_t)skip > (off_t)(mine->end - mine->buffer)) 138228753Smm skip = mine->end - mine->buffer; 139228753Smm /* Round down to block size. */ 140228753Smm skip /= mine->read_size; 141228753Smm skip *= mine->read_size; 142228753Smm mine->buffer += skip; 143228753Smm return (skip); 144228753Smm} 145228753Smm 146228753Smm/* 147228753Smm * Close is just cleaning up our one small bit of data. 148228753Smm */ 149228753Smmstatic int 150228753Smmmemory_read_close(struct archive *a, void *client_data) 151228753Smm{ 152228753Smm struct read_memory_data *mine = (struct read_memory_data *)client_data; 153228753Smm (void)a; /* UNUSED */ 154228753Smm free(mine); 155228753Smm return (ARCHIVE_OK); 156228753Smm} 157