blob: 62f38c95456a0542f9042e1fdb51b2c54de70360 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/encryptedmedia/MediaKeyStatusMap.h"
#include "core/dom/DOMArrayBuffer.h"
#include "core/dom/DOMArrayPiece.h"
#include "public/platform/WebData.h"
#include "wtf/text/WTFString.h"
#include <algorithm>
namespace blink {
// Represents the key ID and associated status.
class MediaKeyStatusMap::MapEntry final : public GarbageCollectedFinalized<MediaKeyStatusMap::MapEntry> {
public:
static MapEntry* create(WebData keyId, const String& status)
{
return new MapEntry(keyId, status);
}
virtual ~MapEntry() { }
DOMArrayBuffer* keyId() const
{
return m_keyId.get();
}
const String& status() const
{
return m_status;
}
static bool compareLessThan(MapEntry* a, MapEntry* b)
{
// Compare the keyIds of 2 different MapEntries. Assume that |a| and |b|
// are not null, but the keyId() may be. KeyIds are compared byte
// by byte.
// Handle null cases first (which shouldn't happen).
// |aKeyId| |bKeyId| result
// null null == (false)
// null not-null < (true)
// not-null null > (false)
if (!a->keyId() || !b->keyId())
return b->keyId();
// Compare the bytes.
int result = memcmp(a->keyId()->data(), b->keyId()->data(),
std::min(a->keyId()->byteLength(), b->keyId()->byteLength()));
if (result != 0)
return result < 0;
// KeyIds are equal to the shared length, so the shorter string is <.
return a->keyId()->byteLength() <= b->keyId()->byteLength();
}
DEFINE_INLINE_VIRTUAL_TRACE()
{
}
private:
MapEntry(WebData keyId, const String& status)
: m_keyId(DOMArrayBuffer::create(keyId.data(), keyId.size()))
, m_status(status)
{
}
RefPtr<DOMArrayBuffer> m_keyId;
const String m_status;
};
// Represents an Iterator that loops through the set of MapEntrys.
class MapIterationSource final : public PairIterable<ArrayBufferOrArrayBufferView, String>::IterationSource {
public:
MapIterationSource(MediaKeyStatusMap* map)
: m_map(map)
, m_current(0)
{
}
bool next(ScriptState* scriptState, ArrayBufferOrArrayBufferView& key, String& value, ExceptionState&) override
{
// This simply advances an index and returns the next value if any,
// so if the iterated object is mutated values may be skipped.
if (m_current >= m_map->size())
return false;
const auto& entry = m_map->at(m_current++);
key.setArrayBuffer(entry.keyId());
value = entry.status();
return true;
}
DEFINE_INLINE_VIRTUAL_TRACE()
{
visitor->trace(m_map);
PairIterable<ArrayBufferOrArrayBufferView, String>::IterationSource::trace(visitor);
}
private:
// m_map is stored just for keeping it alive. It needs to be kept
// alive while JavaScript holds the iterator to it.
const Member<const MediaKeyStatusMap> m_map;
size_t m_current;
};
void MediaKeyStatusMap::clear()
{
m_entries.clear();
}
void MediaKeyStatusMap::addEntry(WebData keyId, const String& status)
{
m_entries.append(MapEntry::create(keyId, status));
// No need to do any sorting for the first entry.
if (m_entries.size() == 1)
return;
// Sort the entries.
std::sort(m_entries.begin(), m_entries.end(), MapEntry::compareLessThan);
}
const MediaKeyStatusMap::MapEntry& MediaKeyStatusMap::at(size_t index) const
{
BLINK_ASSERT(index < m_entries.size());
return *m_entries.at(index);
}
size_t MediaKeyStatusMap::indexOf(const DOMArrayPiece& key) const
{
for (size_t index = 0; index < m_entries.size(); ++index) {
const auto& current = m_entries.at(index)->keyId();
if (key == *current)
return index;
}
// Not found, so return an index outside the valid range.
return m_entries.size();
}
PairIterable<ArrayBufferOrArrayBufferView, String>::IterationSource* MediaKeyStatusMap::startIteration(ScriptState*, ExceptionState&)
{
return new MapIterationSource(this);
}
bool MediaKeyStatusMap::getMapEntry(ScriptState*, const ArrayBufferOrArrayBufferView& key, String& value, ExceptionState&)
{
size_t index = indexOf(key);
if (index < m_entries.size()) {
value = at(index).status();
return true;
}
return false;
}
DEFINE_TRACE(MediaKeyStatusMap)
{
visitor->trace(m_entries);
}
} // namespace blink