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