1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "wincodecs_private.h"
20 
21 typedef struct ColorContext {
22     IWICColorContext IWICColorContext_iface;
23     LONG ref;
24     WICColorContextType type;
25     BYTE *profile;
26     UINT profile_len;
27     UINT exif_color_space;
28 } ColorContext;
29 
30 static inline ColorContext *impl_from_IWICColorContext(IWICColorContext *iface)
31 {
32     return CONTAINING_RECORD(iface, ColorContext, IWICColorContext_iface);
33 }
34 
35 static HRESULT WINAPI ColorContext_QueryInterface(IWICColorContext *iface, REFIID iid,
36     void **ppv)
37 {
38     ColorContext *This = impl_from_IWICColorContext(iface);
39     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
40 
41     if (!ppv) return E_INVALIDARG;
42 
43     if (IsEqualIID(&IID_IUnknown, iid) ||
44         IsEqualIID(&IID_IWICColorContext, iid))
45     {
46         *ppv = &This->IWICColorContext_iface;
47     }
48     else
49     {
50         *ppv = NULL;
51         return E_NOINTERFACE;
52     }
53 
54     IUnknown_AddRef((IUnknown*)*ppv);
55     return S_OK;
56 }
57 
58 static ULONG WINAPI ColorContext_AddRef(IWICColorContext *iface)
59 {
60     ColorContext *This = impl_from_IWICColorContext(iface);
61     ULONG ref = InterlockedIncrement(&This->ref);
62 
63     TRACE("(%p) refcount=%u\n", iface, ref);
64 
65     return ref;
66 }
67 
68 static ULONG WINAPI ColorContext_Release(IWICColorContext *iface)
69 {
70     ColorContext *This = impl_from_IWICColorContext(iface);
71     ULONG ref = InterlockedDecrement(&This->ref);
72 
73     TRACE("(%p) refcount=%u\n", iface, ref);
74 
75     if (ref == 0)
76     {
77         HeapFree(GetProcessHeap(), 0, This->profile);
78         HeapFree(GetProcessHeap(), 0, This);
79     }
80 
81     return ref;
82 }
83 
84 static HRESULT load_profile(const WCHAR *filename, BYTE **profile, UINT *len)
85 {
86     HANDLE handle;
87     DWORD count;
88     LARGE_INTEGER size;
89     BOOL ret;
90 
91     *len = 0;
92     *profile = NULL;
93     handle = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
94     if (handle == INVALID_HANDLE_VALUE) return HRESULT_FROM_WIN32(GetLastError());
95 
96     if (!(GetFileSizeEx(handle, &size)))
97     {
98         CloseHandle(handle);
99         return HRESULT_FROM_WIN32(GetLastError());
100     }
101     if (size.u.HighPart)
102     {
103         WARN("file too large\n");
104         CloseHandle(handle);
105         return E_FAIL;
106     }
107     if (!(*profile = HeapAlloc(GetProcessHeap(), 0, size.u.LowPart)))
108     {
109         CloseHandle(handle);
110         return E_OUTOFMEMORY;
111     }
112     ret = ReadFile(handle, *profile, size.u.LowPart, &count, NULL);
113     CloseHandle(handle);
114     if (!ret) {
115         HeapFree (GetProcessHeap(),0,*profile);
116         *profile = NULL;
117         return HRESULT_FROM_WIN32(GetLastError());
118     }
119     if (count != size.u.LowPart) {
120         HeapFree (GetProcessHeap(),0,*profile);
121         *profile = NULL;
122         return E_FAIL;
123     }
124     *len = count;
125     return S_OK;
126 }
127 
128 static HRESULT WINAPI ColorContext_InitializeFromFilename(IWICColorContext *iface,
129     LPCWSTR wzFilename)
130 {
131     ColorContext *This = impl_from_IWICColorContext(iface);
132     BYTE *profile;
133     UINT len;
134     HRESULT hr;
135     TRACE("(%p,%s)\n", iface, debugstr_w(wzFilename));
136 
137     if (This->type != WICColorContextUninitialized && This->type != WICColorContextProfile)
138         return WINCODEC_ERR_WRONGSTATE;
139 
140     if (!wzFilename) return E_INVALIDARG;
141 
142     hr = load_profile(wzFilename, &profile, &len);
143     if (FAILED(hr)) return hr;
144 
145     HeapFree(GetProcessHeap(), 0, This->profile);
146     This->profile = profile;
147     This->profile_len = len;
148     This->type = WICColorContextProfile;
149 
150     return S_OK;
151 }
152 
153 static HRESULT WINAPI ColorContext_InitializeFromMemory(IWICColorContext *iface,
154     const BYTE *pbBuffer, UINT cbBufferSize)
155 {
156     ColorContext *This = impl_from_IWICColorContext(iface);
157     BYTE *profile;
158     TRACE("(%p,%p,%u)\n", iface, pbBuffer, cbBufferSize);
159 
160     if (This->type != WICColorContextUninitialized && This->type != WICColorContextProfile)
161         return WINCODEC_ERR_WRONGSTATE;
162 
163     if (!(profile = HeapAlloc(GetProcessHeap(), 0, cbBufferSize))) return E_OUTOFMEMORY;
164     memcpy(profile, pbBuffer, cbBufferSize);
165 
166     HeapFree(GetProcessHeap(), 0, This->profile);
167     This->profile = profile;
168     This->profile_len = cbBufferSize;
169     This->type = WICColorContextProfile;
170 
171     return S_OK;
172 }
173 
174 static HRESULT WINAPI ColorContext_InitializeFromExifColorSpace(IWICColorContext *iface,
175     UINT value)
176 {
177     ColorContext *This = impl_from_IWICColorContext(iface);
178     TRACE("(%p,%u)\n", iface, value);
179 
180     if (This->type != WICColorContextUninitialized && This->type != WICColorContextExifColorSpace)
181         return WINCODEC_ERR_WRONGSTATE;
182 
183     This->exif_color_space = value;
184     This->type = WICColorContextExifColorSpace;
185 
186     return S_OK;
187 }
188 
189 static HRESULT WINAPI ColorContext_GetType(IWICColorContext *iface,
190     WICColorContextType *pType)
191 {
192     ColorContext *This = impl_from_IWICColorContext(iface);
193     TRACE("(%p,%p)\n", iface, pType);
194 
195     if (!pType) return E_INVALIDARG;
196 
197     *pType = This->type;
198     return S_OK;
199 }
200 
201 static HRESULT WINAPI ColorContext_GetProfileBytes(IWICColorContext *iface,
202     UINT cbBuffer, BYTE *pbBuffer, UINT *pcbActual)
203 {
204     ColorContext *This = impl_from_IWICColorContext(iface);
205     TRACE("(%p,%u,%p,%p)\n", iface, cbBuffer, pbBuffer, pcbActual);
206 
207     if (This->type != WICColorContextProfile)
208         return WINCODEC_ERR_NOTINITIALIZED;
209 
210     if (!pcbActual) return E_INVALIDARG;
211 
212     if (cbBuffer >= This->profile_len && pbBuffer)
213         memcpy(pbBuffer, This->profile, This->profile_len);
214 
215     *pcbActual = This->profile_len;
216 
217     return S_OK;
218 }
219 
220 static HRESULT WINAPI ColorContext_GetExifColorSpace(IWICColorContext *iface,
221     UINT *pValue)
222 {
223     ColorContext *This = impl_from_IWICColorContext(iface);
224     TRACE("(%p,%p)\n", iface, pValue);
225 
226     if (!pValue) return E_INVALIDARG;
227 
228     *pValue = This->exif_color_space;
229     return S_OK;
230 }
231 
232 static const IWICColorContextVtbl ColorContext_Vtbl = {
233     ColorContext_QueryInterface,
234     ColorContext_AddRef,
235     ColorContext_Release,
236     ColorContext_InitializeFromFilename,
237     ColorContext_InitializeFromMemory,
238     ColorContext_InitializeFromExifColorSpace,
239     ColorContext_GetType,
240     ColorContext_GetProfileBytes,
241     ColorContext_GetExifColorSpace
242 };
243 
244 HRESULT ColorContext_Create(IWICColorContext **colorcontext)
245 {
246     ColorContext *This;
247 
248     if (!colorcontext) return E_INVALIDARG;
249 
250     This = HeapAlloc(GetProcessHeap(), 0, sizeof(ColorContext));
251     if (!This) return E_OUTOFMEMORY;
252 
253     This->IWICColorContext_iface.lpVtbl = &ColorContext_Vtbl;
254     This->ref = 1;
255     This->type = 0;
256     This->profile = NULL;
257     This->profile_len = 0;
258     This->exif_color_space = ~0u;
259 
260     *colorcontext = &This->IWICColorContext_iface;
261 
262     return S_OK;
263 }
264