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