1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "archive_platform.h" 27 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_open_memory.c,v 1.3 2007/01/09 08:05:56 kientzle Exp $"); 28 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "archive.h" 34 35 struct write_memory_data { 36 size_t used; 37 size_t size; 38 size_t * client_size; 39 unsigned char * buff; 40 }; 41 42 static int memory_write_close(struct archive *, void *); 43 static int memory_write_open(struct archive *, void *); 44 static ssize_t memory_write(struct archive *, void *, const void *buff, size_t); 45 46 /* 47 * Client provides a pointer to a block of memory to receive 48 * the data. The 'size' param both tells us the size of the 49 * client buffer and lets us tell the client the final size. 50 */ 51 int 52 archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) 53 { 54 struct write_memory_data *mine; 55 56 mine = (struct write_memory_data *)malloc(sizeof(*mine)); 57 if (mine == NULL) { 58 archive_set_error(a, ENOMEM, "No memory"); 59 return (ARCHIVE_FATAL); 60 } 61 memset(mine, 0, sizeof(*mine)); 62 mine->buff = buff; 63 mine->size = buffSize; 64 mine->client_size = used; 65 return (archive_write_open(a, mine, 66 memory_write_open, memory_write, memory_write_close)); 67 } 68 69 static int 70 memory_write_open(struct archive *a, void *client_data) 71 { 72 struct write_memory_data *mine; 73 mine = client_data; 74 mine->used = 0; 75 if (mine->client_size != NULL) 76 *mine->client_size = mine->used; 77 /* Disable padding if it hasn't been set explicitly. */ 78 if (-1 == archive_write_get_bytes_in_last_block(a)) 79 archive_write_set_bytes_in_last_block(a, 1); 80 return (ARCHIVE_OK); 81 } 82 83 /* 84 * Copy the data into the client buffer. 85 * Note that we update mine->client_size on every write. 86 * In particular, this means the client can follow exactly 87 * how much has been written into their buffer at any time. 88 */ 89 static ssize_t 90 memory_write(struct archive *a, void *client_data, const void *buff, size_t length) 91 { 92 struct write_memory_data *mine; 93 mine = client_data; 94 95 if (mine->used + length > mine->size) { 96 archive_set_error(a, ENOMEM, "Buffer exhausted"); 97 return (ARCHIVE_FATAL); 98 } 99 memcpy(mine->buff + mine->used, buff, length); 100 mine->used += length; 101 if (mine->client_size != NULL) 102 *mine->client_size = mine->used; 103 return (length); 104 } 105 106 static int 107 memory_write_close(struct archive *a, void *client_data) 108 { 109 struct write_memory_data *mine; 110 (void)a; /* UNUSED */ 111 mine = client_data; 112 free(mine); 113 return (ARCHIVE_OK); 114 } 115