diff options
Diffstat (limited to 'src/drivers/vpd/vpd_decode.c')
-rw-r--r-- | src/drivers/vpd/vpd_decode.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/drivers/vpd/vpd_decode.c b/src/drivers/vpd/vpd_decode.c new file mode 100644 index 0000000000..0eab704ca8 --- /dev/null +++ b/src/drivers/vpd/vpd_decode.c @@ -0,0 +1,92 @@ +/* + * Copyright 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * This is a copy from upstream: + * https://chromium.googlesource.com/chromiumos/platform/vpd/+/master/lib/vpd_decode.c + */ +#include "vpd_decode.h" + +int vpd_decode_len( + const u32 max_len, const u8 *in, u32 *length, u32 *decoded_len) +{ + u8 more; + int i = 0; + + if (!length || !decoded_len) + return VPD_DECODE_FAIL; + + *length = 0; + do { + if (i >= max_len) + return VPD_DECODE_FAIL; + + more = in[i] & 0x80; + *length <<= 7; + *length |= in[i] & 0x7f; + ++i; + } while (more); + + *decoded_len = i; + return VPD_DECODE_OK; +} + +int vpd_decode_string( + const u32 max_len, const u8 *input_buf, u32 *consumed, + vpd_decode_callback callback, void *callback_arg) +{ + int type; + int res; + u32 key_len; + u32 value_len; + u32 decoded_len; + const u8 *key; + const u8 *value; + + /* type */ + if (*consumed >= max_len) + return VPD_DECODE_FAIL; + + type = input_buf[*consumed]; + + switch (type) { + case VPD_TYPE_INFO: + case VPD_TYPE_STRING: + (*consumed)++; + + /* key */ + res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], + &key_len, &decoded_len); + /* key name cannot be empty, and must be followed by value. */ + if (res != VPD_DECODE_OK || key_len < 1 || + *consumed + decoded_len + key_len >= max_len) + return VPD_DECODE_FAIL; + + *consumed += decoded_len; + key = &input_buf[*consumed]; + *consumed += key_len; + + /* value */ + res = vpd_decode_len(max_len - *consumed, &input_buf[*consumed], + &value_len, &decoded_len); + /* value can be empty (value_len = 0). */ + if (res != VPD_DECODE_OK || + *consumed + decoded_len + value_len > max_len) + return VPD_DECODE_FAIL; + + *consumed += decoded_len; + value = &input_buf[*consumed]; + *consumed += value_len; + + if (type == VPD_TYPE_STRING) + return callback(key, key_len, value, value_len, + callback_arg); + break; + + default: + return VPD_DECODE_FAIL; + } + + return VPD_DECODE_OK; +} |