diff --git a/_studio/mfx_lib/decode/h264/src/mfx_h264_dec_decode.cpp b/_studio/mfx_lib/decode/h264/src/mfx_h264_dec_decode.cpp index f0580f12..36fab158 100644 --- a/_studio/mfx_lib/decode/h264/src/mfx_h264_dec_decode.cpp +++ b/_studio/mfx_lib/decode/h264/src/mfx_h264_dec_decode.cpp @@ -1209,6 +1209,8 @@ mfxStatus VideoDECODEH264::DecodeFrameCheck(mfxBitstream *bs, mfxFrameSurface1 * } #endif // MFX_ENABLE_PROTECT + // MFX_CHECK((bs->DataFlag & MFX_BITSTREAM_COMPLETE_FRAME), MFX_ERR_UNSUPPORTED); + try { bool force = false; @@ -1225,6 +1227,12 @@ mfxStatus VideoDECODEH264::DecodeFrameCheck(mfxBitstream *bs, mfxFrameSurface1 * src.SetExtBuffer(extbuf); } + extbuf = (bs) ? GetExtendedBuffer(bs->ExtParam, bs->NumExtParam, MFX_EXTBUFF_DECRYPT_CONFIG) : NULL; + if (extbuf) + { + src.SetEncryptedStream(extbuf); + } + m_pH264VideoDecoder->SetVideoCore(m_core); for (;;) diff --git a/_studio/mfx_lib/shared/include/mfx_common_decode_int.h b/_studio/mfx_lib/shared/include/mfx_common_decode_int.h index 5a27d85e..46d0b3d0 100644 --- a/_studio/mfx_lib/shared/include/mfx_common_decode_int.h +++ b/_studio/mfx_lib/shared/include/mfx_common_decode_int.h @@ -37,6 +37,7 @@ class MFXMediaDataAdapter : public UMC::MediaData void Save(mfxBitstream *pBitstream); void SetExtBuffer(mfxExtBuffer*); + void SetEncryptedStream(mfxExtBuffer*); }; mfxStatus ConvertUMCStatusToMfx(UMC::Status status); diff --git a/_studio/mfx_lib/shared/src/mfx_common_decode_int.cpp b/_studio/mfx_lib/shared/src/mfx_common_decode_int.cpp index aecbec1d..004b4a22 100644 --- a/_studio/mfx_lib/shared/src/mfx_common_decode_int.cpp +++ b/_studio/mfx_lib/shared/src/mfx_common_decode_int.cpp @@ -72,6 +72,27 @@ void MFXMediaDataAdapter::SetExtBuffer(mfxExtBuffer* extbuf) SetAuxInfo(extbuf, extbuf->BufferSz, extbuf->BufferId); } +void MFXMediaDataAdapter::SetEncryptedStream(mfxExtBuffer* extbuf) +{ + if (extbuf) + { + SetAuxInfo(extbuf, extbuf->BufferSz, extbuf->BufferId); + // set encrypted ranges + mfxExtDecryptConfig* decryptConfig = reinterpret_cast(extbuf); + UMC::Ranges encryptedRanges; + const mfxU8* start = (uint8_t *)GetDataPointer(); + const mfxU8* stream_end = start + GetDataSize(); + for (size_t i = 0; i < decryptConfig->num_subsamples; ++i) + { + start += decryptConfig->subsamples[i].clear_bytes; + const mfxU8* end = std::min(start + decryptConfig->subsamples[i].cypher_bytes, stream_end); + encryptedRanges.Add(start, end); + start = end; + } + SetEncryptedRanges(encryptedRanges); + } +} + mfxStatus ConvertUMCStatusToMfx(UMC::Status status) { switch((UMC::eUMC_VA_Status)status) diff --git a/_studio/shared/umc/codec/h264_dec/include/umc_h264_nal_spl.h b/_studio/shared/umc/codec/h264_dec/include/umc_h264_nal_spl.h index d65ddeaf..32860ef9 100644 --- a/_studio/shared/umc/codec/h264_dec/include/umc_h264_nal_spl.h +++ b/_studio/shared/umc/codec/h264_dec/include/umc_h264_nal_spl.h @@ -28,6 +28,7 @@ #include "umc_h264_dec_defs_dec.h" #include "umc_media_data_ex.h" #include "umc_h264_heap.h" +#include "mfxstructures.h" namespace UMC { @@ -85,6 +86,14 @@ class NalUnit : public MediaData int m_nal_unit_type; bool m_use_external_memory; + + void GetCurrentSubsamples(MediaData *pSource); + mfxExtDecryptConfig* DecryptConfig() { return m_decryptConfig; } + std::vector Subsamples() { return m_subsamples; } +private: + mfxExtDecryptConfig *m_decryptConfig = NULL; + std::vector m_subsamples; + }; class SwapperBase diff --git a/_studio/shared/umc/codec/h264_dec/include/umc_h264_slice_decoding.h b/_studio/shared/umc/codec/h264_dec/include/umc_h264_slice_decoding.h index 8b67f0e4..2ce146c8 100644 --- a/_studio/shared/umc/codec/h264_dec/include/umc_h264_slice_decoding.h +++ b/_studio/shared/umc/codec/h264_dec/include/umc_h264_slice_decoding.h @@ -101,6 +101,25 @@ class H264Slice : public HeapObject // Obtain first MB number int32_t GetFirstMBNumber(void) const {return m_iFirstMBFld;} int32_t GetStreamFirstMB(void) const {return m_iFirstMB;} + + const mfxExtDecryptConfig& GetDecryptConfig(void) {return m_decryptConfig;} + void SetDecryptConfig(mfxExtDecryptConfig* decryptConfig) { + if (decryptConfig) + { + m_decryptConfig.encryption_scheme = decryptConfig->encryption_scheme; + std::memcpy(m_decryptConfig.hw_key_id, decryptConfig->hw_key_id, 16); + std::memcpy(m_decryptConfig.iv, decryptConfig->iv, 16); + m_decryptConfig.session = decryptConfig->session; + } + else + { + memset(&m_decryptConfig, 0, sizeof(m_decryptConfig)); + } + + } + const std::vector& GetSubsamples() {return m_subsamples;} + void SetSubsamples(const std::vector& subsamples) {m_subsamples = subsamples;} + void SetFirstMBNumber(int32_t x) {m_iFirstMB = x;} // Obtain MB width int32_t GetMBWidth(void) const {return m_iMBWidth;} @@ -238,6 +257,9 @@ class H264Slice : public HeapObject MemoryAllocator *m_pMemoryAllocator; // (MemoryAllocator *) pointer to memory allocation tool H264_Heap_Objects *m_pObjHeap; + + mfxExtDecryptConfig m_decryptConfig; + std::vector m_subsamples; }; inline diff --git a/_studio/shared/umc/codec/h264_dec/include/umc_h264_va_packer.h b/_studio/shared/umc/codec/h264_dec/include/umc_h264_va_packer.h index b3ca7014..b3d0dc4c 100644 --- a/_studio/shared/umc/codec/h264_dec/include/umc_h264_va_packer.h +++ b/_studio/shared/umc/codec/h264_dec/include/umc_h264_va_packer.h @@ -108,6 +108,9 @@ class PackerVA void FillFrameAsInvalid(VAPictureH264 * pic); + void SetupDecryptDecode(H264Slice *pSlice, VAEncryptionParameters* crypto_params, std::vector* segments); + void PackEncryptedParams(VAEncryptionParameters* crypto_params); + #ifndef MFX_DEC_VIDEO_POSTPROCESS_DISABLE void PackProcessingInfo(H264DecoderFrameInfo * sliceInfo); #endif @@ -125,6 +128,10 @@ class PackerVA int32_t PackSliceParams(H264Slice *pSlice, int32_t sliceNum, int32_t chopping, int32_t numSlicesOfPrevField); void PackQmatrix(const UMC_H264_DECODER::H264ScalingPicParams * scaling); + +private: + VAEncryptionParameters crypto_params_; + std::vector encryption_segment_info_; }; diff --git a/_studio/shared/umc/codec/h264_dec/src/umc_h264_nal_spl.cpp b/_studio/shared/umc/codec/h264_dec/src/umc_h264_nal_spl.cpp index 8e48dd25..1eefed7e 100644 --- a/_studio/shared/umc/codec/h264_dec/src/umc_h264_nal_spl.cpp +++ b/_studio/shared/umc/codec/h264_dec/src/umc_h264_nal_spl.cpp @@ -24,7 +24,7 @@ #if defined (MFX_ENABLE_H264_VIDEO_DECODE) #include -#include "umc_structures.h" +#include "umc_decrypt.h" #include "umc_h264_nal_spl.h" #include "mfx_utils_logging.h" @@ -151,8 +151,8 @@ class StartCodeIterator : public StartCodeIteratorBase return -1; int32_t startCodeSize; - - int32_t iCodeNext = FindStartCode(source, size, startCodeSize); + const Ranges& encryptedRanges = pSource->GetEncryptedRanges(); + int32_t iCodeNext = FindStartCodeInClearRanges(source, size, startCodeSize, encryptedRanges); if (m_prev.size()) { @@ -198,7 +198,7 @@ class StartCodeIterator : public StartCodeIteratorBase pSource->MoveDataPointer((int32_t)(source - (uint8_t *)pSource->GetDataPointer() - startCodeSize)); int32_t startCodeSize1; - iCodeNext = FindStartCode(source, size, startCodeSize1); + iCodeNext = FindStartCodeInClearRanges(source, size, startCodeSize1, encryptedRanges); pSource->MoveDataPointer(startCodeSize); @@ -280,6 +280,45 @@ class StartCodeIterator : public StartCodeIteratorBase int32_t m_code; double m_pts; + int32_t FindStartCodeInClearRanges(uint8_t * (&pb), size_t & size, int32_t & startCodeSize, const Ranges& encryptedRanges) + { + if (encryptedRanges.size() == 0) + return FindStartCode(pb, size, startCodeSize); + + uint8_t* pbEnd = pb + size; + int32_t iCodeNext = -1; + uint8_t* start = pb; + int32_t startCodeSize1; + size_t bytesLeft; + do { + bytesLeft = size - (start - pb); + iCodeNext = FindStartCode(start, bytesLeft, startCodeSize1); + if (iCodeNext == -1) { + pb = start; + size = bytesLeft; + startCodeSize = startCodeSize1; + return -1; + } + const uint8_t* startCode = start - startCodeSize1; + const uint8_t* startCodeEnd = start; + Ranges startCodeRange; + startCodeRange.Add(startCode, startCodeEnd + 1); + + if (encryptedRanges.IntersectionWith(startCodeRange).size() > 0) { + // The start code is inside an encrypted section so we need to scan + // for another start code. + startCodeSize1 = 0; + start = std::min(start - startCodeSize1 + 1, pbEnd); + } + + } while (startCodeSize1 == 0); + + pb = start; + size = bytesLeft; + startCodeSize = startCodeSize1; + return iCodeNext; + } + int32_t FindStartCode(uint8_t * (&pb), size_t & size, int32_t & startCodeSize) { uint32_t zeroCount = 0; @@ -391,6 +430,18 @@ class Swapper : public SwapperBase } }; +void NalUnit::GetCurrentSubsamples(MediaData *pSource) +{ + MediaData::AuxInfo* aux = (pSource) ? pSource->GetAuxInfo(MFX_EXTBUFF_DECRYPT_CONFIG) : NULL; + m_decryptConfig = (aux) ? reinterpret_cast(aux->ptr) : NULL; + + Ranges naluRange; + Ranges encryptedRanges = pSource->GetEncryptedRanges(); + naluRange.Add((const uint8_t*)GetDataPointer(), (const uint8_t*)GetDataPointer() + GetDataSize()); + auto intersection = encryptedRanges.IntersectionWith(naluRange); + m_subsamples = EncryptedRangesToSubsampleEntry(naluRange.start(0), naluRange.end(0), intersection); +} + NALUnitSplitter::NALUnitSplitter() : m_pSwapper(0) , m_pStartCodeIter(0) @@ -447,6 +498,7 @@ NalUnit * NALUnitSplitter::GetNalUnits(MediaData * pSource) return 0; } + m_nalUnit.GetCurrentSubsamples(pSource); m_nalUnit.m_nal_unit_type = iCode; /*static int k = 0; diff --git a/_studio/shared/umc/codec/h264_dec/src/umc_h264_task_supplier.cpp b/_studio/shared/umc/codec/h264_dec/src/umc_h264_task_supplier.cpp index a64a623b..49ae29b5 100644 --- a/_studio/shared/umc/codec/h264_dec/src/umc_h264_task_supplier.cpp +++ b/_studio/shared/umc/codec/h264_dec/src/umc_h264_task_supplier.cpp @@ -3482,6 +3482,8 @@ H264Slice * TaskSupplier::DecodeSliceHeader(NalUnit *nalUnit) } pSlice->SetHeap(&m_ObjHeap); pSlice->IncrementReference(); + pSlice->SetDecryptConfig(nalUnit->DecryptConfig()); + pSlice->SetSubsamples(nalUnit->Subsamples()); notifier0 memory_leak_preventing_slice(pSlice, &H264Slice::DecrementReference); diff --git a/_studio/shared/umc/codec/h264_dec/src/umc_h264_va_packer.cpp b/_studio/shared/umc/codec/h264_dec/src/umc_h264_va_packer.cpp index 79c9d79f..c18f3476 100644 --- a/_studio/shared/umc/codec/h264_dec/src/umc_h264_va_packer.cpp +++ b/_studio/shared/umc/codec/h264_dec/src/umc_h264_va_packer.cpp @@ -26,6 +26,7 @@ #include "umc_va_linux.h" #include "umc_va_video_processing.h" +#include "umc_decrypt.h" #include "mfx_common_int.h" #include "mfx_ext_buffers.h" @@ -689,9 +690,90 @@ int32_t PackerVA::PackSliceParams(H264Slice *pSlice, int32_t sliceNum, int32_t c } TRACE_BUFFER_EVENT(VA_TRACE_API_AVC_SLICEPARAMETER_TASK, EVENT_TYPE_INFO, TR_KEY_DECODE_SLICEPARAM, pSlice_H264, H264DecodeSliceParam, SLICEPARAM_AVC); + + SetupDecryptDecode(pSlice, &crypto_params_, &encryption_segment_info_); return partial_data; } +void PackerVA::SetupDecryptDecode(H264Slice *pSlice, VAEncryptionParameters* crypto_params, std::vector* segments) +{ + const mfxExtDecryptConfig& decryptConfig = pSlice->GetDecryptConfig(); + const std::vector& subsamples = pSlice->GetSubsamples(); + + size_t offset = 0; + for (const auto& segment : *segments) + offset += segment.segment_length; + + if (decryptConfig.encryption_scheme == EncryptionScheme::kUnencrypted) { + crypto_params->encryption_type = VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR; // FIXME + VAEncryptionSegmentInfo segment_info = {}; + segment_info.segment_start_offset = offset; + segment_info.segment_length = segment_info.init_byte_length = subsamples[0].clear_bytes; // FIXME: subsamples empty? + segments->emplace_back(std::move(segment_info)); + crypto_params->num_segments++; + crypto_params->segment_info = &segments->front(); + return; + } + + m_va->DecryptCTR(decryptConfig, crypto_params); + + crypto_params->num_segments += subsamples.size(); + + const bool ctr = (decryptConfig.encryption_scheme == EncryptionScheme::kCenc); + if (ctr) + { + crypto_params->encryption_type = VA_ENCRYPTION_TYPE_SUBSAMPLE_CTR; + } + else + { + crypto_params->encryption_type = VA_ENCRYPTION_TYPE_SUBSAMPLE_CBC; + } + + size_t total_cypher_size = 0; + std::vector iv(kDecryptionKeySize); + iv.assign(decryptConfig.iv, decryptConfig.iv + kDecryptionKeySize); + + for (const auto& entry : subsamples) + { + VAEncryptionSegmentInfo segment_info = {}; + segment_info.segment_start_offset = offset; + segment_info.segment_length = entry.clear_bytes + entry.cypher_bytes; + memcpy(segment_info.aes_cbc_iv_or_ctr, iv.data(), kDecryptionKeySize); + if (ctr) + { + size_t partial_block_size = (kDecryptionKeySize - (total_cypher_size % kDecryptionKeySize)) % kDecryptionKeySize; + segment_info.partial_aes_block_size = partial_block_size; + if (entry.cypher_bytes > partial_block_size) { + // If we are finishing a block, increment the counter. + if (partial_block_size) + ctr128_inc64(iv.data()); + // Increment the counter for every complete block we are adding. + for (size_t block = 0; + block < (entry.cypher_bytes - partial_block_size) / kDecryptionKeySize; + ++block) + ctr128_inc64(iv.data()); + } + total_cypher_size += entry.cypher_bytes; + } + segment_info.init_byte_length = entry.clear_bytes; + offset += entry.clear_bytes + entry.cypher_bytes; + segments->emplace_back(std::move(segment_info)); + } + + crypto_params->key_blob_size = kDecryptionKeySize; + crypto_params->segment_info = &segments->front(); +} + +void PackerVA::PackEncryptedParams(VAEncryptionParameters* crypto_params) +{ + UMCVACompBuffer *encryptionParameterBuffer; + VAEncryptionParameters* pCrypto = (VAEncryptionParameters*)m_va->GetCompBuffer(VAEncryptionParameterBufferType, &encryptionParameterBuffer, sizeof(VAEncryptionParameters)); + if (!pCrypto) + throw h264_exception(UMC_ERR_FAILED); + memcpy(pCrypto, crypto_params, sizeof(VAEncryptionParameters)); + encryptionParameterBuffer->SetDataSize(sizeof(VAEncryptionParameters)); +} + #ifndef MFX_DEC_VIDEO_POSTPROCESS_DISABLE void PackerVA::PackProcessingInfo(H264DecoderFrameInfo * sliceInfo) { @@ -797,6 +879,8 @@ void PackerVA::PackAU(const H264DecoderFrame *pFrame, int32_t isTop) for ( ; first_slice < count_all; ) { + encryption_segment_info_.clear(); + memset(&crypto_params_, 0, sizeof(crypto_params_)); PackPicParams(sliceInfo, slice); CreateSliceParamBuffer(sliceInfo); @@ -830,6 +914,7 @@ void PackerVA::PackAU(const H264DecoderFrame *pFrame, int32_t isTop) if (m_va->GetVideoProcessingVA()) PackProcessingInfo(sliceInfo); #endif + PackEncryptedParams(&crypto_params_); Status sts = m_va->Execute(); if (sts != UMC_OK) diff --git a/_studio/shared/umc/core/umc/include/umc_decrypt.h b/_studio/shared/umc/core/umc/include/umc_decrypt.h new file mode 100644 index 00000000..13bb224a --- /dev/null +++ b/_studio/shared/umc/core/umc/include/umc_decrypt.h @@ -0,0 +1,107 @@ +// Copyright (c) 2008-2019 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __UMC_DECRYPT_H_ +#define __UMC_DECRYPT_H_ + +#include +#include "umc_ranges.h" +#include "mfxstructures.h" + +namespace UMC { + +const int kDecryptionKeySize = 16; + +void ctr128_inc64(uint8_t* counter); + +std::vector EncryptedRangesToSubsampleEntry( + const uint8_t* start, + const uint8_t* end, + const Ranges& encrypted_ranges); + +union pavp_header_stream_t { + uint32_t dw; + struct { + uint32_t pavp_session_index : 7; + uint32_t app_type : 1; + uint32_t reserved : 23; + uint32_t valid : 1; + } fields; +}; + +union pavp_42_header_stream_t { + uint32_t dw; + struct { + uint32_t valid : 1; + uint32_t app_type : 1; + uint32_t stream_id : 16; + uint32_t reserved : 14; + } fields; +}; + +constexpr uint32_t FIRMWARE_API_VERSION_2_1 = ((2 << 16) | (1)); +constexpr uint32_t FIRMWARE_API_VERSION_4_2 = ((4 << 16) | (2)); + +struct pavp_cmd_header_t { + uint32_t api_version = FIRMWARE_API_VERSION_2_1; + uint32_t command_id; + union { + uint32_t status; + pavp_header_stream_t stream_id; + pavp_42_header_stream_t stream_id_42; + }; + uint32_t buffer_len; +}; + +constexpr uint32_t wv20_get_wrapped_title_keys = 0x00C20022; + +struct wv20_get_wrapped_title_keys_in { + pavp_cmd_header_t header; + uint32_t session_id; +}; + +struct wv20_get_wrapped_title_keys_out { + pavp_cmd_header_t header; + uint32_t num_keys; + uint32_t title_key_obj_offset; + uint32_t buffer_size; + uint8_t buffer[]; +}; + +constexpr uint32_t PAVP_HECI_IO_BUFFER_SIZE = 16 * 1024; + +struct wrapped_title_key_t { + uint32_t key_id_size; + uint32_t key_id_offset; + uint32_t enc_title_key_offset; +}; + +struct PAVP_SET_STREAM_KEY_PARAMS { + uint32_t StreamType; + uint32_t EncryptedDecryptKey[4]; + union { + uint32_t EncryptedEncryptKey[4]; + uint32_t EncryptedDecryptRotationKey[4]; + }; +}; + +} // namespace UMC + +#endif // __UMC_DECRYPT_H_ \ No newline at end of file diff --git a/_studio/shared/umc/core/umc/include/umc_media_data.h b/_studio/shared/umc/core/umc/include/umc_media_data.h index f54fc863..fd803553 100644 --- a/_studio/shared/umc/core/umc/include/umc_media_data.h +++ b/_studio/shared/umc/core/umc/include/umc_media_data.h @@ -21,6 +21,7 @@ #ifndef __UMC_MEDIA_DATA_H__ #define __UMC_MEDIA_DATA_H__ +#include "umc_ranges.h" #include "umc_structures.h" #include "umc_dynamic_cast.h" @@ -104,6 +105,8 @@ class MediaData void SetAuxInfo(void* ptr, size_t size, int type); void ClearAuxInfo(int type); + void SetEncryptedRanges(Ranges ranges) { m_encryptedRanges = std::move(ranges); } + const Ranges& GetEncryptedRanges(void) const { return m_encryptedRanges; } AuxInfo* GetAuxInfo(int type) { @@ -155,6 +158,8 @@ class MediaData uint32_t m_bMemoryAllocated; // (uint32_t) is memory owned by object std::list m_AuxInfo; + + Ranges m_encryptedRanges; }; diff --git a/_studio/shared/umc/core/umc/include/umc_ranges.h b/_studio/shared/umc/core/umc/include/umc_ranges.h new file mode 100644 index 00000000..1d6d5cd2 --- /dev/null +++ b/_studio/shared/umc/core/umc/include/umc_ranges.h @@ -0,0 +1,182 @@ +// Copyright (c) 2008-2019 Intel Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __UMC_RANGES_H_ +#define __UMC_RANGES_H_ + +#include +#include + +#include +#include +#include + +namespace UMC { + +// Ranges allows holding an ordered list of ranges of [start,end) intervals. +// The canonical example use-case is holding the list of ranges of buffered +// bytes or times in a