Files
oemcrypto/util/include/hls_attribute_list.h
2025-05-22 16:33:29 -07:00

212 lines
8.6 KiB
C++

// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef WVCDM_UTIL_HLS_ATTRIBUTE_LIST_H_
#define WVCDM_UTIL_HLS_ATTRIBUTE_LIST_H_
#include <inttypes.h>
#include <map>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "wv_class_utils.h"
namespace wvutil {
// An HLS Attribute List is a loosely defined HLS tag value
// type representing a dictionary of attribute name-value pairs.
// No attribute name may appear twice in a valid HLS Attribute
// List.
//
// When serialized, an HLS attribute list appears as a comma
// separated list of <name>=<value> pairs, without any line breaks,
// and whitespace only within quoted string attribute values.
//
// The HLS specification defines them as context sensitive-types,
// as the format of certain value types are ambiguous with other
// value types (ex. something that looks like a hex sequence could
// actually be an enum string). The exact value types of attributes
// depends on the HLS tag.
//
// This implementation is intended to be context free when parsing.
// Internally, value will be assigned a type based on their
// appearance to the most restrictive type; however, accessing as a
// particular type will be allowed so long as they match the format
// that type. The only exception to this is quoted strings, which
// are fully unambiguous with all other types.
//
// The standard HLS attribute list allows for UTF-8 encoded unicode
// characters; however, for Widevine's use case, we only allow
// basic ASCII.
//
// This class is based on RFC 8216 section 4.2.
class HlsAttributeList {
public:
enum ValueType {
kUnsetType = 0,
// HLS integers are a sequence of 1 to 20 base10 digits
// values, which must fit into an unsigned 64-bit integer.
// Note:
// All integers can appear as an enum string.
// All integers can appear as floats; however, precision
// restrictions may limit ability to parse accurately.
kIntegerType,
// HLS hex sequence are a sequence of 1 or more upper case
// hexadecimal digits, with the prefix "0x" or "0X".
// Note:
// All hex sequences can appear as an enum string.
// Certain hex sequences can appear as a resolution.
kHexSequenceType,
// HLS float and sign float are a sequence of base10 digits
// with a possible leading negative sign ('-') and at most one
// decimal point ('.').
// Note:
// All floats can appear as an enum string.
// Certain floats can appear are an integer.
kFloatType,
// For simplicity, signed and unsigned floats are internally
// treated as the same.
kSignedFloatType = kFloatType, // Aliasing
// HLS quoted strings are a sequence of printable characters
// (except a double quote), or space characters, contained within
// a pair of double quotes.
// Note: Quote string are unambiguous with all other types.
kQuotedStringType,
// HLS enum strings are a sequence of any printable characters
// (except quotes or commas) and do not contain whitespace.
// Note:
// Certain enum strings can appear as integers, floats, hex
// sequences or resolutions.
kEnumStringType,
// HLS resolutions are a pair of base10 integers (similar to
// integer types) separated by an 'x' character.
// Note:
// All resolutions can appear as enum strings
// Certain resolutions can appear as hex sequences.
kResolutionType,
};
static const char* ValueTypeToString(ValueType type);
// Checks if the provided |name| is valid HLS attribute name.
static bool IsValidName(const std::string& name);
// Checks if the provided |value| is a valid HLS enumerated
// string.
static bool IsValidEnumStringValue(const std::string& value);
// Checks if the provided |value| is an allowed content
// of a quote string (i.e., |value| is the portion that is
// to be contained within the double quotes).
static bool IsValidQuotedStringValue(const std::string& value);
// Validator for an HLS unsigned integer representation.
// Checks that the value representation |value_rep| conforms
// to HLS requirements for a serialized integer.
static bool IsValidIntegerRep(const std::string& value_rep);
// Parses the provided |integer_rep| as an HLS integer, assign
// the parsed integer to |value|.
static bool ParseInteger(const std::string& integer_rep, uint64_t* value);
HlsAttributeList() = default;
WVCDM_DEFAULT_COPY_AND_MOVE(HlsAttributeList);
// == Basic Accessors ==
bool IsEmpty() const { return members_.empty(); }
size_t Count() const { return members_.size(); }
void Clear() { members_.clear(); }
// == Value Getters ==
// Returns a list of attribute names.
std::vector<std::string> GetNames() const;
// Returns true if the provided attribute |name| is contained
// within list.
bool Contains(const std::string& name) const;
// Checks if the provided attribute |name| could be the
// specified |type|.
// Certain value types are ambiguous; so they may be marked
// internally as one type, but are still valid forms of a
// different type.
bool IsType(const std::string& name, ValueType type) const;
// Gets the attribute value for the provided attribute |name|,
// assigning the deserialized value to the output parameter(s).
//
// If a type is internally stored as a different type, but the format
// matches the requested type, it will be allowed.
//
// Returns true if the attribute value was successfully obtained;
// false otherwise (attribute does not exist, or the value could
// not be parsed as the specified type).
bool GetEnumString(const std::string& name, std::string* value) const;
bool GetQuotedString(const std::string& name, std::string* value) const;
bool GetHexSequence(const std::string& name, std::string* value) const;
bool GetHexSequence(const std::string& name,
std::vector<uint8_t>* value) const;
bool GetInteger(const std::string& name, uint64_t* value) const;
bool GetFloat(const std::string& name, double* value) const;
bool GetResolution(const std::string& name, uint64_t* width,
uint64_t* height) const;
// == Value Setters ==
// The value setters attempt to serializes the provided value
// into an HLS attribute value format of the type indicated
// by the method name. These methods will overwrite any existing
// attribute of the same name.
// Setting will be rejected if |name| is not a valid HLS attribute
// name, or if the provided |value| is valid (only applicable to
// certain types).
bool SetEnumString(const std::string& name, const std::string& value);
bool SetQuotedString(const std::string& name, const std::string& value);
// Note: This implementation will use lower "0x" prefix for
// hex sequences.
bool SetHexSequence(const std::string& name, const std::string& value);
bool SetHexSequence(const std::string& name,
const std::vector<uint8_t>& value);
bool SetInteger(const std::string& name, uint64_t value);
bool SetFloat(const std::string& name, double value);
bool SetResolution(const std::string& name, uint64_t width, uint64_t height);
// Removes the specified attribute. Returns true if the attribute
// was removed; false otherwise.
bool Remove(const std::string& name);
// == Parsing / Serialization ==
// Attempts to parse the provided HLS Attribute List.
// Always clears the existing contents, even if the attribute
// list cannot be parsed.
//
// Internally, values are not parsed, but checked to see which
// type they resemble. This does not restrict accessing them
// as different types.
//
// Returns true if successfully parsed; false otherwise.
bool Parse(const std::string& hls_attr_list_rep);
// Serializes the contents of the HLS attribute list into a
// valid HLS attribute list form.
std::string Serialize() const;
bool SerializeToStream(std::ostream* out) const;
// Internally, values are stored in their serialized form
// in case their value is ambiguous between two or more types.
// The assigned ValueType is intended to be a hint for improve
// access speeds.
using ValueInfo =
std::pair</* type hint */ ValueType, /* value rep */ std::string>;
private:
// Internal utility to obtain the value info.
// Silently returns null if the name does not exist.
const ValueInfo* GetInfo(const std::string& name) const;
// Values in |members_| will always be validated before assigned.
std::map</* name */ std::string, ValueInfo> members_;
}; // class HlsAttributeList
} // namespace wvutil
#endif // WVCDM_UTIL_HLS_ATTRIBUTE_LIST_H_