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$"); 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_free(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 *)calloc(1, sizeof(*mine)); 57 if (mine == NULL) { 58 archive_set_error(a, ENOMEM, "No memory"); 59 return (ARCHIVE_FATAL); 60 } 61 mine->buff = buff; 62 mine->size = buffSize; 63 mine->client_size = used; 64 return (archive_write_open2(a, mine, 65 memory_write_open, memory_write, NULL, memory_write_free)); 66 } 67 68 static int 69 memory_write_open(struct archive *a, void *client_data) 70 { 71 struct write_memory_data *mine; 72 mine = client_data; 73 mine->used = 0; 74 if (mine->client_size != NULL) 75 *mine->client_size = mine->used; 76 /* Disable padding if it hasn't been set explicitly. */ 77 if (-1 == archive_write_get_bytes_in_last_block(a)) 78 archive_write_set_bytes_in_last_block(a, 1); 79 return (ARCHIVE_OK); 80 } 81 82 /* 83 * Copy the data into the client buffer. 84 * Note that we update mine->client_size on every write. 85 * In particular, this means the client can follow exactly 86 * how much has been written into their buffer at any time. 87 */ 88 static ssize_t 89 memory_write(struct archive *a, void *client_data, const void *buff, size_t length) 90 { 91 struct write_memory_data *mine; 92 mine = client_data; 93 94 if (mine->used + length > mine->size) { 95 archive_set_error(a, ENOMEM, "Buffer exhausted"); 96 return (ARCHIVE_FATAL); 97 } 98 memcpy(mine->buff + mine->used, buff, length); 99 mine->used += length; 100 if (mine->client_size != NULL) 101 *mine->client_size = mine->used; 102 return (length); 103 } 104 105 static int 106 memory_write_free(struct archive *a, void *client_data) 107 { 108 struct write_memory_data *mine; 109 (void)a; /* UNUSED */ 110 mine = client_data; 111 if (mine == NULL) 112 return (ARCHIVE_OK); 113 free(mine); 114 return (ARCHIVE_OK); 115 } 116