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