propsys: Implement PSStringFromPropertyKey.
[wine] / dlls / msrle32 / msrle32.c
1 /*
2  * Copyright 2002-2003 Michael Günnewig
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 /* TODO:
20  *   - some improvements possible
21  *   - implement DecompressSetPalette? -- do we need it for anything?
22  */
23
24 #include <assert.h>
25
26 #include "msrle_private.h"
27
28 #include "winnls.h"
29 #include "winuser.h"
30
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(msrle32);
34
35 static HINSTANCE MSRLE32_hModule = 0;
36
37 #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020)
38
39 #define ABS(a)                ((a) < 0 ? -(a) : (a))
40 #define SQR(a)                ((a) * (a))
41
42 #define QUALITY_to_DIST(q)    (ICQUALITY_HIGH - q)
43 static inline WORD ColorCmp(WORD clr1, WORD clr2)
44 {
45   register UINT a = (clr1-clr2);
46   return SQR(a);
47 }
48 static inline WORD Intensity(RGBQUAD clr)
49 {
50   return (30 * clr.rgbRed + 59 * clr.rgbGreen + 11 * clr.rgbBlue)/4;
51 }
52
53 #define GetRawPixel(lpbi,lp,x) \
54   ((lpbi)->biBitCount == 1 ? ((lp)[(x)/8] >> (8 - (x)%8)) & 1 : \
55    ((lpbi)->biBitCount == 4 ? ((lp)[(x)/2] >> (4 * (1 - (x)%2))) & 15 : lp[x]))
56
57 /*****************************************************************************/
58
59 /* utility functions */
60 static BOOL    isSupportedDIB(LPCBITMAPINFOHEADER lpbi);
61 static BOOL    isSupportedMRLE(LPCBITMAPINFOHEADER lpbi);
62 static BYTE    MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr);
63
64 /* compression functions */
65 static void    computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn);
66 static LONG    MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi);
67 static LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
68                                     const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
69                                     LPBYTE lpOut, BOOL isKey);
70 static LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
71                                     const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
72                                     LPBYTE lpOut, BOOL isKey);
73
74 /* decompression functions */
75 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
76                                       const BYTE *lpIn, LPBYTE lpOut);
77 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
78                                       const BYTE *lpIn, LPBYTE lpOut);
79
80 /* API functions */
81 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
82                                  LPBITMAPINFOHEADER lpbiOut);
83 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
84                                LPCBITMAPINFOHEADER lpbiOut);
85 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
86                              LPCBITMAPINFOHEADER lpbiOut);
87 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
88                              LPCBITMAPINFOHEADER lpbiOut);
89 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize);
90 static LRESULT CompressEnd(CodecInfo *pi);
91
92 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
93                                    LPBITMAPINFOHEADER lpbiOut);
94 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
95                                LPCBITMAPINFOHEADER lpbiOut);
96 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
97                                LPCBITMAPINFOHEADER lpbiOut);
98 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize);
99 static LRESULT DecompressEnd(CodecInfo *pi);
100 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
101                                     LPBITMAPINFOHEADER lpbiOut);
102
103 /*****************************************************************************/
104
105 static BOOL isSupportedMRLE(LPCBITMAPINFOHEADER lpbi)
106 {
107   /* pre-conditions */
108   assert(lpbi != NULL);
109
110   if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
111       lpbi->biPlanes != 1)
112     return FALSE;
113
114   if (lpbi->biCompression == BI_RLE4) {
115     if (lpbi->biBitCount != 4 ||
116         (lpbi->biWidth % 2) != 0)
117       return FALSE;
118   } else if (lpbi->biCompression == BI_RLE8) {
119     if (lpbi->biBitCount != 8)
120       return FALSE;
121   } else
122     return FALSE;
123
124   return TRUE;
125 }
126
127 static BOOL  isSupportedDIB(LPCBITMAPINFOHEADER lpbi)
128 {
129   /* pre-conditions */
130   assert(lpbi != NULL);
131
132   /* check structure version/planes/compression */
133   if (lpbi->biSize < sizeof(BITMAPINFOHEADER) ||
134       lpbi->biPlanes != 1)
135     return FALSE;
136   if (lpbi->biCompression != BI_RGB &&
137       lpbi->biCompression != BI_BITFIELDS)
138     return FALSE;
139
140   /* check bit-depth */
141   if (lpbi->biBitCount != 1 &&
142       lpbi->biBitCount != 4 &&
143       lpbi->biBitCount != 8 &&
144       lpbi->biBitCount != 15 &&
145       lpbi->biBitCount != 16 &&
146       lpbi->biBitCount != 24 &&
147       lpbi->biBitCount != 32)
148     return FALSE;
149
150   /* check for size(s) */
151   if (!lpbi->biWidth || !lpbi->biHeight)
152     return FALSE; /* image with zero size, makes no sense so error ! */
153   if (DIBWIDTHBYTES(*lpbi) * (DWORD)lpbi->biHeight >= (1UL << 31) - 1)
154     return FALSE; /* image too big ! */
155
156   /* check for nonexistent colortable for hi- and true-color DIB's */
157   if (lpbi->biBitCount >= 15 && lpbi->biClrUsed > 0)
158     return FALSE;
159
160   return TRUE;
161 }
162
163 static BYTE MSRLE32_GetNearestPaletteIndex(UINT count, const RGBQUAD *clrs, RGBQUAD clr)
164 {
165   INT  diff = 0x00FFFFFF;
166   UINT i;
167   UINT idx = 0;
168
169   /* pre-conditions */
170   assert(clrs != NULL);
171
172   for (i = 0; i < count; i++) {
173     int r = ((int)clrs[i].rgbRed   - (int)clr.rgbRed);
174     int g = ((int)clrs[i].rgbGreen - (int)clr.rgbGreen);
175     int b = ((int)clrs[i].rgbBlue  - (int)clr.rgbBlue);
176
177     r = r*r + g*g + b*b;
178
179     if (r < diff) {
180       idx  = i;
181       diff = r;
182       if (diff == 0)
183         break;
184     }
185   }
186
187   return idx;
188 }
189
190 /*****************************************************************************/
191
192 void computeInternalFrame(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn, const BYTE *lpIn)
193 {
194   WORD   wIntensityTbl[256];
195   DWORD  lInLine, lOutLine;
196   LPWORD lpOut;
197   UINT   i;
198   LONG   y;
199
200   /* pre-conditions */
201   assert(pi != NULL && lpbiIn != NULL && lpIn != NULL);
202   assert(pi->pCurFrame != NULL);
203
204   lInLine  = DIBWIDTHBYTES(*lpbiIn);
205   lOutLine = WIDTHBYTES((WORD)lpbiIn->biWidth * 8u * sizeof(WORD)) / 2u;
206   lpOut    = pi->pCurFrame;
207
208   assert(lpbiIn->biClrUsed != 0);
209
210   {
211     const RGBQUAD *lp =
212       (const RGBQUAD *)((const BYTE*)lpbiIn + lpbiIn->biSize);
213
214     for (i = 0; i < lpbiIn->biClrUsed; i++)
215       wIntensityTbl[i] = Intensity(lp[i]);
216   }
217
218   for (y = 0; y < lpbiIn->biHeight; y++) {
219     LONG x;
220
221     switch (lpbiIn->biBitCount) {
222     case 1:
223       for (x = 0; x < lpbiIn->biWidth / 8; x++) {
224         for (i = 0; i < 7; i++)
225           lpOut[8 * x + i] = wIntensityTbl[(lpIn[x] >> (7 - i)) & 1];
226       }
227       break;
228     case 4:
229       for (x = 0; x < lpbiIn->biWidth / 2; x++) {
230         lpOut[2 * x + 0] = wIntensityTbl[(lpIn[x] >> 4)];
231         lpOut[2 * x + 1] = wIntensityTbl[(lpIn[x] & 0x0F)];
232       }
233       break;
234     case 8:
235       for (x = 0; x < lpbiIn->biWidth; x++)
236         lpOut[x] = wIntensityTbl[lpIn[x]];
237       break;
238     }
239
240     lpIn  += lInLine;
241     lpOut += lOutLine;
242   }
243 }
244
245 static LONG MSRLE32_GetMaxCompressedSize(LPCBITMAPINFOHEADER lpbi)
246 {
247   LONG a, b, size;
248
249   /* pre-condition */
250   assert(lpbi != NULL);
251
252   a = lpbi->biWidth / 255;
253   b = lpbi->biWidth % 255;
254   if (lpbi->biBitCount <= 4) {
255     a /= 2;
256     b /= 2;
257   }
258
259   size = (2 + a * (2 + ((a + 2) & ~2)) + b * (2 + ((b + 2) & ~2)));
260   return size * lpbi->biHeight;
261 }
262
263 /* lpP => current  pos in previous frame
264  * lpA => previous pos in current  frame
265  * lpB => current  pos in current  frame
266  */
267 static INT countDiffRLE4(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
268 {
269   INT  count;
270   WORD clr1, clr2;
271
272   /* pre-conditions */
273   assert(lpA && lpB && lDist >= 0 && width > 0);
274
275   if (pos >= width)
276     return 0;
277   if (pos+1 == width)
278     return 1;
279
280   clr1 = lpB[pos++];
281   clr2 = lpB[pos];
282
283   count = 2;
284   while (pos + 1 < width) {
285     WORD clr3, clr4;
286
287     clr3 = lpB[++pos];
288     if (pos + 1 >= width)
289       return count + 1;
290
291     clr4 = lpB[++pos];
292     if (ColorCmp(clr1, clr3) <= lDist &&
293         ColorCmp(clr2, clr4) <= lDist) {
294       /* diff at end? -- look-ahead for at least ?? more encodable pixels */
295       if (pos + 2 < width && ColorCmp(clr1,lpB[pos+1]) <= lDist &&
296           ColorCmp(clr2,lpB[pos+2]) <= lDist) {
297         if (pos + 4 < width && ColorCmp(lpB[pos+1],lpB[pos+3]) <= lDist &&
298             ColorCmp(lpB[pos+2],lpB[pos+4]) <= lDist)
299           return count - 3; /* followed by at least 4 encodable pixels */
300         return count - 2;
301       }
302     } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
303       /* 'compare' with previous frame for end of diff */
304       INT count2 = 0;
305
306       /* FIXME */
307
308       if (count2 >= 8)
309         return count;
310
311       pos -= count2;
312     }
313
314     count += 2;
315     clr1 = clr3;
316     clr2 = clr4;
317   }
318
319   return count;
320 }
321
322 /* lpP => current  pos in previous frame
323  * lpA => previous pos in current  frame
324  * lpB => current  pos in current  frame
325  */
326 static INT countDiffRLE8(const WORD *lpP, const WORD *lpA, const WORD *lpB, INT pos, LONG lDist, LONG width)
327 {
328   INT count;
329
330   for (count = 0; pos < width; pos++, count++) {
331     if (ColorCmp(lpA[pos], lpB[pos]) <= lDist) {
332       /* diff at end? -- look-ahead for some more encodable pixel */
333       if (pos + 1 < width && ColorCmp(lpB[pos], lpB[pos+1]) <= lDist)
334         return count - 1;
335       if (pos + 2 < width && ColorCmp(lpB[pos+1], lpB[pos+2]) <= lDist)
336         return count - 1;
337     } else if (lpP != NULL && ColorCmp(lpP[pos], lpB[pos]) <= lDist) {
338       /* 'compare' with previous frame for end of diff */
339       INT count2 = 0;
340
341       for (count2 = 0, pos++; pos < width && count2 <= 5; pos++, count2++) {
342         if (ColorCmp(lpP[pos], lpB[pos]) > lDist)
343           break;
344       }
345       if (count2 > 4)
346         return count;
347
348       pos -= count2;
349     }
350   }
351
352   return count;
353 }
354
355 static INT MSRLE32_CompressRLE4Line(const CodecInfo *pi, const WORD *lpP,
356                                     const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
357                                     const BYTE *lpIn, LONG lDist,
358                                     INT x, LPBYTE *ppOut,
359                                     DWORD *lpSizeImage)
360 {
361   LPBYTE lpOut = *ppOut;
362   INT    count, pos;
363   WORD   clr1, clr2;
364
365   /* try to encode as many pixel as possible */
366   count = 1;
367   pos   = x;
368   clr1  = lpC[pos++];
369   if (pos < lpbi->biWidth) {
370     clr2 = lpC[pos];
371     for (++count; pos + 1 < lpbi->biWidth; ) {
372       ++pos;
373       if (ColorCmp(clr1, lpC[pos]) > lDist)
374         break;
375       count++;
376       if (pos + 1 >= lpbi->biWidth)
377         break;
378       ++pos;
379       if (ColorCmp(clr2, lpC[pos]) > lDist)
380         break;
381       count++;
382     }
383   }
384
385   if (count < 4) {
386     /* add some pixel for absoluting if possible */
387     count += countDiffRLE4(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
388
389     assert(count > 0);
390
391     /* check for near end of line */
392     if (x + count > lpbi->biWidth)
393       count = lpbi->biWidth - x;
394
395     /* absolute pixel(s) in groups of at least 3 and at most 254 pixels */
396     while (count > 2) {
397       INT  i;
398       INT  size       = min(count, 254);
399       int  bytes      = ((size + 1) & (~1)) / 2;
400       int  extra_byte = bytes & 0x01;
401
402       *lpSizeImage += 2 + bytes + extra_byte;
403       assert(((*lpSizeImage) % 2) == 0);
404       count -= size;
405       *lpOut++ = 0;
406       *lpOut++ = size;
407       for (i = 0; i < size; i += 2) {
408         clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
409         x++;
410         if (i + 1 < size) {
411           clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
412           x++;
413         } else
414           clr2 = 0;
415
416         *lpOut++ = (clr1 << 4) | clr2;
417       }
418       if (extra_byte)
419         *lpOut++ = 0;
420     }
421
422     if (count > 0) {
423       /* too little for absoluting so we must encode them */
424       assert(count <= 2);
425
426       *lpSizeImage += 2;
427       clr1 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
428       x++;
429       if (count == 2) {
430         clr2 = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
431         x++;
432       } else
433         clr2 = 0;
434       *lpOut++ = count;
435       *lpOut++ = (clr1 << 4) | clr2;
436     }
437   } else {
438     /* encode count pixel(s) */
439     clr1 = ((pi->palette_map[GetRawPixel(lpbi,lpIn,x)] << 4) |
440             pi->palette_map[GetRawPixel(lpbi,lpIn,x + 1)]);
441
442     x += count;
443     while (count > 0) {
444       INT size = min(count, 254);
445
446       *lpSizeImage += 2;
447       count    -= size;
448       *lpOut++  = size;
449       *lpOut++  = clr1;
450     }
451   }
452
453   *ppOut = lpOut;
454
455   return x;
456 }
457
458 static INT MSRLE32_CompressRLE8Line(const CodecInfo *pi, const WORD *lpP,
459                                     const WORD *lpC, LPCBITMAPINFOHEADER lpbi,
460                                     const BYTE *lpIn, LONG lDist,
461                                     INT x, LPBYTE *ppOut,
462                                     DWORD *lpSizeImage)
463 {
464   LPBYTE lpOut = *ppOut;
465   INT    count, pos;
466   WORD   clr;
467
468   assert(lpbi->biBitCount <= 8);
469   assert(lpbi->biCompression == BI_RGB);
470
471   /* try to encode as much as possible */
472   pos = x;
473   clr = lpC[pos++];
474   for (count = 1; pos < lpbi->biWidth; count++) {
475     if (ColorCmp(clr, lpC[pos++]) > lDist)
476       break;
477   }
478
479   if (count < 2) {
480     /* add some more pixels for absoluting if possible */
481     count += countDiffRLE8(lpP, lpC - 1, lpC, pos-1, lDist, lpbi->biWidth);
482
483     assert(count > 0);
484
485     /* check for over end of line */
486     if (x + count > lpbi->biWidth)
487       count = lpbi->biWidth - x;
488
489     /* absolute pixel(s) in groups of at least 3 and at most 255 pixels */
490     while (count > 2) {
491       INT  i;
492       INT  size       = min(count, 255);
493       int  extra_byte = size % 2;
494
495       *lpSizeImage += 2 + size + extra_byte;
496       count -= size;
497       *lpOut++ = 0;
498       *lpOut++ = size;
499       for (i = 0; i < size; i++) {
500         *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
501         x++;
502       }
503       if (extra_byte)
504         *lpOut++ = 0;
505     }
506     if (count > 0) {
507       /* too little for absoluting so we must encode them even if it's expensive! */
508       assert(count <= 2);
509
510       *lpSizeImage += 2 * count;
511       *lpOut++ = 1;
512       *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
513       x++;
514
515       if (count == 2) {
516         *lpOut++ = 1;
517         *lpOut++ = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
518         x++;
519       }
520     }
521   } else {
522     /* encode count pixel(s) */
523     clr = pi->palette_map[GetRawPixel(lpbi,lpIn,x)];
524
525     /* optimize end of line */
526     if (x + count + 1 == lpbi->biWidth)
527       count++;
528
529     x += count;
530     while (count > 0) {
531       INT size = min(count, 255);
532
533       *lpSizeImage += 2;
534       count    -= size;
535       *lpOut++  = size;
536       *lpOut++  = clr;
537     }
538   }
539
540   *ppOut = lpOut;
541
542   return x;
543 }
544
545 LRESULT MSRLE32_CompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
546                              const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
547                              LPBYTE lpOut, BOOL isKey)
548 {
549   LPWORD lpC;
550   LONG   lLine, lInLine, lDist;
551   LPBYTE lpOutStart = lpOut;
552
553   /* pre-conditions */
554   assert(pi != NULL && lpbiOut != NULL);
555   assert(lpIn != NULL && lpOut != NULL);
556   assert(pi->pCurFrame != NULL);
557
558   lpC      = pi->pCurFrame;
559   lDist    = QUALITY_to_DIST(pi->dwQuality);
560   lInLine  = DIBWIDTHBYTES(*lpbiIn);
561   lLine    = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
562
563   lpbiOut->biSizeImage = 0;
564   if (isKey) {
565     /* keyframe -- convert internal frame to output format */
566     INT x, y;
567
568     for (y = 0; y < lpbiOut->biHeight; y++) {
569       x = 0;
570
571       do {
572         x = MSRLE32_CompressRLE4Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
573                                      &lpOut, &lpbiOut->biSizeImage);
574       } while (x < lpbiOut->biWidth);
575
576       lpC   += lLine;
577       lpIn  += lInLine;
578
579       /* add EOL -- end of line */
580       lpbiOut->biSizeImage += 2;
581       *(LPWORD)lpOut = 0;
582       lpOut += sizeof(WORD);
583       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
584     }
585   } else {
586     /* delta-frame -- compute delta between last and this internal frame */
587     LPWORD lpP;
588     INT    x, y;
589     INT    jumpx, jumpy;
590
591     assert(pi->pPrevFrame != NULL);
592
593     lpP   = pi->pPrevFrame;
594     jumpy = 0;
595     jumpx = -1;
596
597     for (y = 0; y < lpbiOut->biHeight; y++) {
598       x = 0;
599
600       do {
601         INT count, pos;
602
603         if (jumpx == -1)
604           jumpx = x;
605         for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
606           if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
607             break;
608         }
609
610         if (pos == lpbiOut->biWidth && count > 8) {
611           /* (count > 8) secures that we will save space */
612           jumpy++;
613           break;
614         } else if (jumpy || jumpx != pos) {
615           /* time to jump */
616           assert(jumpx != -1);
617
618           if (pos < jumpx) {
619             /* can only jump in positive direction -- jump until EOL, EOL */
620             INT w = lpbiOut->biWidth - jumpx;
621
622             assert(jumpy > 0);
623             assert(w >= 4);
624
625             jumpx = 0;
626             jumpy--;
627             /* if (w % 255 == 2) then equal costs
628              * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
629              * else it will be cheaper
630              */
631             while (w > 0) {
632               lpbiOut->biSizeImage += 4;
633               *lpOut++ = 0;
634               *lpOut++ = 2;
635               *lpOut   = min(w, 255);
636               w       -= *lpOut++;
637               *lpOut++ = 0;
638             }
639             /* add EOL -- end of line */
640             lpbiOut->biSizeImage += 2;
641             *((LPWORD)lpOut) = 0;
642             lpOut += sizeof(WORD);
643           }
644
645           /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
646
647           /* write out real jump(s) */
648           while (jumpy || pos != jumpx) {
649             lpbiOut->biSizeImage += 4;
650             *lpOut++ = 0;
651             *lpOut++ = 2;
652             *lpOut   = min(pos - jumpx, 255);
653             x       += *lpOut;
654             jumpx   += *lpOut++;
655             *lpOut   = min(jumpy, 255);
656             jumpy   -= *lpOut++;
657           }
658
659           jumpy = 0;
660         }
661
662         jumpx = -1;
663
664         if (x < lpbiOut->biWidth) {
665           /* skipped the 'same' things corresponding to previous frame */
666           x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
667                                &lpOut, &lpbiOut->biSizeImage);
668         }
669       } while (x < lpbiOut->biWidth);
670
671       lpP   += lLine;
672       lpC   += lLine;
673       lpIn  += lInLine;
674
675       if (jumpy == 0) {
676         assert(jumpx == -1);
677
678         /* add EOL -- end of line */
679         lpbiOut->biSizeImage += 2;
680         *((LPWORD)lpOut) = 0;
681         lpOut += sizeof(WORD);
682         assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
683       }
684     }
685
686     /* add EOL -- will be changed to EOI */
687     lpbiOut->biSizeImage += 2;
688     *((LPWORD)lpOut) = 0;
689     lpOut += sizeof(WORD);
690   }
691
692   /* change EOL to EOI -- end of image */
693   lpOut[-1] = 1;
694   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
695
696   return ICERR_OK;
697 }
698
699 LRESULT MSRLE32_CompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
700                              const BYTE *lpIn, LPBITMAPINFOHEADER lpbiOut,
701                              LPBYTE lpOut, BOOL isKey)
702 {
703   LPWORD lpC;
704   LONG   lDist, lInLine, lLine;
705   LPBYTE lpOutStart = lpOut;
706
707   assert(pi != NULL && lpbiOut != NULL);
708   assert(lpIn != NULL && lpOut != NULL);
709   assert(pi->pCurFrame != NULL);
710
711   lpC     = pi->pCurFrame;
712   lDist   = QUALITY_to_DIST(pi->dwQuality);
713   lInLine = DIBWIDTHBYTES(*lpbiIn);
714   lLine   = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
715
716   lpbiOut->biSizeImage = 0;
717   if (isKey) {
718     /* keyframe -- convert internal frame to output format */
719     INT x, y;
720
721     for (y = 0; y < lpbiOut->biHeight; y++) {
722       x = 0;
723
724       do {
725         x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
726                              &lpOut, &lpbiOut->biSizeImage);
727         assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
728       } while (x < lpbiOut->biWidth);
729
730       lpC  += lLine;
731       lpIn += lInLine;
732
733       /* add EOL -- end of line */
734       lpbiOut->biSizeImage += 2;
735       *((LPWORD)lpOut) = 0;
736       lpOut += sizeof(WORD);
737       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
738     }
739   } else {
740     /* delta-frame -- compute delta between last and this internal frame */
741     LPWORD lpP;
742     INT    x, y;
743     INT    jumpx, jumpy;
744
745     assert(pi->pPrevFrame != NULL);
746
747     lpP   = pi->pPrevFrame;
748     jumpx = -1;
749     jumpy = 0;
750
751     for (y = 0; y < lpbiOut->biHeight; y++) {
752       x = 0;
753
754       do {
755         INT count, pos;
756
757         if (jumpx == -1)
758           jumpx = x;
759         for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
760           if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
761             break;
762         }
763
764         if (pos == lpbiOut->biWidth && count > 4) {
765           /* (count > 4) secures that we will save space */
766           jumpy++;
767           break;
768         } else if (jumpy || jumpx != pos) {
769           /* time to jump */
770           assert(jumpx != -1);
771
772           if (pos < jumpx) {
773             /* can only jump in positive direction -- do an EOL then jump */
774             assert(jumpy > 0);
775
776             jumpx = 0;
777             jumpy--;
778
779             /* add EOL -- end of line */
780             lpbiOut->biSizeImage += 2;
781             *((LPWORD)lpOut) = 0;
782             lpOut += sizeof(WORD);
783             assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
784           }
785
786           /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
787
788           /* write out real jump(s) */
789           while (jumpy || pos != jumpx) {
790             lpbiOut->biSizeImage += 4;
791             *lpOut++ = 0;
792             *lpOut++ = 2;
793             *lpOut   = min(pos - jumpx, 255);
794             jumpx   += *lpOut++;
795             *lpOut   = min(jumpy, 255);
796             jumpy   -= *lpOut++;
797           }
798           x = pos;
799
800           jumpy = 0;
801         }
802
803         jumpx = -1;
804
805         if (x < lpbiOut->biWidth) {
806           /* skip the 'same' things corresponding to previous frame */
807           x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
808                                &lpOut, &lpbiOut->biSizeImage);
809           assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
810         }
811       } while (x < lpbiOut->biWidth);
812
813       lpP  += lLine;
814       lpC  += lLine;
815       lpIn += lInLine;
816
817       if (jumpy == 0) {
818         /* add EOL -- end of line */
819         lpbiOut->biSizeImage += 2;
820         *((LPWORD)lpOut) = 0;
821         lpOut += sizeof(WORD);
822         assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
823       }
824     }
825
826     /* add EOL -- will be changed to EOI */
827     lpbiOut->biSizeImage += 2;
828     *((LPWORD)lpOut) = 0;
829     lpOut += sizeof(WORD);
830   }
831
832   /* change EOL to EOI -- end of image */
833   lpOut[-1] = 1;
834   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
835
836   return ICERR_OK;
837 }
838
839 /*****************************************************************************/
840
841 static LRESULT MSRLE32_DecompressRLE4(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
842                                       const BYTE *lpIn, LPBYTE lpOut)
843 {
844   int  bytes_per_pixel;
845   int  line_size;
846   int  pixel_ptr  = 0;
847   int  i;
848   BOOL bEndFlag   = FALSE;
849
850   assert(pi != NULL);
851   assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
852   assert(lpIn != NULL && lpOut != NULL);
853
854   bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
855   line_size       = DIBWIDTHBYTES(*lpbi);
856
857   do {
858     BYTE code0, code1;
859
860     code0 = *lpIn++;
861     code1 = *lpIn++;
862
863     if (code0 == 0) {
864       int  extra_byte;
865
866       switch (code1) {
867       case  0: /* EOL - end of line  */
868         pixel_ptr = 0;
869         lpOut += line_size;
870         break;
871       case  1: /* EOI - end of image */
872         bEndFlag = TRUE;
873         break;
874       case  2: /* skip */
875         pixel_ptr += *lpIn++ * bytes_per_pixel;
876         lpOut     += *lpIn++ * line_size;
877         if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
878           pixel_ptr = 0;
879           lpOut    += line_size;
880         }
881         break;
882       default: /* absolute mode */
883         extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
884
885         if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
886           return ICERR_ERROR;
887
888         code0 = code1;
889         for (i = 0; i < code0 / 2; i++) {
890           if (bytes_per_pixel == 1) {
891             code1 = lpIn[i];
892             lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
893             if (2 * i + 1 <= code0)
894               lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
895           } else if (bytes_per_pixel == 2) {
896             code1 = lpIn[i] >> 4;
897             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
898             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
899
900             if (2 * i + 1 <= code0) {
901               code1 = lpIn[i] & 0x0F;
902               lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
903               lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
904             }
905           } else {
906             code1 = lpIn[i] >> 4;
907             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
908             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
909             lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
910             pixel_ptr += bytes_per_pixel;
911
912             if (2 * i + 1 <= code0) {
913               code1 = lpIn[i] & 0x0F;
914               lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
915               lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
916               lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
917               pixel_ptr += bytes_per_pixel;
918             }
919           }
920         }
921         if (code0 & 0x01) {
922           if (bytes_per_pixel == 1) {
923             code1 = lpIn[i];
924             lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
925           } else if (bytes_per_pixel == 2) {
926             code1 = lpIn[i] >> 4;
927             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
928             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
929           } else {
930             code1 = lpIn[i] >> 4;
931             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
932             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
933             lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
934             pixel_ptr += bytes_per_pixel;
935           }
936           lpIn++;
937         }
938         lpIn += code0 / 2;
939
940         /* if the RLE code is odd, skip a byte in the stream */
941         if (extra_byte)
942           lpIn++;
943       };
944     } else {
945       /* coded mode */
946       if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
947         return ICERR_ERROR;
948
949       if (bytes_per_pixel == 1) {
950         BYTE c1 = pi->palette_map[(code1 >> 4)];
951         BYTE c2 = pi->palette_map[(code1 & 0x0F)];
952
953         for (i = 0; i < code0; i++) {
954           if ((i & 1) == 0)
955             lpOut[pixel_ptr++] = c1;
956           else
957             lpOut[pixel_ptr++] = c2;
958         }
959       } else if (bytes_per_pixel == 2) {
960         BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
961         BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
962
963         BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
964         BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
965
966         for (i = 0; i < code0; i++) {
967           if ((i & 1) == 0) {
968             lpOut[pixel_ptr++] = hi1;
969             lpOut[pixel_ptr++] = lo1;
970           } else {
971             lpOut[pixel_ptr++] = hi2;
972             lpOut[pixel_ptr++] = lo2;
973           }
974         }
975       } else {
976         BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
977         BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
978         BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
979
980         BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
981         BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
982         BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
983
984         for (i = 0; i < code0; i++) {
985           if ((i & 1) == 0) {
986             lpOut[pixel_ptr + 0] = b1;
987             lpOut[pixel_ptr + 1] = g1;
988             lpOut[pixel_ptr + 2] = r1;
989           } else {
990             lpOut[pixel_ptr + 0] = b2;
991             lpOut[pixel_ptr + 1] = g2;
992             lpOut[pixel_ptr + 2] = r2;
993           }
994           pixel_ptr += bytes_per_pixel;
995         }
996       }
997     }
998   } while (! bEndFlag);
999
1000   return ICERR_OK;
1001 }
1002
1003 static LRESULT MSRLE32_DecompressRLE8(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
1004                                       const BYTE *lpIn, LPBYTE lpOut)
1005 {
1006   int  bytes_per_pixel;
1007   int  line_size;
1008   int  pixel_ptr  = 0;
1009   BOOL bEndFlag   = FALSE;
1010
1011   assert(pi != NULL);
1012   assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
1013   assert(lpIn != NULL && lpOut != NULL);
1014
1015   bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
1016   line_size       = DIBWIDTHBYTES(*lpbi);
1017
1018   do {
1019     BYTE code0, code1;
1020
1021     code0 = *lpIn++;
1022     code1 = *lpIn++;
1023
1024     if (code0 == 0) {
1025       int  extra_byte;
1026
1027       switch (code1) {
1028       case  0: /* EOL - end of line  */
1029         pixel_ptr = 0;
1030         lpOut += line_size;
1031         break;
1032       case  1: /* EOI - end of image */
1033         bEndFlag = TRUE;
1034         break;
1035       case  2: /* skip */
1036         pixel_ptr += *lpIn++ * bytes_per_pixel;
1037         lpOut     += *lpIn++ * line_size;
1038         if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1039           pixel_ptr = 0;
1040           lpOut    += line_size;
1041         }
1042         break;
1043       default: /* absolute mode */
1044         if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1045           WARN("aborted absolute: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1046           return ICERR_ERROR;
1047         }
1048         extra_byte = code1 & 0x01;
1049
1050         code0 = code1;
1051         while (code0--) {
1052           code1 = *lpIn++;
1053           if (bytes_per_pixel == 1) {
1054             lpOut[pixel_ptr] = pi->palette_map[code1];
1055           } else if (bytes_per_pixel == 2) {
1056             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1057             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1058           } else {
1059             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1060             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1061             lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1062           }
1063           pixel_ptr += bytes_per_pixel;
1064         }
1065
1066         /* if the RLE code is odd, skip a byte in the stream */
1067         if (extra_byte)
1068           lpIn++;
1069       };
1070     } else {
1071       /* coded mode */
1072       if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1073         WARN("aborted coded: (%d=%d/%d+%d) > %d\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1074         return ICERR_ERROR;
1075       }
1076
1077       if (bytes_per_pixel == 1) {
1078         code1 = pi->palette_map[code1];
1079         while (code0--)
1080           lpOut[pixel_ptr++] = code1;
1081       } else if (bytes_per_pixel == 2) {
1082         BYTE hi = pi->palette_map[code1 * 2 + 0];
1083         BYTE lo = pi->palette_map[code1 * 2 + 1];
1084
1085         while (code0--) {
1086           lpOut[pixel_ptr + 0] = hi;
1087           lpOut[pixel_ptr + 1] = lo;
1088           pixel_ptr += bytes_per_pixel;
1089         }
1090       } else {
1091         BYTE r = pi->palette_map[code1 * 4 + 2];
1092         BYTE g = pi->palette_map[code1 * 4 + 1];
1093         BYTE b = pi->palette_map[code1 * 4 + 0];
1094
1095         while (code0--) {
1096           lpOut[pixel_ptr + 0] = b;
1097           lpOut[pixel_ptr + 1] = g;
1098           lpOut[pixel_ptr + 2] = r;
1099           pixel_ptr += bytes_per_pixel;
1100         }
1101       }
1102     }
1103   } while (! bEndFlag);
1104
1105   return ICERR_OK;
1106 }
1107
1108 /*****************************************************************************/
1109
1110 static CodecInfo* Open(LPICOPEN icinfo)
1111 {
1112   CodecInfo* pi = NULL;
1113
1114   if (icinfo == NULL) {
1115     TRACE("(NULL)\n");
1116     return (LPVOID)0xFFFF0000;
1117   }
1118
1119   if (compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return NULL;
1120
1121   TRACE("(%p = {%u,0x%08X(%4.4s),0x%08X(%4.4s),0x%X,0x%X,...})\n", icinfo,
1122         icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1123         icinfo->fccHandler, (char*)&icinfo->fccHandler,
1124         icinfo->dwVersion,icinfo->dwFlags);
1125
1126   switch (icinfo->fccHandler) {
1127   case FOURCC_RLE:
1128   case FOURCC_RLE4:
1129   case FOURCC_RLE8:
1130   case FOURCC_MRLE:
1131     break;
1132   case mmioFOURCC('m','r','l','e'):
1133     icinfo->fccHandler = FOURCC_MRLE;
1134     break;
1135   default:
1136     WARN("unknown FOURCC = 0x%08X(%4.4s) !\n",
1137          icinfo->fccHandler,(char*)&icinfo->fccHandler);
1138     return NULL;
1139   }
1140
1141   pi = LocalAlloc(LPTR, sizeof(CodecInfo));
1142
1143   if (pi != NULL) {
1144     pi->fccHandler  = icinfo->fccHandler;
1145
1146     pi->bCompress   = FALSE;
1147     pi->dwQuality   = MSRLE32_DEFAULTQUALITY;
1148     pi->nPrevFrame  = -1;
1149     pi->pPrevFrame  = pi->pCurFrame = NULL;
1150
1151     pi->bDecompress = FALSE;
1152     pi->palette_map = NULL;
1153   }
1154
1155   icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1156
1157   return pi;
1158 }
1159
1160 static LRESULT Close(CodecInfo *pi)
1161 {
1162   TRACE("(%p)\n", pi);
1163
1164   /* pre-condition */
1165   assert(pi != NULL);
1166
1167   if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1168     CompressEnd(pi);
1169
1170   LocalFree(pi);
1171   return 1;
1172 }
1173
1174 static LRESULT GetInfo(const CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1175 {
1176   /* pre-condition */
1177   assert(pi != NULL);
1178
1179   /* check parameters */
1180   if (icinfo == NULL)
1181     return sizeof(ICINFO);
1182   if (dwSize < sizeof(ICINFO))
1183     return 0;
1184
1185   icinfo->dwSize       = sizeof(ICINFO);
1186   icinfo->fccType      = ICTYPE_VIDEO;
1187   icinfo->fccHandler   = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1188   icinfo->dwFlags      = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1189   icinfo->dwVersion    = ICVERSION;
1190   icinfo->dwVersionICM = ICVERSION;
1191
1192   LoadStringW(MSRLE32_hModule, IDS_NAME, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR));
1193   LoadStringW(MSRLE32_hModule, IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR));
1194
1195   return sizeof(ICINFO);
1196 }
1197
1198 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1199 {
1200   /* pre-condition */
1201   assert(pi != NULL);
1202
1203   if (lQuality == -1)
1204     lQuality = MSRLE32_DEFAULTQUALITY;
1205   else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1206     return ICERR_BADPARAM;
1207
1208   pi->dwQuality = (DWORD)lQuality;
1209
1210   return ICERR_OK;
1211 }
1212
1213 static LRESULT Configure(const CodecInfo *pi, HWND hWnd)
1214 {
1215   /* pre-condition */
1216   assert(pi != NULL);
1217
1218   /* FIXME */
1219   return ICERR_OK;
1220 }
1221
1222 static LRESULT About(CodecInfo *pi, HWND hWnd)
1223 {
1224   WCHAR szTitle[20];
1225   WCHAR szAbout[128];
1226
1227   /* pre-condition */
1228   assert(MSRLE32_hModule != 0);
1229
1230   LoadStringW(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
1231   LoadStringW(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout)/sizeof(szAbout[0]));
1232
1233   MessageBoxW(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1234
1235   return ICERR_OK;
1236 }
1237
1238 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1239                                  LPBITMAPINFOHEADER lpbiOut)
1240 {
1241   LRESULT size;
1242
1243   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1244
1245   /* pre-condition */
1246   assert(pi != NULL);
1247
1248   /* check parameters -- need at least input format */
1249   if (lpbiIn == NULL) {
1250     if (lpbiOut != NULL)
1251       return ICERR_BADPARAM;
1252     return 0;
1253   }
1254
1255   /* handle unsupported input format */
1256   if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1257     return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1258
1259   assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1260
1261   switch (pi->fccHandler) {
1262   case FOURCC_RLE4:
1263     size = 1 << 4;
1264     break;
1265   case FOURCC_RLE8:
1266     size = 1 << 8;
1267     break;
1268   case FOURCC_RLE:
1269   case FOURCC_MRLE:
1270     size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1271     break;
1272   default:
1273     return ICERR_ERROR;
1274   }
1275
1276   if (lpbiIn->biClrUsed != 0)
1277     size = lpbiIn->biClrUsed;
1278
1279   size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1280
1281   if (lpbiOut != NULL) {
1282     lpbiOut->biSize          = sizeof(BITMAPINFOHEADER);
1283     lpbiOut->biWidth         = lpbiIn->biWidth;
1284     lpbiOut->biHeight        = lpbiIn->biHeight;
1285     lpbiOut->biPlanes        = 1;
1286     if (pi->fccHandler == FOURCC_RLE4 ||
1287         lpbiIn->biBitCount <= 4) {
1288       lpbiOut->biCompression = BI_RLE4;
1289       lpbiOut->biBitCount    = 4;
1290     } else {
1291       lpbiOut->biCompression = BI_RLE8;
1292       lpbiOut->biBitCount    = 8;
1293     }
1294     lpbiOut->biSizeImage     = MSRLE32_GetMaxCompressedSize(lpbiOut);
1295     lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1296     lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1297     if (lpbiIn->biClrUsed == 0)
1298       size = 1<<lpbiIn->biBitCount;
1299     else
1300       size = lpbiIn->biClrUsed;
1301     lpbiOut->biClrUsed       = min(size, 1 << lpbiOut->biBitCount);
1302     lpbiOut->biClrImportant  = 0;
1303
1304     memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1305            (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1306
1307     return ICERR_OK;
1308   } else
1309     return size;
1310 }
1311
1312 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1313                                LPCBITMAPINFOHEADER lpbiOut)
1314 {
1315   /* pre-condition */
1316   assert(pi != NULL);
1317
1318   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1319
1320   /* check parameter -- need at least one format */
1321   if (lpbiIn == NULL && lpbiOut == NULL)
1322     return 0;
1323   /* check if the given format is supported */
1324   if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1325     return 0;
1326
1327   /* the worst case is coding the complete image in absolute mode. */
1328   if (lpbiIn)
1329     return MSRLE32_GetMaxCompressedSize(lpbiIn);
1330   else
1331     return MSRLE32_GetMaxCompressedSize(lpbiOut);
1332 }
1333
1334 static LRESULT CompressQuery(const CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1335                              LPCBITMAPINFOHEADER lpbiOut)
1336 {
1337   /* pre-condition */
1338   assert(pi != NULL);
1339
1340   /* need at least one format */
1341   if (lpbiIn == NULL && lpbiOut == NULL)
1342     return ICERR_BADPARAM;
1343
1344   /* check input format if given */
1345   if (lpbiIn != NULL) {
1346     if (!isSupportedDIB(lpbiIn))
1347       return ICERR_BADFORMAT;
1348
1349     /* for 4-bit need an even width */
1350     if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1351       return ICERR_BADFORMAT;
1352
1353     if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1354       return ICERR_UNSUPPORTED;
1355     else if (lpbiIn->biBitCount > 8)
1356       return ICERR_UNSUPPORTED;
1357   }
1358
1359   /* check output format if given */
1360   if (lpbiOut != NULL) {
1361     if (!isSupportedMRLE(lpbiOut))
1362       return ICERR_BADFORMAT;
1363
1364     if (lpbiIn != NULL) {
1365       if (lpbiIn->biWidth  != lpbiOut->biWidth)
1366         return ICERR_UNSUPPORTED;
1367       if (lpbiIn->biHeight != lpbiOut->biHeight)
1368         return ICERR_UNSUPPORTED;
1369       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1370         return ICERR_UNSUPPORTED;
1371     }
1372   }
1373
1374   return ICERR_OK;
1375 }
1376
1377 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1378                              LPCBITMAPINFOHEADER lpbiOut)
1379 {
1380   const RGBQUAD *rgbIn;
1381   const RGBQUAD *rgbOut;
1382   UINT   i;
1383   size_t size;
1384
1385   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1386
1387   /* pre-condition */
1388   assert(pi != NULL);
1389
1390   /* check parameters -- need both formats */
1391   if (lpbiIn == NULL || lpbiOut == NULL)
1392     return ICERR_BADPARAM;
1393   /* And both must be supported */
1394   if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1395     return ICERR_BADFORMAT;
1396
1397   /* FIXME: cannot compress and decompress at same time! */
1398   if (pi->bDecompress) {
1399     FIXME("cannot compress and decompress at same time!\n");
1400     return ICERR_ERROR;
1401   }
1402
1403   if (pi->bCompress)
1404     CompressEnd(pi);
1405
1406   size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1407   pi->pPrevFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1408   if (pi->pPrevFrame == NULL)
1409     return ICERR_MEMORY;
1410   pi->pCurFrame = GlobalLock(GlobalAlloc(GPTR, size * sizeof(WORD)));
1411   if (pi->pCurFrame == NULL) {
1412     CompressEnd(pi);
1413     return ICERR_MEMORY;
1414   }
1415   pi->nPrevFrame = -1;
1416   pi->bCompress  = TRUE;
1417
1418   rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
1419   rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1420
1421   switch (lpbiOut->biBitCount) {
1422   case 4:
1423   case 8:
1424     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
1425     if (pi->palette_map == NULL) {
1426       CompressEnd(pi);
1427       return ICERR_MEMORY;
1428     }
1429
1430     for (i = 0; i < lpbiIn->biClrUsed; i++) {
1431       pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1432     }
1433     break;
1434   };
1435
1436   return ICERR_OK;
1437 }
1438
1439 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1440 {
1441   int i;
1442
1443   TRACE("(%p,%p,%u)\n",pi,lpic,dwSize);
1444
1445   /* pre-condition */
1446   assert(pi != NULL);
1447
1448   /* check parameters */
1449   if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1450     return ICERR_BADPARAM;
1451   if (!lpic->lpbiOutput || !lpic->lpOutput ||
1452       !lpic->lpbiInput  || !lpic->lpInput)
1453     return ICERR_BADPARAM;
1454
1455   TRACE("lpic={0x%X,%p,%p,%p,%p,%p,%p,%d,%u,%u,%p,%p}\n",lpic->dwFlags,lpic->lpbiOutput,lpic->lpOutput,lpic->lpbiInput,lpic->lpInput,lpic->lpckid,lpic->lpdwFlags,lpic->lFrameNum,lpic->dwFrameSize,lpic->dwQuality,lpic->lpbiPrev,lpic->lpPrev);
1456
1457   if (! pi->bCompress) {
1458     LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1459     if (hr != ICERR_OK)
1460       return hr;
1461   } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1462     return ICERR_BADFORMAT;
1463
1464   if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1465     /* we continue in the sequence so we need to initialize 
1466      * our internal framedata */
1467
1468     computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1469   } else if (lpic->lFrameNum == pi->nPrevFrame) {
1470     /* Oops, compress same frame again ? Okay, as you wish.
1471      * No need to recompute internal framedata, because we only swapped buffers */
1472     LPWORD pTmp = pi->pPrevFrame;
1473
1474     pi->pPrevFrame = pi->pCurFrame;
1475     pi->pCurFrame  = pTmp;
1476   } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1477     LPWORD pTmp;
1478
1479     WARN(": prev=%d cur=%d gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1480     if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1481       return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1482     if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1483       return ICERR_BADFORMAT;
1484
1485     WARN(": prev=%d cur=%d compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1486     computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1487
1488     /* swap buffers for current and previous frame */
1489     /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1490     pTmp = pi->pPrevFrame;
1491     pi->pPrevFrame = pi->pCurFrame;
1492     pi->pCurFrame  = pTmp;
1493     pi->nPrevFrame = lpic->lFrameNum;
1494   }
1495
1496   for (i = 0; i < 3; i++) {
1497     SetQuality(pi, lpic->dwQuality);
1498
1499     lpic->lpbiOutput->biSizeImage = 0;
1500
1501     if (lpic->lpbiOutput->biBitCount == 4)
1502       MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
1503                    lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1504     else
1505       MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
1506                    lpic->lpbiOutput, lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1507
1508     if (lpic->dwFrameSize == 0 ||
1509         lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1510       break;
1511
1512     if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1513       if (lpic->lpbiOutput->biBitCount == 4)
1514         MSRLE32_CompressRLE4(pi, lpic->lpbiInput, lpic->lpInput,
1515                              lpic->lpbiOutput, lpic->lpOutput, TRUE);
1516       else
1517         MSRLE32_CompressRLE8(pi, lpic->lpbiInput, lpic->lpInput,
1518                              lpic->lpbiOutput, lpic->lpOutput, TRUE);
1519
1520       if (lpic->dwFrameSize == 0 ||
1521           lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1522         WARN("switched to keyframe, was small enough!\n");
1523         *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1524         *lpic->lpckid    = MAKEAVICKID(cktypeDIBbits,
1525                                        StreamFromFOURCC(*lpic->lpckid));
1526         break;
1527       }
1528     }
1529
1530     if (lpic->dwQuality < 1000)
1531       break;
1532
1533     lpic->dwQuality -= 1000; /* reduce quality by 10% */
1534   }
1535
1536   { /* swap buffer for current and previous frame */
1537     /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1538     register LPWORD pTmp = pi->pPrevFrame;
1539
1540     pi->pPrevFrame = pi->pCurFrame;
1541     pi->pCurFrame  = pTmp;
1542     pi->nPrevFrame = lpic->lFrameNum;
1543   }
1544
1545   return ICERR_OK;
1546 }
1547
1548 static LRESULT CompressEnd(CodecInfo *pi)
1549 {
1550   TRACE("(%p)\n",pi);
1551
1552   if (pi != NULL) {
1553     if (pi->pPrevFrame != NULL)
1554     {
1555       GlobalUnlock(GlobalHandle(pi->pPrevFrame));
1556       GlobalFree(GlobalHandle(pi->pPrevFrame));
1557     }
1558     if (pi->pCurFrame != NULL)
1559     {
1560       GlobalUnlock(GlobalHandle(pi->pCurFrame));
1561       GlobalFree(GlobalHandle(pi->pCurFrame));
1562     }
1563     pi->pPrevFrame = NULL;
1564     pi->pCurFrame  = NULL;
1565     pi->nPrevFrame = -1;
1566     pi->bCompress  = FALSE;
1567   }
1568
1569   return ICERR_OK;
1570 }
1571
1572 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1573                                    LPBITMAPINFOHEADER lpbiOut)
1574 {
1575   DWORD size;
1576
1577   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1578
1579   /* pre-condition */
1580   assert(pi != NULL);
1581
1582   if (lpbiIn == NULL)
1583     return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1584
1585   if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1586     return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1587
1588   size = lpbiIn->biSize;
1589
1590   if (lpbiIn->biBitCount <= 8)
1591     size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1592
1593   if (lpbiOut != NULL) {
1594     memcpy(lpbiOut, lpbiIn, size);
1595     lpbiOut->biCompression  = BI_RGB;
1596     lpbiOut->biSizeImage    = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1597
1598     return ICERR_OK;
1599   } else
1600     return size;
1601 }
1602
1603 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1604                                LPCBITMAPINFOHEADER lpbiOut)
1605 {
1606   LRESULT hr = ICERR_OK;
1607
1608   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1609
1610   /* pre-condition */
1611   assert(pi != NULL);
1612
1613   /* need at least one format */
1614   if (lpbiIn == NULL && lpbiOut == NULL)
1615     return ICERR_BADPARAM;
1616
1617   /* check input format if given */
1618   if (lpbiIn != NULL) {
1619     if (!isSupportedMRLE(lpbiIn))
1620       return ICERR_BADFORMAT;
1621   }
1622
1623   /* check output format if given */
1624   if (lpbiOut != NULL) {
1625     if (!isSupportedDIB(lpbiOut))
1626       hr = ICERR_BADFORMAT;
1627
1628     if (lpbiIn != NULL) {
1629       if (lpbiIn->biWidth  != lpbiOut->biWidth)
1630         hr = ICERR_UNSUPPORTED;
1631       if (lpbiIn->biHeight != lpbiOut->biHeight)
1632         hr = ICERR_UNSUPPORTED;
1633       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1634         hr = ICERR_UNSUPPORTED;
1635     }
1636   }
1637
1638   return hr;
1639 }
1640
1641 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1642                                LPCBITMAPINFOHEADER lpbiOut)
1643 {
1644   const RGBQUAD *rgbIn;
1645   const RGBQUAD *rgbOut;
1646   UINT  i;
1647
1648   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1649
1650   /* pre-condition */
1651   assert(pi != NULL);
1652
1653   /* check parameters */
1654   if (lpbiIn == NULL || lpbiOut == NULL)
1655     return ICERR_BADPARAM;
1656   if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1657     return ICERR_BADFORMAT;
1658
1659   /* FIXME: cannot compress and decompress at a time! */
1660   if (pi->bCompress) {
1661     FIXME("cannot compress and decompress at same time!\n");
1662     return ICERR_ERROR;
1663   }
1664
1665   if (pi->bDecompress)
1666     DecompressEnd(pi);
1667
1668   rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
1669   rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1670
1671   switch (lpbiOut->biBitCount) {
1672   case 4:
1673   case 8:
1674     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed);
1675     if (pi->palette_map == NULL)
1676       return ICERR_MEMORY;
1677
1678     for (i = 0; i < lpbiIn->biClrUsed; i++) {
1679       pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1680     }
1681     break;
1682   case 15:
1683   case 16:
1684     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1685     if (pi->palette_map == NULL)
1686       return ICERR_MEMORY;
1687
1688     for (i = 0; i < lpbiIn->biClrUsed; i++) {
1689       WORD color;
1690
1691       if (lpbiOut->biBitCount == 15)
1692         color = ((rgbIn[i].rgbRed >> 3) << 10)
1693           | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1694       else
1695         color = ((rgbIn[i].rgbRed >> 3) << 11)
1696           | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1697
1698       pi->palette_map[i * 2 + 1] = color >> 8;
1699       pi->palette_map[i * 2 + 0] = color & 0xFF;
1700     };
1701     break;
1702   case 24:
1703   case 32:
1704     pi->palette_map = LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1705     if (pi->palette_map == NULL)
1706       return ICERR_MEMORY;
1707     memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1708     break;
1709   };
1710
1711   pi->bDecompress = TRUE;
1712
1713   return ICERR_OK;
1714 }
1715
1716 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1717 {
1718   TRACE("(%p,%p,%u)\n",pi,pic,dwSize);
1719
1720   /* pre-condition */
1721   assert(pi != NULL);
1722
1723   /* check parameters */
1724   if (pic == NULL)
1725     return ICERR_BADPARAM;
1726   if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1727       pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1728     return ICERR_BADPARAM;
1729
1730   /* check formats */
1731   if (! pi->bDecompress) {
1732     LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1733     if (hr != ICERR_OK)
1734       return hr;
1735   } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1736     return ICERR_BADFORMAT;
1737
1738   assert(pic->lpbiInput->biWidth  == pic->lpbiOutput->biWidth);
1739   assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1740
1741   pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1742   if (pic->lpbiInput->biBitCount == 4)
1743     return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1744   else
1745     return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1746 }
1747
1748 static LRESULT DecompressEnd(CodecInfo *pi)
1749 {
1750   TRACE("(%p)\n",pi);
1751
1752   /* pre-condition */
1753   assert(pi != NULL);
1754
1755   pi->bDecompress = FALSE;
1756
1757   if (pi->palette_map != NULL) {
1758     LocalFree(pi->palette_map);
1759     pi->palette_map = NULL;
1760   }
1761
1762   return ICERR_OK;
1763 }
1764
1765 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1766                                     LPBITMAPINFOHEADER lpbiOut)
1767 {
1768   int size;
1769
1770   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1771
1772   /* pre-condition */
1773   assert(pi != NULL);
1774
1775   /* check parameters */
1776   if (lpbiIn == NULL || lpbiOut == NULL)
1777     return ICERR_BADPARAM;
1778
1779   if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1780     return ICERR_BADFORMAT;
1781
1782   if (lpbiOut->biBitCount > 8)
1783     return ICERR_ERROR;
1784
1785   if (lpbiIn->biBitCount <= 8) {
1786     if (lpbiIn->biClrUsed > 0)
1787       size = lpbiIn->biClrUsed;
1788     else
1789       size = (1 << lpbiIn->biBitCount);
1790
1791     lpbiOut->biClrUsed = size;
1792
1793     memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1794   } /* else could never occur ! */
1795
1796   return ICERR_OK;
1797 }
1798
1799 /* DriverProc - entry point for an installable driver */
1800 LRESULT CALLBACK MSRLE32_DriverProc(DWORD_PTR dwDrvID, HDRVR hDrv, UINT uMsg,
1801                                     LPARAM lParam1, LPARAM lParam2)
1802 {
1803   CodecInfo *pi = (CodecInfo*)dwDrvID;
1804
1805   TRACE("(%lx,%p,0x%04X,0x%08lX,0x%08lX)\n", dwDrvID, hDrv, uMsg, lParam1, lParam2);
1806
1807   switch (uMsg) {
1808     /* standard driver messages */
1809   case DRV_LOAD:
1810     return DRVCNF_OK;
1811   case DRV_OPEN:
1812       return (LRESULT)Open((ICOPEN*)lParam2);
1813   case DRV_CLOSE:
1814     if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1815       Close(pi);
1816     return DRVCNF_OK;
1817   case DRV_ENABLE:
1818   case DRV_DISABLE:
1819     return DRVCNF_OK;
1820   case DRV_FREE:
1821     return DRVCNF_OK;
1822   case DRV_QUERYCONFIGURE:
1823     return DRVCNF_CANCEL; /* FIXME */
1824   case DRV_CONFIGURE:
1825     return DRVCNF_OK;     /* FIXME */
1826   case DRV_INSTALL:
1827   case DRV_REMOVE:
1828     return DRVCNF_OK;
1829
1830     /* installable compression manager messages */
1831   case ICM_CONFIGURE:
1832     FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1833     if (lParam1 == -1)
1834       return ICERR_UNSUPPORTED; /* FIXME */
1835     else
1836       return Configure(pi, (HWND)lParam1);
1837   case ICM_ABOUT:
1838     if (lParam1 == -1)
1839       return ICERR_OK;
1840     else
1841       return About(pi, (HWND)lParam1);
1842   case ICM_GETSTATE:
1843   case ICM_SETSTATE:
1844     return 0; /* no state */
1845   case ICM_GETINFO:
1846     return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1847   case ICM_GETDEFAULTQUALITY:
1848     if ((LPVOID)lParam1 != NULL) {
1849       *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1850       return ICERR_OK;
1851     }
1852     break;
1853   case ICM_GETQUALITY:
1854     if ((LPVOID)lParam1 != NULL) {
1855       *((LPDWORD)lParam1) = pi->dwQuality;
1856       return ICERR_OK;
1857     }
1858     break;
1859   case ICM_SETQUALITY:
1860     return SetQuality(pi, *(LPLONG)lParam1);
1861   case ICM_COMPRESS_GET_FORMAT:
1862     return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1863                              (LPBITMAPINFOHEADER)lParam2);
1864   case ICM_COMPRESS_GET_SIZE:
1865     return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1866                            (LPCBITMAPINFOHEADER)lParam2);
1867   case ICM_COMPRESS_QUERY:
1868     return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1869                          (LPCBITMAPINFOHEADER)lParam2);
1870   case ICM_COMPRESS_BEGIN:
1871     return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1872                          (LPCBITMAPINFOHEADER)lParam2);
1873   case ICM_COMPRESS:
1874     return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1875   case ICM_COMPRESS_END:
1876     return CompressEnd(pi);
1877   case ICM_DECOMPRESS_GET_FORMAT:
1878     return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1879                                (LPBITMAPINFOHEADER)lParam2);
1880   case ICM_DECOMPRESS_QUERY:
1881     return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1882                            (LPCBITMAPINFOHEADER)lParam2);
1883   case ICM_DECOMPRESS_BEGIN:
1884     return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1885                            (LPCBITMAPINFOHEADER)lParam2);
1886   case ICM_DECOMPRESS:
1887     return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1888   case ICM_DECOMPRESS_END:
1889     return DecompressEnd(pi);
1890   case ICM_DECOMPRESS_SET_PALETTE:
1891     FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1892     return ICERR_UNSUPPORTED;
1893   case ICM_DECOMPRESS_GET_PALETTE:
1894     return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1895                                 (LPBITMAPINFOHEADER)lParam2);
1896   case ICM_GETDEFAULTKEYFRAMERATE:
1897     if ((LPVOID)lParam1 != NULL)
1898       *(LPDWORD)lParam1 = 15;
1899     return ICERR_OK;
1900   default:
1901     if (uMsg < DRV_USER)
1902       return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1903     else
1904       FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1905   };
1906
1907   return ICERR_UNSUPPORTED;
1908 }
1909
1910 /* DllMain - library initialization code */
1911 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1912 {
1913   TRACE("(%p,%d,%p)\n",hModule,dwReason,lpReserved);
1914
1915   switch (dwReason) {
1916   case DLL_PROCESS_ATTACH:
1917     DisableThreadLibraryCalls(hModule);
1918     MSRLE32_hModule = hModule;
1919     break;
1920
1921   case DLL_PROCESS_DETACH:
1922     break;
1923   }
1924
1925   return TRUE;
1926 }