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 28 #include <errno.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include "archive.h" 33 34 struct write_memory_data { 35 size_t used; 36 size_t size; 37 size_t * client_size; 38 unsigned char * buff; 39 }; 40 41 static int memory_write_free(struct archive *, void *); 42 static int memory_write_open(struct archive *, void *); 43 static ssize_t memory_write(struct archive *, void *, const void *buff, size_t); 44 45 /* 46 * Client provides a pointer to a block of memory to receive 47 * the data. The 'size' param both tells us the size of the 48 * client buffer and lets us tell the client the final size. 49 */ 50 int 51 archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t *used) 52 { 53 struct write_memory_data *mine; 54 55 mine = calloc(1, sizeof(*mine)); 56 if (mine == NULL) { 57 archive_set_error(a, ENOMEM, "No memory"); 58 return (ARCHIVE_FATAL); 59 } 60 mine->buff = buff; 61 mine->size = buffSize; 62 mine->client_size = used; 63 return (archive_write_open2(a, mine, 64 memory_write_open, memory_write, NULL, memory_write_free)); 65 } 66 67 static int 68 memory_write_open(struct archive *a, void *client_data) 69 { 70 struct write_memory_data *mine; 71 mine = client_data; 72 mine->used = 0; 73 if (mine->client_size != NULL) 74 *mine->client_size = mine->used; 75 /* Disable padding if it hasn't been set explicitly. */ 76 if (-1 == archive_write_get_bytes_in_last_block(a)) 77 archive_write_set_bytes_in_last_block(a, 1); 78 return (ARCHIVE_OK); 79 } 80 81 /* 82 * Copy the data into the client buffer. 83 * Note that we update mine->client_size on every write. 84 * In particular, this means the client can follow exactly 85 * how much has been written into their buffer at any time. 86 */ 87 static ssize_t 88 memory_write(struct archive *a, void *client_data, const void *buff, size_t length) 89 { 90 struct write_memory_data *mine; 91 mine = client_data; 92 93 if (mine->used + length > mine->size) { 94 archive_set_error(a, ENOMEM, "Buffer exhausted"); 95 return (ARCHIVE_FATAL); 96 } 97 memcpy(mine->buff + mine->used, buff, length); 98 mine->used += length; 99 if (mine->client_size != NULL) 100 *mine->client_size = mine->used; 101 return (length); 102 } 103 104 static int 105 memory_write_free(struct archive *a, void *client_data) 106 { 107 struct write_memory_data *mine; 108 (void)a; /* UNUSED */ 109 mine = client_data; 110 if (mine == NULL) 111 return (ARCHIVE_OK); 112 free(mine); 113 return (ARCHIVE_OK); 114 } 115