1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "MockCDM.h"
28
29#if ENABLE(ENCRYPTED_MEDIA_V2)
30
31#include "CDM.h"
32#include "MediaKeyError.h"
33#include <wtf/Uint8Array.h>
34
35namespace WebCore {
36
37class MockCDMSession : public CDMSession {
38public:
39    static PassOwnPtr<MockCDMSession> create() { return adoptPtr(new MockCDMSession()); }
40    virtual ~MockCDMSession() { }
41
42    virtual const String& sessionId() const OVERRIDE { return m_sessionId; }
43    virtual PassRefPtr<Uint8Array> generateKeyRequest(const String& mimeType, Uint8Array* initData, String& destinationURL, unsigned short& errorCode, unsigned long& systemCode) OVERRIDE;
44    virtual void releaseKeys() OVERRIDE;
45    virtual bool update(Uint8Array*, RefPtr<Uint8Array>& nextMessage, unsigned short& errorCode, unsigned long& systemCode) OVERRIDE;
46
47protected:
48    MockCDMSession();
49
50    String m_sessionId;
51};
52
53bool MockCDM::supportsKeySystem(const String& keySystem)
54{
55    return equalIgnoringCase(keySystem, "com.webcore.mock");
56}
57
58bool MockCDM::supportsKeySystemAndMimeType(const String& keySystem, const String& mimeType)
59{
60    if (!supportsKeySystem(keySystem))
61        return false;
62
63    return equalIgnoringCase(mimeType, "video/mock");
64}
65
66bool MockCDM::supportsMIMEType(const String& mimeType)
67{
68    return equalIgnoringCase(mimeType, "video/mock");
69}
70
71PassOwnPtr<CDMSession> MockCDM::createSession()
72{
73    return MockCDMSession::create();
74}
75
76static Uint8Array* initDataPrefix()
77{
78    static const unsigned char prefixData[] = {'m', 'o', 'c', 'k'};
79    DEFINE_STATIC_LOCAL(RefPtr<Uint8Array>, prefix, ());
80    static bool initialized = false;
81    if (!initialized) {
82        initialized = true;
83        prefix = Uint8Array::create(prefixData, sizeof(prefixData) / sizeof(prefixData[0]));
84    }
85    return prefix.get();
86}
87
88static Uint8Array* keyPrefix()
89{
90    static const unsigned char prefixData[] = {'k', 'e', 'y'};
91    DEFINE_STATIC_LOCAL(RefPtr<WTF::Uint8Array>, prefix, ());
92    static bool initialized = false;
93    if (!initialized) {
94        initialized = true;
95        prefix = Uint8Array::create(prefixData, sizeof(prefixData) / sizeof(prefixData[0]));
96    }
97    return prefix.get();
98}
99
100static Uint8Array* keyRequest()
101{
102    static const unsigned char requestData[] = {'r', 'e', 'q', 'u', 'e', 's', 't'};
103    DEFINE_STATIC_LOCAL(RefPtr<WTF::Uint8Array>, request, ());
104    static bool initialized = false;
105    if (!initialized) {
106        initialized = true;
107        request = Uint8Array::create(requestData, sizeof(requestData) / sizeof(requestData[0]));
108    }
109    return request.get();
110}
111
112static String generateSessionId()
113{
114    static int monotonicallyIncreasingSessionId = 0;
115    return String::number(monotonicallyIncreasingSessionId++);
116}
117
118MockCDMSession::MockCDMSession()
119    : m_sessionId(generateSessionId())
120{
121}
122
123PassRefPtr<Uint8Array> MockCDMSession::generateKeyRequest(const String&, Uint8Array* initData, String&, unsigned short& errorCode, unsigned long&)
124{
125    for (unsigned i = 0; i < initDataPrefix()->length(); ++i) {
126        if (!initData || i >= initData->length() || initData->item(i) != initDataPrefix()->item(i)) {
127            errorCode = MediaKeyError::MEDIA_KEYERR_UNKNOWN;
128            return 0;
129        }
130    }
131    return keyRequest();
132}
133
134void MockCDMSession::releaseKeys()
135{
136    // no-op
137}
138
139bool MockCDMSession::update(Uint8Array* key, RefPtr<Uint8Array>&, unsigned short& errorCode, unsigned long&)
140{
141    for (unsigned i = 0; i < keyPrefix()->length(); ++i) {
142        if (i >= key->length() || key->item(i) != keyPrefix()->item(i)) {
143            errorCode = MediaKeyError::MEDIA_KEYERR_CLIENT;
144            return false;
145        }
146    }
147    return true;
148}
149
150}
151
152#endif // ENABLE(ENCRYPTED_MEDIA_V2)
153