colorcontext.c 7.38 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * Copyright 2012 Hans Leidekker for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "objbase.h"

#include "wincodecs_private.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);

typedef struct ColorContext {
    IWICColorContext IWICColorContext_iface;
    LONG ref;
36
    WICColorContextType type;
37 38
    BYTE *profile;
    UINT profile_len;
39
    UINT exif_color_space;
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
} ColorContext;

static inline ColorContext *impl_from_IWICColorContext(IWICColorContext *iface)
{
    return CONTAINING_RECORD(iface, ColorContext, IWICColorContext_iface);
}

static HRESULT WINAPI ColorContext_QueryInterface(IWICColorContext *iface, REFIID iid,
    void **ppv)
{
    ColorContext *This = impl_from_IWICColorContext(iface);
    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);

    if (!ppv) return E_INVALIDARG;

    if (IsEqualIID(&IID_IUnknown, iid) ||
        IsEqualIID(&IID_IWICColorContext, iid))
    {
        *ppv = &This->IWICColorContext_iface;
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    IUnknown_AddRef((IUnknown*)*ppv);
    return S_OK;
}

static ULONG WINAPI ColorContext_AddRef(IWICColorContext *iface)
{
    ColorContext *This = impl_from_IWICColorContext(iface);
    ULONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) refcount=%u\n", iface, ref);

    return ref;
}

static ULONG WINAPI ColorContext_Release(IWICColorContext *iface)
{
    ColorContext *This = impl_from_IWICColorContext(iface);
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) refcount=%u\n", iface, ref);

    if (ref == 0)
    {
89
        HeapFree(GetProcessHeap(), 0, This->profile);
90 91 92 93 94 95
        HeapFree(GetProcessHeap(), 0, This);
    }

    return ref;
}

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
static HRESULT load_profile(const WCHAR *filename, BYTE **profile, UINT *len)
{
    HANDLE handle;
    DWORD count;
    LARGE_INTEGER size;
    BOOL ret;

    *len = 0;
    *profile = NULL;
    handle = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (handle == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError());

    if (!(GetFileSizeEx(handle, &size)))
    {
        CloseHandle(handle);
        return HRESULT_FROM_WIN32(GetLastError());
    }
    if (size.u.HighPart)
    {
        WARN("file too large\n");
        CloseHandle(handle);
        return E_FAIL;
    }
    if (!(*profile = HeapAlloc(GetProcessHeap(), 0, size.u.LowPart)))
    {
        CloseHandle(handle);
        return E_OUTOFMEMORY;
    }
    ret = ReadFile(handle, *profile, size.u.LowPart, &count, NULL);
    CloseHandle(handle);
126 127 128 129 130 131 132 133 134 135
    if (!ret) {
        HeapFree (GetProcessHeap(),0,*profile);
        *profile = NULL;
        return HRESULT_FROM_WIN32(GetLastError());
    }
    if (count != size.u.LowPart) {
        HeapFree (GetProcessHeap(),0,*profile);
        *profile = NULL;
        return E_FAIL;
    }
136 137 138 139
    *len = count;
    return S_OK;
}

140 141 142
static HRESULT WINAPI ColorContext_InitializeFromFilename(IWICColorContext *iface,
    LPCWSTR wzFilename)
{
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
    ColorContext *This = impl_from_IWICColorContext(iface);
    BYTE *profile;
    UINT len;
    HRESULT hr;
    TRACE("(%p,%s)\n", iface, debugstr_w(wzFilename));

    if (This->type != WICColorContextUninitialized && This->type != WICColorContextProfile)
        return WINCODEC_ERR_WRONGSTATE;

    if (!wzFilename) return E_INVALIDARG;

    hr = load_profile(wzFilename, &profile, &len);
    if (FAILED(hr)) return hr;

    HeapFree(GetProcessHeap(), 0, This->profile);
    This->profile = profile;
    This->profile_len = len;
    This->type = WICColorContextProfile;

    return S_OK;
163 164 165 166 167
}

static HRESULT WINAPI ColorContext_InitializeFromMemory(IWICColorContext *iface,
    const BYTE *pbBuffer, UINT cbBufferSize)
{
168
    ColorContext *This = impl_from_IWICColorContext(iface);
169
    BYTE *profile;
170 171
    TRACE("(%p,%p,%u)\n", iface, pbBuffer, cbBufferSize);

172
    if (This->type != WICColorContextUninitialized && This->type != WICColorContextProfile)
173 174
        return WINCODEC_ERR_WRONGSTATE;

175 176
    if (!(profile = HeapAlloc(GetProcessHeap(), 0, cbBufferSize))) return E_OUTOFMEMORY;
    memcpy(profile, pbBuffer, cbBufferSize);
177

178 179
    HeapFree(GetProcessHeap(), 0, This->profile);
    This->profile = profile;
180 181 182 183
    This->profile_len = cbBufferSize;
    This->type = WICColorContextProfile;

    return S_OK;
184 185 186 187 188
}

static HRESULT WINAPI ColorContext_InitializeFromExifColorSpace(IWICColorContext *iface,
    UINT value)
{
189 190 191 192 193 194 195 196 197 198
    ColorContext *This = impl_from_IWICColorContext(iface);
    TRACE("(%p,%u)\n", iface, value);

    if (This->type != WICColorContextUninitialized && This->type != WICColorContextExifColorSpace)
        return WINCODEC_ERR_WRONGSTATE;

    This->exif_color_space = value;
    This->type = WICColorContextExifColorSpace;

    return S_OK;
199 200 201 202 203
}

static HRESULT WINAPI ColorContext_GetType(IWICColorContext *iface,
    WICColorContextType *pType)
{
204 205 206
    ColorContext *This = impl_from_IWICColorContext(iface);
    TRACE("(%p,%p)\n", iface, pType);

207 208
    if (!pType) return E_INVALIDARG;

209 210
    *pType = This->type;
    return S_OK;
211 212 213 214 215
}

static HRESULT WINAPI ColorContext_GetProfileBytes(IWICColorContext *iface,
    UINT cbBuffer, BYTE *pbBuffer, UINT *pcbActual)
{
216 217 218 219 220 221
    ColorContext *This = impl_from_IWICColorContext(iface);
    TRACE("(%p,%u,%p,%p)\n", iface, cbBuffer, pbBuffer, pcbActual);

    if (This->type != WICColorContextProfile)
        return WINCODEC_ERR_NOTINITIALIZED;

222 223
    if (!pcbActual) return E_INVALIDARG;

224 225 226 227 228 229
    if (cbBuffer >= This->profile_len && pbBuffer)
        memcpy(pbBuffer, This->profile, This->profile_len);

    *pcbActual = This->profile_len;

    return S_OK;
230 231 232 233 234
}

static HRESULT WINAPI ColorContext_GetExifColorSpace(IWICColorContext *iface,
    UINT *pValue)
{
235 236 237
    ColorContext *This = impl_from_IWICColorContext(iface);
    TRACE("(%p,%p)\n", iface, pValue);

238 239
    if (!pValue) return E_INVALIDARG;

240 241
    *pValue = This->exif_color_space;
    return S_OK;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
}

static const IWICColorContextVtbl ColorContext_Vtbl = {
    ColorContext_QueryInterface,
    ColorContext_AddRef,
    ColorContext_Release,
    ColorContext_InitializeFromFilename,
    ColorContext_InitializeFromMemory,
    ColorContext_InitializeFromExifColorSpace,
    ColorContext_GetType,
    ColorContext_GetProfileBytes,
    ColorContext_GetExifColorSpace
};

HRESULT ColorContext_Create(IWICColorContext **colorcontext)
{
    ColorContext *This;

260 261
    if (!colorcontext) return E_INVALIDARG;

262 263 264 265 266
    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ColorContext));
    if (!This) return E_OUTOFMEMORY;

    This->IWICColorContext_iface.lpVtbl = &ColorContext_Vtbl;
    This->ref = 1;
267
    This->type = 0;
268 269
    This->profile = NULL;
    This->profile_len = 0;
270
    This->exif_color_space = ~0u;
271 272 273 274 275

    *colorcontext = &This->IWICColorContext_iface;

    return S_OK;
}