| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 1 | /*- | 
 | 2 |  * Copyright (c) 2003, 2004 David Young.  All rights reserved. | 
 | 3 |  * | 
 | 4 |  * Redistribution and use in source and binary forms, with or without | 
 | 5 |  * modification, are permitted provided that the following conditions | 
 | 6 |  * are met: | 
 | 7 |  * 1. Redistributions of source code must retain the above copyright | 
 | 8 |  *    notice, this list of conditions and the following disclaimer. | 
 | 9 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 | 10 |  *    notice, this list of conditions and the following disclaimer in the | 
 | 11 |  *    documentation and/or other materials provided with the distribution. | 
 | 12 |  * 3. The name of David Young may not be used to endorse or promote | 
 | 13 |  *    products derived from this software without specific prior | 
 | 14 |  *    written permission. | 
 | 15 |  * | 
 | 16 |  * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY | 
 | 17 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 
 | 18 |  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | 
 | 19 |  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DAVID | 
 | 20 |  * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 | 21 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | 
 | 22 |  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 | 23 |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
 | 24 |  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
 | 25 |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
 | 26 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | 
 | 27 |  * OF SUCH DAMAGE. | 
 | 28 |  */ | 
 | 29 |  | 
 | 30 | #ifdef HAVE_CONFIG_H | 
 | 31 | #include "config.h" | 
 | 32 | #endif | 
 | 33 |  | 
 | 34 | #include <stdlib.h> | 
 | 35 | #include <string.h> | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 36 | #include <netdissect-stdinc.h> | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 37 |  | 
 | 38 | #include "cpack.h" | 
 | 39 | #include "extract.h" | 
 | 40 |  | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 41 | const uint8_t * | 
 | 42 | cpack_next_boundary(const uint8_t *buf, const uint8_t *p, size_t alignment) | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 43 | { | 
 | 44 | 	size_t misalignment = (size_t)(p - buf) % alignment; | 
 | 45 |  | 
 | 46 | 	if (misalignment == 0) | 
 | 47 | 		return p; | 
 | 48 |  | 
 | 49 | 	return p + (alignment - misalignment); | 
 | 50 | } | 
 | 51 |  | 
 | 52 | /* Advance to the next wordsize boundary. Return NULL if fewer than | 
 | 53 |  * wordsize bytes remain in the buffer after the boundary.  Otherwise, | 
 | 54 |  * return a pointer to the boundary. | 
 | 55 |  */ | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 56 | const uint8_t * | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 57 | cpack_align_and_reserve(struct cpack_state *cs, size_t wordsize) | 
 | 58 | { | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 59 | 	const uint8_t *next; | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 60 |  | 
 | 61 | 	/* Ensure alignment. */ | 
 | 62 | 	next = cpack_next_boundary(cs->c_buf, cs->c_next, wordsize); | 
 | 63 |  | 
 | 64 | 	/* Too little space for wordsize bytes? */ | 
 | 65 | 	if (next - cs->c_buf + wordsize > cs->c_len) | 
 | 66 | 		return NULL; | 
 | 67 |  | 
 | 68 | 	return next; | 
 | 69 | } | 
 | 70 |  | 
| JP Abgrall | 53f17a9 | 2014-02-12 14:02:41 -0800 | [diff] [blame] | 71 | /* Advance by N bytes without returning them. */ | 
 | 72 | int | 
 | 73 | cpack_advance(struct cpack_state *cs, const size_t toskip) | 
 | 74 | { | 
 | 75 | 	/* No space left? */ | 
 | 76 | 	if (cs->c_next - cs->c_buf + toskip > cs->c_len) | 
 | 77 | 		return -1; | 
 | 78 | 	cs->c_next += toskip; | 
 | 79 | 	return 0; | 
 | 80 | } | 
 | 81 |  | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 82 | int | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 83 | cpack_init(struct cpack_state *cs, const uint8_t *buf, size_t buflen) | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 84 | { | 
 | 85 | 	memset(cs, 0, sizeof(*cs)); | 
 | 86 |  | 
 | 87 | 	cs->c_buf = buf; | 
 | 88 | 	cs->c_len = buflen; | 
 | 89 | 	cs->c_next = cs->c_buf; | 
 | 90 |  | 
 | 91 | 	return 0; | 
 | 92 | } | 
 | 93 |  | 
 | 94 | /* Unpack a 64-bit unsigned integer. */ | 
 | 95 | int | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 96 | cpack_uint64(struct cpack_state *cs, uint64_t *u) | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 97 | { | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 98 | 	const uint8_t *next; | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 99 |  | 
 | 100 | 	if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) | 
 | 101 | 		return -1; | 
 | 102 |  | 
 | 103 | 	*u = EXTRACT_LE_64BITS(next); | 
 | 104 |  | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 105 | 	/* Move pointer past the uint64_t. */ | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 106 | 	cs->c_next = next + sizeof(*u); | 
 | 107 | 	return 0; | 
 | 108 | } | 
 | 109 |  | 
 | 110 | /* Unpack a 32-bit unsigned integer. */ | 
 | 111 | int | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 112 | cpack_uint32(struct cpack_state *cs, uint32_t *u) | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 113 | { | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 114 | 	const uint8_t *next; | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 115 |  | 
 | 116 | 	if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) | 
 | 117 | 		return -1; | 
 | 118 |  | 
 | 119 | 	*u = EXTRACT_LE_32BITS(next); | 
 | 120 |  | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 121 | 	/* Move pointer past the uint32_t. */ | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 122 | 	cs->c_next = next + sizeof(*u); | 
 | 123 | 	return 0; | 
 | 124 | } | 
 | 125 |  | 
 | 126 | /* Unpack a 16-bit unsigned integer. */ | 
 | 127 | int | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 128 | cpack_uint16(struct cpack_state *cs, uint16_t *u) | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 129 | { | 
| Elliott Hughes | e2e3bd1 | 2017-05-15 10:59:29 -0700 | [diff] [blame] | 130 | 	const uint8_t *next; | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 131 |  | 
 | 132 | 	if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) | 
 | 133 | 		return -1; | 
 | 134 |  | 
 | 135 | 	*u = EXTRACT_LE_16BITS(next); | 
 | 136 |  | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 137 | 	/* Move pointer past the uint16_t. */ | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 138 | 	cs->c_next = next + sizeof(*u); | 
 | 139 | 	return 0; | 
 | 140 | } | 
 | 141 |  | 
 | 142 | /* Unpack an 8-bit unsigned integer. */ | 
 | 143 | int | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 144 | cpack_uint8(struct cpack_state *cs, uint8_t *u) | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 145 | { | 
 | 146 | 	/* No space left? */ | 
 | 147 | 	if ((size_t)(cs->c_next - cs->c_buf) >= cs->c_len) | 
 | 148 | 		return -1; | 
 | 149 |  | 
 | 150 | 	*u = *cs->c_next; | 
 | 151 |  | 
| Elliott Hughes | 892a68b | 2015-10-19 14:43:53 -0700 | [diff] [blame] | 152 | 	/* Move pointer past the uint8_t. */ | 
| The Android Open Source Project | 2949f58 | 2009-03-03 19:30:46 -0800 | [diff] [blame] | 153 | 	cs->c_next++; | 
 | 154 | 	return 0; | 
 | 155 | } |