/* * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary * source code may only be used and distributed under the Widevine Master * License Agreement. */ #include "odk_message.h" #include "odk_message_priv.h" #include #include #include /* * C11 defines static_assert in assert.h. If it is available, force a compile * time error if the abstract ODK_Message struct size does not match its * implementation. If static_assert is not available, the runtime assert in * InitMessage will catch the mismatch at the time a message is initialized. */ #ifdef static_assert static_assert( sizeof(ODK_Message) >= sizeof(ODK_Message_Impl), "sizeof(ODK_Message) is too small. You can increase " "SIZE_OF_ODK_MESSAGE_IMPL in odk_message.h to make it large enough."); #endif /* * Create a message structure that references a separate data buffer. An * initialized message is returned. The caller is responsible for ensuring that * the buffer remains allocated for the lifetime of the message. |buffer| may be * NULL. Serialization into a message with a NULL buffer will cause the message * size to be incremented, but no data will be written into the message * buffer. This is useful for calculating the amount of space a message will * need, prior to doing the actual serialization. The buffer contents are * unchanged by this function. */ ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) { assert(sizeof(ODK_Message) >= sizeof(ODK_Message_Impl)); ODK_Message message; ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message; message_impl->base = buffer; message_impl->capacity = capacity; message_impl->size = 0; message_impl->read_offset = 0; message_impl->status = MESSAGE_STATUS_OK; return message; } /* * Erase the contents of the message, set it to an empty state by setting the * message size and read offset to 0, effectively erasing the contents of the * message. The message data buffer pointer remains unchanged, i.e. the message * retains ownership of the buffer. The message buffer is zero-filled. The * message status is reset to MESSAGE_STATUS_OK. */ void ODK_Message_Clear(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); message_impl->read_offset = 0; message_impl->size = 0; message_impl->status = MESSAGE_STATUS_OK; if (message_impl->base) { memset(message_impl->base, 0, message_impl->capacity); } } /* * Reset read pointer to the beginning of the message and clear status * so that parsing of the message will restart at the beginning of the * message. The message status is reset to MESSAGE_STATUS_OK. */ void ODK_Message_Reset(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); message_impl->read_offset = 0; message_impl->status = MESSAGE_STATUS_OK; } /* * Return a pointer to the message data buffer, i.e. the message payload. * This is the buffer address that was passed into ODK_Message_Create. */ uint8_t* ODK_Message_GetBase(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); return message_impl->base; } /* * Get the maximum number of bytes the message can hold. */ size_t ODK_Message_GetCapacity(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); return message_impl->capacity; } /* * Get the number of bytes currently in the message */ size_t ODK_Message_GetSize(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); return message_impl->size; } /* * Get the offset of where the next bytes will be read from the message data * buffer. */ size_t ODK_Message_GetOffset(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); return message_impl->read_offset; } /* * Return the status of the message */ ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); return message_impl->status; } /* * Set the message status to a specific value */ void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); /* preserve the first error */ if (message_impl->status == MESSAGE_STATUS_OK) { message_impl->status = status; } } /* * Set the size of the message to a value. This may be needed after writing data * into the message data buffer. */ void ODK_Message_SetSize(ODK_Message* message, size_t size) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); assert(size <= message_impl->capacity); message_impl->size = size; } /* * Test if the integrity of a message. This means that the status must be * MESSAGE_STATUS_OK and that the base, read_offset, size and capacity of the * message are within the range of valid values. The message's base pointer * may be NULL if the buffer has not been assigned yet, that is not invalid. */ bool ODK_Message_IsValid(ODK_Message* message) { assert(message); ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; if (message_impl == NULL) { return false; } if (message_impl->status != MESSAGE_STATUS_OK) { return false; } if (message_impl->read_offset > message_impl->capacity || message_impl->size > message_impl->capacity || message_impl->read_offset > message_impl->size) { message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; return false; } return true; }