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