If the selection owner doesn't understand TARGETS, try retrieving
[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 non-existent 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 atleast ?? more encodable pixel */
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 atleast 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 atleast 3 and maximal 254 pixel */
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 less 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 atleast 3 and maximal 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 less 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       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
577     }
578   } else {
579     /* delta-frame -- compute delta between last and this internal frame */
580     LPWORD lpP;
581     INT    x, y;
582     INT    jumpx, jumpy;
583
584     assert(pi->pPrevFrame != NULL);
585
586     lpP   = pi->pPrevFrame;
587     jumpy = 0;
588     jumpx = -1;
589
590     for (y = 0; y < lpbiOut->biHeight; y++) {
591       x = 0;
592
593       do {
594         INT count, pos;
595
596         if (jumpx == -1)
597           jumpx = x;
598         for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
599           if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
600             break;
601         }
602
603         if (pos == lpbiOut->biWidth && count > 8) {
604           /* (count > 8) secures that we will save space */
605           jumpy++;
606           break;
607         } else if (jumpy || jumpx != pos) {
608           /* time to jump */
609           assert(jumpx != -1);
610
611           if (pos < jumpx) {
612             /* can only jump in positive direction -- jump until EOL, EOL */
613             INT w = lpbiOut->biWidth - jumpx;
614
615             assert(jumpy > 0);
616             assert(w >= 4);
617
618             jumpx = 0;
619             jumpy--;
620             /* if (w % 255 == 2) then equal costs
621              * else if (w % 255 < 4 && we could encode all) then 2 bytes too expensive
622              * else it will be cheaper
623              */
624             while (w > 0) {
625               lpbiOut->biSizeImage += 4;
626               *lpOut++ = 0;
627               *lpOut++ = 2;
628               *lpOut   = min(w, 255);
629               w       -= *lpOut++;
630               *lpOut++ = 0;
631             }
632             /* add EOL -- end of line */
633             lpbiOut->biSizeImage += 2;
634             *((LPWORD)lpOut)++ = 0;
635           }
636
637           /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
638
639           /* write out real jump(s) */
640           while (jumpy || pos != jumpx) {
641             lpbiOut->biSizeImage += 4;
642             *lpOut++ = 0;
643             *lpOut++ = 2;
644             *lpOut   = min(pos - jumpx, 255);
645             x       += *lpOut;
646             jumpx   += *lpOut++;
647             *lpOut   = min(jumpy, 255);
648             jumpy   -= *lpOut++;
649           }
650
651           jumpy = 0;
652         }
653
654         jumpx = -1;
655
656         if (x < lpbiOut->biWidth) {
657           /* skipped the 'same' things corresponding to previous frame */
658           x = MSRLE32_CompressRLE4Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
659                                &lpOut, &lpbiOut->biSizeImage);
660         }
661       } while (x < lpbiOut->biWidth);
662
663       lpP   += lLine;
664       lpC   += lLine;
665       lpIn  += lInLine;
666
667       if (jumpy == 0) {
668         assert(jumpx == -1);
669
670         /* add EOL -- end of line */
671         lpbiOut->biSizeImage += 2;
672         *((LPWORD)lpOut)++ = 0;
673         assert(lpOut == lpOutStart + lpbiOut->biSizeImage);
674       }
675     }
676
677     /* add EOL -- will be changed to EOI */
678     lpbiOut->biSizeImage += 2;
679     *((LPWORD)lpOut)++ = 0;
680   }
681
682   /* change EOL to EOI -- end of image */
683   lpOut[-1] = 1;
684   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
685
686   return ICERR_OK;
687 }
688
689 LRESULT MSRLE32_CompressRLE8(CodecInfo *pi, LPBITMAPINFOHEADER lpbiIn, LPBYTE lpIn, LPBITMAPINFOHEADER lpbiOut, LPBYTE lpOut, BOOL isKey)
690 {
691   LPWORD lpC;
692   LONG   lDist, lInLine, lLine;
693   LPBYTE lpOutStart = lpOut;
694
695   assert(pi != NULL && lpbiOut != NULL);
696   assert(lpIn != NULL && lpOut != NULL);
697   assert(pi->pCurFrame != NULL);
698
699   lpC     = pi->pCurFrame;
700   lDist   = QUALITY_to_DIST(pi->dwQuality);
701   lInLine = DIBWIDTHBYTES(*lpbiIn);
702   lLine   = WIDTHBYTES(lpbiOut->biWidth * 16) / 2;
703
704   lpbiOut->biSizeImage = 0;
705   if (isKey) {
706     /* keyframe -- convert internal frame to output format */
707     INT x, y;
708
709     for (y = 0; y < lpbiOut->biHeight; y++) {
710       x = 0;
711
712       do {
713         x = MSRLE32_CompressRLE8Line(pi, NULL, lpC, lpbiIn, lpIn, lDist, x,
714                              &lpOut, &lpbiOut->biSizeImage);
715         assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
716       } while (x < lpbiOut->biWidth);
717
718       lpC  += lLine;
719       lpIn += lInLine;
720
721       /* add EOL -- end of line */
722       lpbiOut->biSizeImage += 2;
723       *((LPWORD)lpOut)++ = 0;
724       assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
725     }
726   } else {
727     /* delta-frame -- compute delta between last and this internal frame */
728     LPWORD lpP;
729     INT    x, y;
730     INT    jumpx, jumpy;
731
732     assert(pi->pPrevFrame != NULL);
733
734     lpP   = pi->pPrevFrame;
735     jumpx = -1;
736     jumpy = 0;
737
738     for (y = 0; y < lpbiOut->biHeight; y++) {
739       x = 0;
740
741       do {
742         INT count, pos;
743
744         if (jumpx == -1)
745           jumpx = x;
746         for (count = 0, pos = x; pos < lpbiOut->biWidth; pos++, count++) {
747           if (ColorCmp(lpP[pos], lpC[pos]) > lDist)
748             break;
749         }
750
751         if (pos == lpbiOut->biWidth && count > 4) {
752           /* (count > 4) secures that we will save space */
753           jumpy++;
754           break;
755         } else if (jumpy || jumpx != pos) {
756           /* time to jump */
757           assert(jumpx != -1);
758
759           if (pos < jumpx) {
760             /* can only jump in positive direction -- do a EOL then jump */
761             assert(jumpy > 0);
762
763             jumpx = 0;
764             jumpy--;
765
766             /* add EOL -- end of line */
767             lpbiOut->biSizeImage += 2;
768             *((LPWORD)lpOut)++ = 0;
769             assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
770           }
771
772           /* FIXME: if (jumpy == 0 && could encode all) then jump too expensive */
773
774           /* write out real jump(s) */
775           while (jumpy || pos != jumpx) {
776             lpbiOut->biSizeImage += 4;
777             *lpOut++ = 0;
778             *lpOut++ = 2;
779             *lpOut   = min(pos - jumpx, 255);
780             jumpx   += *lpOut++;
781             *lpOut   = min(jumpy, 255);
782             jumpy   -= *lpOut++;
783           }
784           x = pos;
785
786           jumpy = 0;
787         }
788
789         jumpx = -1;
790
791         if (x < lpbiOut->biWidth) {
792           /* skip the 'same' things corresponding to previous frame */
793           x = MSRLE32_CompressRLE8Line(pi, lpP, lpC, lpbiIn, lpIn, lDist, x,
794                                &lpOut, &lpbiOut->biSizeImage);
795           assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
796         }
797       } while (x < lpbiOut->biWidth);
798
799       lpP  += lLine;
800       lpC  += lLine;
801       lpIn += lInLine;
802
803       if (jumpy == 0) {
804         /* add EOL -- end of line */
805         lpbiOut->biSizeImage += 2;
806         *((LPWORD)lpOut)++ = 0;
807         assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
808       }
809     }
810
811     /* add EOL -- will be changed to EOI */
812     lpbiOut->biSizeImage += 2;
813     *((LPWORD)lpOut)++ = 0;
814   }
815
816   /* change EOL to EOI -- end of image */
817   lpOut[-1] = 1;
818   assert(lpOut == (lpOutStart + lpbiOut->biSizeImage));
819
820   return ICERR_OK;
821 }
822
823 /*****************************************************************************/
824
825 static LRESULT MSRLE32_DecompressRLE4(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
826                                       LPBYTE lpIn, LPBYTE lpOut)
827 {
828   int  bytes_per_pixel;
829   int  line_size;
830   int  pixel_ptr  = 0;
831   int  i;
832   BOOL bEndFlag   = FALSE;
833
834   assert(pi != NULL);
835   assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
836   assert(lpIn != NULL && lpOut != NULL);
837
838   bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
839   line_size       = DIBWIDTHBYTES(*lpbi);
840
841   do {
842     BYTE code0, code1;
843
844     code0 = *lpIn++;
845     code1 = *lpIn++;
846
847     if (code0 == 0) {
848       int  extra_byte;
849
850       switch (code1) {
851       case  0: /* EOL - end of line  */
852         pixel_ptr = 0;
853         lpOut += line_size;
854         break;
855       case  1: /* EOI - end of image */
856         bEndFlag = TRUE;
857         break;
858       case  2: /* skip */
859         pixel_ptr += *lpIn++ * bytes_per_pixel;
860         lpOut     += *lpIn++ * line_size;
861         if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
862           pixel_ptr = 0;
863           lpOut    += line_size;
864         }
865         break;
866       default: /* absolute mode */
867         extra_byte = (((code1 + 1) & (~1)) / 2) & 0x01;
868
869         if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth)
870           return ICERR_ERROR;
871
872         code0 = code1;
873         for (i = 0; i < code0 / 2; i++) {
874           if (bytes_per_pixel == 1) {
875             code1 = lpIn[i];
876             lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
877             if (2 * i + 1 <= code0)
878               lpOut[pixel_ptr++] = pi->palette_map[(code1 & 0x0F)];
879           } else if (bytes_per_pixel == 2) {
880             code1 = lpIn[i] >> 4;
881             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
882             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
883
884             if (2 * i + 1 <= code0) {
885               code1 = lpIn[i] & 0x0F;
886               lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
887               lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
888             }
889           } else {
890             code1 = lpIn[i] >> 4;
891             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
892             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
893             lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
894             pixel_ptr += bytes_per_pixel;
895
896             if (2 * i + 1 <= code0) {
897               code1 = lpIn[i] & 0x0F;
898               lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
899               lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
900               lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
901               pixel_ptr += bytes_per_pixel;
902             }
903           }
904         }
905         if (code0 & 0x01) {
906           if (bytes_per_pixel == 1) {
907             code1 = lpIn[i];
908             lpOut[pixel_ptr++] = pi->palette_map[(code1 >> 4)];
909           } else if (bytes_per_pixel == 2) {
910             code1 = lpIn[i] >> 4;
911             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 0];
912             lpOut[pixel_ptr++] = pi->palette_map[code1 * 2 + 1];
913           } else {
914             code1 = lpIn[i] >> 4;
915             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
916             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
917             lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
918             pixel_ptr += bytes_per_pixel;
919           }
920           lpIn++;
921         }
922         lpIn += code0 / 2;
923
924         /* if the RLE code is odd, skip a byte in the stream */
925         if (extra_byte)
926           lpIn++;
927       };
928     } else {
929       /* coded mode */
930       if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth)
931         return ICERR_ERROR;
932
933       if (bytes_per_pixel == 1) {
934         BYTE c1 = pi->palette_map[(code1 >> 4)];
935         BYTE c2 = pi->palette_map[(code1 & 0x0F)];
936
937         for (i = 0; i < code0; i++) {
938           if ((i & 1) == 0)
939             lpOut[pixel_ptr++] = c1;
940           else
941             lpOut[pixel_ptr++] = c2;
942         }
943       } else if (bytes_per_pixel == 2) {
944         BYTE hi1 = pi->palette_map[(code1 >> 4) * 2 + 0];
945         BYTE lo1 = pi->palette_map[(code1 >> 4) * 2 + 1];
946
947         BYTE hi2 = pi->palette_map[(code1 & 0x0F) * 2 + 0];
948         BYTE lo2 = pi->palette_map[(code1 & 0x0F) * 2 + 1];
949
950         for (i = 0; i < code0; i++) {
951           if ((i & 1) == 0) {
952             lpOut[pixel_ptr++] = hi1;
953             lpOut[pixel_ptr++] = lo1;
954           } else {
955             lpOut[pixel_ptr++] = hi2;
956             lpOut[pixel_ptr++] = lo2;
957           }
958         }
959       } else {
960         BYTE b1 = pi->palette_map[(code1 >> 4) * 4 + 0];
961         BYTE g1 = pi->palette_map[(code1 >> 4) * 4 + 1];
962         BYTE r1 = pi->palette_map[(code1 >> 4) * 4 + 2];
963
964         BYTE b2 = pi->palette_map[(code1 & 0x0F) * 4 + 0];
965         BYTE g2 = pi->palette_map[(code1 & 0x0F) * 4 + 1];
966         BYTE r2 = pi->palette_map[(code1 & 0x0F) * 4 + 2];
967
968         for (i = 0; i < code0; i++) {
969           if ((i & 1) == 0) {
970             lpOut[pixel_ptr + 0] = b1;
971             lpOut[pixel_ptr + 1] = g1;
972             lpOut[pixel_ptr + 2] = r1;
973           } else {
974             lpOut[pixel_ptr + 0] = b2;
975             lpOut[pixel_ptr + 1] = g2;
976             lpOut[pixel_ptr + 2] = r2;
977           }
978           pixel_ptr += bytes_per_pixel;
979         }
980       }
981     }
982   } while (! bEndFlag);
983
984   return ICERR_OK;
985 }
986
987 static LRESULT MSRLE32_DecompressRLE8(CodecInfo *pi, LPCBITMAPINFOHEADER lpbi,
988                                       LPBYTE lpIn, LPBYTE lpOut)
989 {
990   int  bytes_per_pixel;
991   int  line_size;
992   int  pixel_ptr  = 0;
993   BOOL bEndFlag   = FALSE;
994
995   assert(pi != NULL);
996   assert(lpbi != NULL && lpbi->biCompression == BI_RGB);
997   assert(lpIn != NULL && lpOut != NULL);
998
999   bytes_per_pixel = (lpbi->biBitCount + 1) / 8;
1000   line_size       = DIBWIDTHBYTES(*lpbi);
1001
1002   do {
1003     BYTE code0, code1;
1004
1005     code0 = *lpIn++;
1006     code1 = *lpIn++;
1007
1008     if (code0 == 0) {
1009       int  extra_byte;
1010
1011       switch (code1) {
1012       case  0: /* EOL - end of line  */
1013         pixel_ptr = 0;
1014         lpOut += line_size;
1015         break;
1016       case  1: /* EOI - end of image */
1017         bEndFlag = TRUE;
1018         break;
1019       case  2: /* skip */
1020         pixel_ptr += *lpIn++ * bytes_per_pixel;
1021         lpOut     += *lpIn++ * line_size;
1022         if (pixel_ptr >= lpbi->biWidth * bytes_per_pixel) {
1023           pixel_ptr = 0;
1024           lpOut    += line_size;
1025         }
1026         break;
1027       default: /* absolute mode */
1028         if (pixel_ptr/bytes_per_pixel + code1 > lpbi->biWidth) {
1029           WARN("aborted absolute: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1030           return ICERR_ERROR;
1031         }
1032         extra_byte = code1 & 0x01;
1033
1034         code0 = code1;
1035         while (code0--) {
1036           code1 = *lpIn++;
1037           if (bytes_per_pixel == 1) {
1038             lpOut[pixel_ptr] = pi->palette_map[code1];
1039           } else if (bytes_per_pixel == 2) {
1040             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 2 + 0];
1041             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 2 + 1];
1042           } else {
1043             lpOut[pixel_ptr + 0] = pi->palette_map[code1 * 4 + 0];
1044             lpOut[pixel_ptr + 1] = pi->palette_map[code1 * 4 + 1];
1045             lpOut[pixel_ptr + 2] = pi->palette_map[code1 * 4 + 2];
1046           }
1047           pixel_ptr += bytes_per_pixel;
1048         }
1049
1050         /* if the RLE code is odd, skip a byte in the stream */
1051         if (extra_byte)
1052           lpIn++;
1053       };
1054     } else {
1055       /* coded mode */
1056       if (pixel_ptr/bytes_per_pixel + code0 > lpbi->biWidth) {
1057         WARN("aborted coded: (%d=%d/%d+%d) > %ld\n",pixel_ptr/bytes_per_pixel + code1,pixel_ptr,bytes_per_pixel,code1,lpbi->biWidth);
1058         return ICERR_ERROR;
1059       }
1060
1061       if (bytes_per_pixel == 1) {
1062         code1 = pi->palette_map[code1];
1063         while (code0--)
1064           lpOut[pixel_ptr++] = code1;
1065       } else if (bytes_per_pixel == 2) {
1066         BYTE hi = pi->palette_map[code1 * 2 + 0];
1067         BYTE lo = pi->palette_map[code1 * 2 + 1];
1068
1069         while (code0--) {
1070           lpOut[pixel_ptr + 0] = hi;
1071           lpOut[pixel_ptr + 1] = lo;
1072           pixel_ptr += bytes_per_pixel;
1073         }
1074       } else {
1075         BYTE r = pi->palette_map[code1 * 4 + 2];
1076         BYTE g = pi->palette_map[code1 * 4 + 1];
1077         BYTE b = pi->palette_map[code1 * 4 + 0];
1078
1079         while (code0--) {
1080           lpOut[pixel_ptr + 0] = b;
1081           lpOut[pixel_ptr + 1] = g;
1082           lpOut[pixel_ptr + 2] = r;
1083           pixel_ptr += bytes_per_pixel;
1084         }
1085       }
1086     }
1087   } while (! bEndFlag);
1088
1089   return ICERR_OK;
1090 }
1091
1092 /*****************************************************************************/
1093
1094 static CodecInfo* Open(LPICOPEN icinfo)
1095 {
1096   CodecInfo* pi = NULL;
1097
1098   if (icinfo == NULL) {
1099     TRACE("(NULL)\n");
1100     return (LPVOID)0xFFFF0000;
1101   }
1102
1103   TRACE("(%p = {%lu,0x%08lX(%4.4s),0x%08lX(%4.4s),0x%lX,0x%lX,...})\n", icinfo,
1104         icinfo->dwSize, icinfo->fccType, (char*)&icinfo->fccType,
1105         icinfo->fccHandler, (char*)&icinfo->fccHandler,
1106         icinfo->dwVersion,icinfo->dwFlags);
1107
1108   if (icinfo->fccType != ICTYPE_VIDEO)
1109     return NULL;
1110
1111   switch (icinfo->fccHandler) {
1112   case FOURCC_RLE:
1113   case FOURCC_RLE4:
1114   case FOURCC_RLE8:
1115   case FOURCC_MRLE:
1116     break;
1117   case mmioFOURCC('m','r','l','e'):
1118     icinfo->fccHandler = FOURCC_MRLE;
1119     break;
1120   default:
1121     WARN("unknown FOURCC = 0x%08lX(%4.4s) !\n",
1122          icinfo->fccHandler,(char*)&icinfo->fccHandler);
1123     return NULL;
1124   }
1125
1126   pi = (CodecInfo*)LocalAlloc(LPTR, sizeof(CodecInfo));
1127
1128   if (pi != NULL) {
1129     pi->fccHandler  = icinfo->fccHandler;
1130
1131     pi->bCompress   = FALSE;
1132     pi->dwQuality   = MSRLE32_DEFAULTQUALITY;
1133     pi->nPrevFrame  = -1;
1134     pi->pPrevFrame  = pi->pCurFrame = NULL;
1135
1136     pi->bDecompress = FALSE;
1137     pi->palette_map = NULL;
1138   }
1139
1140   icinfo->dwError = (pi != NULL ? ICERR_OK : ICERR_MEMORY);
1141
1142   return pi;
1143 }
1144
1145 static LRESULT Close(CodecInfo *pi)
1146 {
1147   TRACE("(%p)\n", pi);
1148
1149   /* pre-condition */
1150   assert(pi != NULL);
1151
1152   if (pi->pPrevFrame != NULL || pi->pCurFrame != NULL)
1153     CompressEnd(pi);
1154
1155   LocalFree((HLOCAL)pi);
1156   return 1;
1157 }
1158
1159 static LRESULT GetInfo(CodecInfo *pi, ICINFO *icinfo, DWORD dwSize)
1160 {
1161   /* pre-condition */
1162   assert(pi != NULL);
1163
1164   /* check parameters */
1165   if (icinfo == NULL)
1166     return sizeof(ICINFO);
1167   if (dwSize < sizeof(ICINFO))
1168     return 0;
1169
1170   icinfo->dwSize       = sizeof(ICINFO);
1171   icinfo->fccType      = streamtypeVIDEO;
1172   icinfo->fccHandler   = (pi != NULL ? pi->fccHandler : FOURCC_MRLE);
1173   icinfo->dwFlags      = VIDCF_QUALITY | VIDCF_TEMPORAL | VIDCF_CRUNCH | VIDCF_FASTTEMPORALC;
1174   icinfo->dwVersion    = MSRLE32_VERSION;
1175   icinfo->dwVersionICM = 0x01040000; /* Version 1.4 build 0 */
1176
1177   LoadWideString(IDS_NAME, icinfo->szName, sizeof(icinfo->szName));
1178   LoadWideString(IDS_DESCRIPTION, icinfo->szDescription, sizeof(icinfo->szDescription));
1179
1180   return sizeof(ICINFO);
1181 }
1182
1183 static LRESULT SetQuality(CodecInfo *pi, LONG lQuality)
1184 {
1185   /* pre-condition */
1186   assert(pi != NULL);
1187
1188   if (lQuality == -1)
1189     lQuality = MSRLE32_DEFAULTQUALITY;
1190   else if (ICQUALITY_LOW > lQuality || lQuality > ICQUALITY_HIGH)
1191     return ICERR_BADPARAM;
1192
1193   pi->dwQuality = (DWORD)lQuality;
1194
1195   return ICERR_OK;
1196 }
1197
1198 static LRESULT Configure(CodecInfo *pi, HWND hWnd)
1199 {
1200   /* pre-condition */
1201   assert(pi != NULL);
1202
1203   /* FIXME */
1204   return ICERR_OK;
1205 }
1206
1207 static LRESULT About(CodecInfo *pi, HWND hWnd)
1208 {
1209   CHAR szTitle[20];
1210   CHAR szAbout[128];
1211
1212   /* pre-condition */
1213   assert(MSRLE32_hModule != 0);
1214
1215   LoadStringA(MSRLE32_hModule, IDS_NAME, szTitle, sizeof(szTitle));
1216   LoadStringA(MSRLE32_hModule, IDS_ABOUT, szAbout, sizeof(szAbout));
1217
1218   MessageBoxA(hWnd, szAbout, szTitle, MB_OK|MB_ICONINFORMATION);
1219
1220   return ICERR_OK;
1221 }
1222
1223 static LRESULT CompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1224                                  LPBITMAPINFOHEADER lpbiOut)
1225 {
1226   LRESULT size;
1227
1228   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1229
1230   /* pre-condition */
1231   assert(pi != NULL);
1232
1233   /* check parameters -- need atleast input format */
1234   if (lpbiIn == NULL) {
1235     if (lpbiOut != NULL)
1236       return ICERR_BADPARAM;
1237     return 0;
1238   }
1239
1240   /* handle unsupported input format */
1241   if (CompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1242     return (lpbiOut == NULL ? ICERR_BADFORMAT : 0);
1243
1244   assert(0 < lpbiIn->biBitCount && lpbiIn->biBitCount <= 8);
1245
1246   switch (pi->fccHandler) {
1247   case FOURCC_RLE4:
1248     size = 1 << 4;
1249     break;
1250   case FOURCC_RLE8:
1251     size = 1 << 8;
1252     break;
1253   case FOURCC_RLE:
1254   case FOURCC_MRLE:
1255     size = (lpbiIn->biBitCount <= 4 ? 1 << 4 : 1 << 8);
1256     break;
1257   default:
1258     return ICERR_ERROR;
1259   }
1260
1261   if (lpbiIn->biClrUsed != 0)
1262     size = lpbiIn->biClrUsed;
1263
1264   size = sizeof(BITMAPINFOHEADER) + size * sizeof(RGBQUAD);
1265
1266   if (lpbiOut != NULL) {
1267     lpbiOut->biSize          = sizeof(BITMAPINFOHEADER);
1268     lpbiOut->biWidth         = lpbiIn->biWidth;
1269     lpbiOut->biHeight        = lpbiIn->biHeight;
1270     lpbiOut->biPlanes        = 1;
1271     if (pi->fccHandler == FOURCC_RLE4 ||
1272         lpbiIn->biBitCount <= 4) {
1273       lpbiOut->biCompression = BI_RLE4;
1274       lpbiOut->biBitCount    = 4;
1275     } else {
1276       lpbiOut->biCompression = BI_RLE8;
1277       lpbiOut->biBitCount    = 8;
1278     }
1279     lpbiOut->biSizeImage     = MSRLE32_GetMaxCompressedSize(lpbiOut);
1280     lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter;
1281     lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter;
1282     if (lpbiIn->biClrUsed == 0)
1283       size = 1<<lpbiIn->biBitCount;
1284     else
1285       size = lpbiIn->biClrUsed;
1286     lpbiOut->biClrUsed       = min(size, 1 << lpbiOut->biBitCount);
1287     lpbiOut->biClrImportant  = 0;
1288
1289     memcpy((LPBYTE)lpbiOut + lpbiOut->biSize,
1290            (const BYTE*)lpbiIn + lpbiIn->biSize, lpbiOut->biClrUsed * sizeof(RGBQUAD));
1291
1292     return ICERR_OK;
1293   } else
1294     return size;
1295 }
1296
1297 static LRESULT CompressGetSize(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1298                                LPCBITMAPINFOHEADER lpbiOut)
1299 {
1300   /* pre-condition */
1301   assert(pi != NULL);
1302
1303   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1304
1305   /* check parameter -- need atleast one format */
1306   if (lpbiIn == NULL && lpbiOut == NULL)
1307     return 0;
1308   /* check if the given format is supported */
1309   if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1310     return 0;
1311
1312   /* the worst case is coding the complete image in absolute mode. */
1313   if (lpbiIn)
1314     return MSRLE32_GetMaxCompressedSize(lpbiIn);
1315   else
1316     return MSRLE32_GetMaxCompressedSize(lpbiOut);
1317 }
1318
1319 static LRESULT CompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1320                              LPCBITMAPINFOHEADER lpbiOut)
1321 {
1322   /* pre-condition */
1323   assert(pi != NULL);
1324
1325   /* need atleast one format */
1326   if (lpbiIn == NULL && lpbiOut == NULL)
1327     return ICERR_BADPARAM;
1328
1329   /* check input format if given */
1330   if (lpbiIn != NULL) {
1331     if (!isSupportedDIB(lpbiIn))
1332       return ICERR_BADFORMAT;
1333
1334     /* for 4-bit need an even width */
1335     if (lpbiIn->biBitCount <= 4 && (lpbiIn->biWidth % 2))
1336       return ICERR_BADFORMAT;
1337
1338     if (pi->fccHandler == FOURCC_RLE4 && lpbiIn->biBitCount > 4)
1339       return ICERR_UNSUPPORTED;
1340     else if (lpbiIn->biBitCount > 8)
1341       return ICERR_UNSUPPORTED;
1342   }
1343
1344   /* check output format if given */
1345   if (lpbiOut != NULL) {
1346     if (!isSupportedMRLE(lpbiOut))
1347       return ICERR_BADFORMAT;
1348
1349     if (lpbiIn != NULL) {
1350       if (lpbiIn->biWidth  != lpbiOut->biWidth)
1351         return ICERR_UNSUPPORTED;
1352       if (lpbiIn->biHeight != lpbiOut->biHeight)
1353         return ICERR_UNSUPPORTED;
1354       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1355         return ICERR_UNSUPPORTED;
1356     }
1357   }
1358
1359   return ICERR_OK;
1360 }
1361
1362 static LRESULT CompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1363                              LPCBITMAPINFOHEADER lpbiOut)
1364 {
1365   const RGBQUAD *rgbIn;
1366   const RGBQUAD *rgbOut;
1367   UINT   i;
1368   size_t size;
1369
1370   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1371
1372   /* pre-condition */
1373   assert(pi != NULL);
1374
1375   /* check parameters -- need both formats */
1376   if (lpbiIn == NULL || lpbiOut == NULL)
1377     return ICERR_BADPARAM;
1378   /* And both must be supported */
1379   if (CompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1380     return ICERR_BADFORMAT;
1381
1382   /* FIXME: cannot compress and decompress at same time! */
1383   if (pi->bDecompress) {
1384     FIXME("cannot compress and decompress at same time!\n");
1385     return ICERR_ERROR;
1386   }
1387
1388   if (pi->bCompress)
1389     CompressEnd(pi);
1390
1391   size = WIDTHBYTES(lpbiOut->biWidth * 16) / 2 * lpbiOut->biHeight;
1392   pi->pPrevFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1393   if (pi->pPrevFrame == NULL)
1394     return ICERR_MEMORY;
1395   pi->pCurFrame = (LPWORD)GlobalAllocPtr(GPTR, size * sizeof(WORD));
1396   if (pi->pCurFrame == NULL) {
1397     CompressEnd(pi);
1398     return ICERR_MEMORY;
1399   }
1400   pi->nPrevFrame = -1;
1401   pi->bCompress  = TRUE;
1402
1403   rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
1404   rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1405
1406   switch (lpbiOut->biBitCount) {
1407   case 4:
1408   case 8:
1409     pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1410     if (pi->palette_map == NULL) {
1411       CompressEnd(pi);
1412       return ICERR_MEMORY;
1413     }
1414
1415     for (i = 0; i < lpbiIn->biClrUsed; i++) {
1416       pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1417     }
1418     break;
1419   };
1420
1421   return ICERR_OK;
1422 }
1423
1424 static LRESULT Compress(CodecInfo *pi, ICCOMPRESS* lpic, DWORD dwSize)
1425 {
1426   int i;
1427
1428   TRACE("(%p,%p,%lu)\n",pi,lpic,dwSize);
1429
1430   /* pre-condition */
1431   assert(pi != NULL);
1432
1433   /* check parameters */
1434   if (lpic == NULL || dwSize < sizeof(ICCOMPRESS))
1435     return ICERR_BADPARAM;
1436   if (!lpic->lpbiOutput || !lpic->lpOutput ||
1437       !lpic->lpbiInput  || !lpic->lpInput)
1438     return ICERR_BADPARAM;
1439
1440   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);
1441
1442   if (! pi->bCompress) {
1443     LRESULT hr = CompressBegin(pi, lpic->lpbiInput, lpic->lpbiOutput);
1444     if (hr != ICERR_OK)
1445       return hr;
1446   } else if (CompressQuery(pi, lpic->lpbiInput, lpic->lpbiOutput) != ICERR_OK)
1447     return ICERR_BADFORMAT;
1448
1449   if (lpic->lFrameNum >= pi->nPrevFrame + 1) {
1450     /* we continue in the sequence so we need to initialize 
1451      * our internal framedata */
1452
1453     computeInternalFrame(pi, lpic->lpbiInput, lpic->lpInput);
1454   } else if (lpic->lFrameNum == pi->nPrevFrame) {
1455     /* Oops, compress same frame again ? Okay, as you wish.
1456      * No need to recompute internal framedata, because we only swapped buffers */
1457     LPWORD pTmp = pi->pPrevFrame;
1458
1459     pi->pPrevFrame = pi->pCurFrame;
1460     pi->pCurFrame  = pTmp;
1461   } else if ((lpic->dwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1462     LPWORD pTmp;
1463
1464     WARN(": prev=%ld cur=%ld gone back? -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1465     if (lpic->lpbiPrev == NULL || lpic->lpPrev == NULL)
1466       return ICERR_GOTOKEYFRAME; /* Need a keyframe if you go back */
1467     if (CompressQuery(pi, lpic->lpbiPrev, lpic->lpbiOutput) != ICERR_OK)
1468       return ICERR_BADFORMAT;
1469
1470     WARN(": prev=%ld cur=%ld compute swapped -- untested\n",pi->nPrevFrame,lpic->lFrameNum);
1471     computeInternalFrame(pi, lpic->lpbiPrev, lpic->lpPrev);
1472
1473     /* swap buffers for current and previous frame */
1474     /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1475     pTmp = pi->pPrevFrame;
1476     pi->pPrevFrame = pi->pCurFrame;
1477     pi->pCurFrame  = pTmp;
1478     pi->nPrevFrame = lpic->lFrameNum;
1479   }
1480
1481   for (i = 0; i < 3; i++) {
1482     SetQuality(pi, lpic->dwQuality);
1483
1484     lpic->lpbiOutput->biSizeImage = 0;
1485
1486     if (lpic->lpbiOutput->biBitCount == 4)
1487       MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1488                    lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1489     else
1490       MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1491                    lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, (lpic->dwFlags & ICCOMPRESS_KEYFRAME) != 0);
1492
1493     if (lpic->dwFrameSize == 0 ||
1494         lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize)
1495       break;
1496
1497     if ((*lpic->lpdwFlags & ICCOMPRESS_KEYFRAME) == 0) {
1498       if (lpic->lpbiOutput->biBitCount == 4)
1499         MSRLE32_CompressRLE4(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1500                              lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1501       else
1502         MSRLE32_CompressRLE8(pi, lpic->lpbiInput, (LPBYTE)lpic->lpInput,
1503                              lpic->lpbiOutput, (LPBYTE)lpic->lpOutput, TRUE);
1504
1505       if (lpic->dwFrameSize == 0 ||
1506           lpic->lpbiOutput->biSizeImage < lpic->dwFrameSize) {
1507         WARN("switched to keyframe, was small enough!\n");
1508         *lpic->lpdwFlags |= ICCOMPRESS_KEYFRAME;
1509         *lpic->lpckid    = MAKEAVICKID(cktypeDIBbits,
1510                                        StreamFromFOURCC(*lpic->lpckid));
1511         break;
1512       }
1513     }
1514
1515     if (lpic->dwQuality < 1000)
1516       break;
1517
1518     lpic->dwQuality -= 1000; /* reduce quality by 10% */
1519   }
1520
1521   { /* swap buffer for current and previous frame */
1522     /* Don't free and alloc new -- costs to much time and they are of equal size ! */
1523     register LPWORD pTmp = pi->pPrevFrame;
1524
1525     pi->pPrevFrame = pi->pCurFrame;
1526     pi->pCurFrame  = pTmp;
1527     pi->nPrevFrame = lpic->lFrameNum;
1528   }
1529
1530   return ICERR_OK;
1531 }
1532
1533 static LRESULT CompressEnd(CodecInfo *pi)
1534 {
1535   TRACE("(%p)\n",pi);
1536
1537   if (pi != NULL) {
1538     if (pi->pPrevFrame != NULL)
1539       GlobalFreePtr(pi->pPrevFrame);
1540     if (pi->pCurFrame != NULL)
1541       GlobalFreePtr(pi->pCurFrame);
1542     pi->pPrevFrame = NULL;
1543     pi->pCurFrame  = NULL;
1544     pi->nPrevFrame = -1;
1545     pi->bCompress  = FALSE;
1546   }
1547
1548   return ICERR_OK;
1549 }
1550
1551 static LRESULT DecompressGetFormat(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1552                                    LPBITMAPINFOHEADER lpbiOut)
1553 {
1554   DWORD size;
1555
1556   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1557
1558   /* pre-condition */
1559   assert(pi != NULL);
1560
1561   if (lpbiIn == NULL)
1562     return (lpbiOut != NULL ? ICERR_BADPARAM : 0);
1563
1564   if (DecompressQuery(pi, lpbiIn, NULL) != ICERR_OK)
1565     return (lpbiOut != NULL ? ICERR_BADFORMAT : 0);
1566
1567   size = lpbiIn->biSize;
1568
1569   if (lpbiIn->biBitCount <= 8)
1570     size += lpbiIn->biClrUsed * sizeof(RGBQUAD);
1571
1572   if (lpbiOut != NULL) {
1573     memcpy(lpbiOut, lpbiIn, size);
1574     lpbiOut->biCompression  = BI_RGB;
1575     lpbiOut->biSizeImage    = DIBWIDTHBYTES(*lpbiOut) * lpbiOut->biHeight;
1576
1577     return ICERR_OK;
1578   } else
1579     return size;
1580 }
1581
1582 static LRESULT DecompressQuery(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1583                                LPCBITMAPINFOHEADER lpbiOut)
1584 {
1585   LRESULT hr = ICERR_OK;
1586
1587   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1588
1589   /* pre-condition */
1590   assert(pi != NULL);
1591
1592   /* need atleast one format */
1593   if (lpbiIn == NULL && lpbiOut == NULL)
1594     return ICERR_BADPARAM;
1595
1596   /* check input format if given */
1597   if (lpbiIn != NULL) {
1598     if (!isSupportedMRLE(lpbiIn))
1599       return ICERR_BADFORMAT;
1600   }
1601
1602   /* check output format if given */
1603   if (lpbiOut != NULL) {
1604     if (!isSupportedDIB(lpbiOut))
1605       hr = ICERR_BADFORMAT;
1606
1607     if (lpbiIn != NULL) {
1608       if (lpbiIn->biWidth  != lpbiOut->biWidth)
1609         hr = ICERR_UNSUPPORTED;
1610       if (lpbiIn->biHeight != lpbiOut->biHeight)
1611         hr = ICERR_UNSUPPORTED;
1612       if (lpbiIn->biBitCount > lpbiOut->biBitCount)
1613         hr = ICERR_UNSUPPORTED;
1614     }
1615   }
1616
1617   return hr;
1618 }
1619
1620 static LRESULT DecompressBegin(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1621                                LPCBITMAPINFOHEADER lpbiOut)
1622 {
1623   const RGBQUAD *rgbIn;
1624   const RGBQUAD *rgbOut;
1625   UINT  i;
1626
1627   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1628
1629   /* pre-condition */
1630   assert(pi != NULL);
1631
1632   /* check parameters */
1633   if (lpbiIn == NULL || lpbiOut == NULL)
1634     return ICERR_BADPARAM;
1635   if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1636     return ICERR_BADFORMAT;
1637
1638   /* FIXME: cannot compress and decompress at a time! */
1639   if (pi->bCompress) {
1640     FIXME("cannot compress and decompress at same time!\n");
1641     return ICERR_ERROR;
1642   }
1643
1644   if (pi->bDecompress)
1645     DecompressEnd(pi);
1646
1647   rgbIn  = (const RGBQUAD*)((const BYTE*)lpbiIn  + lpbiIn->biSize);
1648   rgbOut = (const RGBQUAD*)((const BYTE*)lpbiOut + lpbiOut->biSize);
1649
1650   switch (lpbiOut->biBitCount) {
1651   case 4:
1652   case 8:
1653     pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed);
1654     if (pi->palette_map == NULL)
1655       return ICERR_MEMORY;
1656
1657     for (i = 0; i < lpbiIn->biClrUsed; i++) {
1658       pi->palette_map[i] = MSRLE32_GetNearestPaletteIndex(lpbiOut->biClrUsed, rgbOut, rgbIn[i]);
1659     }
1660     break;
1661   case 15:
1662   case 16:
1663     pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * 2);
1664     if (pi->palette_map == NULL)
1665       return ICERR_MEMORY;
1666
1667     for (i = 0; i < lpbiIn->biClrUsed; i++) {
1668       WORD color;
1669
1670       if (lpbiOut->biBitCount == 15)
1671         color = ((rgbIn[i].rgbRed >> 3) << 10)
1672           | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1673       else
1674         color = ((rgbIn[i].rgbRed >> 3) << 11)
1675           | ((rgbIn[i].rgbGreen >> 3) << 5) | (rgbIn[i].rgbBlue >> 3);
1676
1677       pi->palette_map[i * 2 + 1] = color >> 8;
1678       pi->palette_map[i * 2 + 0] = color & 0xFF;
1679     };
1680     break;
1681   case 24:
1682   case 32:
1683     pi->palette_map = (LPBYTE)LocalAlloc(LPTR, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1684     if (pi->palette_map == NULL)
1685       return ICERR_MEMORY;
1686     memcpy(pi->palette_map, rgbIn, lpbiIn->biClrUsed * sizeof(RGBQUAD));
1687     break;
1688   };
1689
1690   pi->bDecompress = TRUE;
1691
1692   return ICERR_OK;
1693 }
1694
1695 static LRESULT Decompress(CodecInfo *pi, ICDECOMPRESS *pic, DWORD dwSize)
1696 {
1697   TRACE("(%p,%p,%lu)\n",pi,pic,dwSize);
1698
1699   /* pre-condition */
1700   assert(pi != NULL);
1701
1702   /* check parameters */
1703   if (pic == NULL)
1704     return ICERR_BADPARAM;
1705   if (pic->lpbiInput == NULL || pic->lpInput == NULL ||
1706       pic->lpbiOutput == NULL || pic->lpOutput == NULL)
1707     return ICERR_BADPARAM;
1708
1709   /* check formats */
1710   if (! pi->bDecompress) {
1711     LRESULT hr = DecompressBegin(pi, pic->lpbiInput, pic->lpbiOutput);
1712     if (hr != ICERR_OK)
1713       return hr;
1714   } else if (DecompressQuery(pi, pic->lpbiInput, pic->lpbiOutput) != ICERR_OK)
1715     return ICERR_BADFORMAT;
1716
1717   assert(pic->lpbiInput->biWidth  == pic->lpbiOutput->biWidth);
1718   assert(pic->lpbiInput->biHeight == pic->lpbiOutput->biHeight);
1719
1720   pic->lpbiOutput->biSizeImage = DIBWIDTHBYTES(*pic->lpbiOutput) * pic->lpbiOutput->biHeight;
1721   if (pic->lpbiInput->biBitCount == 4)
1722     return MSRLE32_DecompressRLE4(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1723   else
1724     return MSRLE32_DecompressRLE8(pi, pic->lpbiOutput, pic->lpInput, pic->lpOutput);
1725 }
1726
1727 static LRESULT DecompressEnd(CodecInfo *pi)
1728 {
1729   TRACE("(%p)\n",pi);
1730
1731   /* pre-condition */
1732   assert(pi != NULL);
1733
1734   pi->bDecompress = FALSE;
1735
1736   if (pi->palette_map != NULL) {
1737     LocalFree((HLOCAL)pi->palette_map);
1738     pi->palette_map = NULL;
1739   }
1740
1741   return ICERR_OK;
1742 }
1743
1744 static LRESULT DecompressGetPalette(CodecInfo *pi, LPCBITMAPINFOHEADER lpbiIn,
1745                                     LPBITMAPINFOHEADER lpbiOut)
1746 {
1747   int size;
1748
1749   TRACE("(%p,%p,%p)\n",pi,lpbiIn,lpbiOut);
1750
1751   /* pre-condition */
1752   assert(pi != NULL);
1753
1754   /* check parameters */
1755   if (lpbiIn == NULL || lpbiOut == NULL)
1756     return ICERR_BADPARAM;
1757
1758   if (DecompressQuery(pi, lpbiIn, lpbiOut) != ICERR_OK)
1759     return ICERR_BADFORMAT;
1760
1761   if (lpbiOut->biBitCount > 8)
1762     return ICERR_ERROR;
1763
1764   if (lpbiIn->biBitCount <= 8) {
1765     if (lpbiIn->biClrUsed > 0)
1766       size = lpbiIn->biClrUsed;
1767     else
1768       size = (1 << lpbiIn->biBitCount);
1769
1770     lpbiOut->biClrUsed = size;
1771
1772     memcpy((LPBYTE)lpbiOut + lpbiOut->biSize, (const BYTE*)lpbiIn + lpbiIn->biSize, size * sizeof(RGBQUAD));
1773   } /* else could never occur ! */
1774
1775   return ICERR_OK;
1776 }
1777
1778 /* DriverProc - entry point for an installable driver */
1779 LRESULT CALLBACK MSRLE32_DriverProc(DWORD dwDrvID, HDRVR hDrv, UINT uMsg,
1780                                     LPARAM lParam1, LPARAM lParam2)
1781 {
1782   CodecInfo *pi = (CodecInfo*)dwDrvID;
1783
1784   TRACE("(%p,%p,0x%04X,0x%08lX,0x%08lX)\n", (LPVOID)dwDrvID, (LPVOID)hDrv,
1785         uMsg, lParam1, lParam2);
1786
1787   switch (uMsg) {
1788     /* standard driver messages */
1789   case DRV_LOAD:
1790     return DRVCNF_OK;
1791   case DRV_OPEN:
1792     if (lParam2 == 0)
1793       return (LRESULT)0xFFFF0000;
1794     else
1795       return (LRESULT)Open((ICOPEN*)lParam2);
1796   case DRV_CLOSE:
1797     if (dwDrvID != 0xFFFF0000 && (LPVOID)dwDrvID != NULL)
1798       Close(pi);
1799     return DRVCNF_OK;
1800   case DRV_ENABLE:
1801   case DRV_DISABLE:
1802     return DRVCNF_OK;
1803   case DRV_FREE:
1804     return DRVCNF_OK;
1805   case DRV_QUERYCONFIGURE:
1806     return DRVCNF_CANCEL; /* FIXME */
1807   case DRV_CONFIGURE:
1808     return DRVCNF_OK;     /* FIXME */
1809   case DRV_INSTALL:
1810   case DRV_REMOVE:
1811     return DRVCNF_OK;
1812
1813     /* installable compression manager messages */
1814   case ICM_CONFIGURE:
1815     FIXME("ICM_CONFIGURE (%ld)\n",lParam1);
1816     if (lParam1 == -1)
1817       return ICERR_UNSUPPORTED; /* FIXME */
1818     else
1819       return Configure(pi, (HWND)lParam1);
1820   case ICM_ABOUT:
1821     if (lParam1 == -1)
1822       return ICERR_OK;
1823     else
1824       return About(pi, (HWND)lParam1);
1825   case ICM_GETSTATE:
1826   case ICM_SETSTATE:
1827     return 0; /* no state */
1828   case ICM_GETINFO:
1829     return GetInfo(pi, (ICINFO*)lParam1, (DWORD)lParam2);
1830   case ICM_GETDEFAULTQUALITY:
1831     if ((LPVOID)lParam1 != NULL) {
1832       *((LPDWORD)lParam1) = MSRLE32_DEFAULTQUALITY;
1833       return ICERR_OK;
1834     }
1835     break;
1836   case ICM_GETQUALITY:
1837     if ((LPVOID)lParam1 != NULL) {
1838       *((LPDWORD)lParam1) = pi->dwQuality;
1839       return ICERR_OK;
1840     }
1841     break;
1842   case ICM_SETQUALITY:
1843     return SetQuality(pi, *(LPLONG)lParam1);
1844     break;
1845   case ICM_COMPRESS_GET_FORMAT:
1846     return CompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1847                              (LPBITMAPINFOHEADER)lParam2);
1848   case ICM_COMPRESS_GET_SIZE:
1849     return CompressGetSize(pi, (LPCBITMAPINFOHEADER)lParam1,
1850                            (LPCBITMAPINFOHEADER)lParam2);
1851   case ICM_COMPRESS_QUERY:
1852     return CompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1853                          (LPCBITMAPINFOHEADER)lParam2);
1854   case ICM_COMPRESS_BEGIN:
1855     return CompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1856                          (LPCBITMAPINFOHEADER)lParam2);
1857   case ICM_COMPRESS:
1858     return Compress(pi, (ICCOMPRESS*)lParam1, (DWORD)lParam2);
1859   case ICM_COMPRESS_END:
1860     return CompressEnd(pi);
1861   case ICM_DECOMPRESS_GET_FORMAT:
1862     return DecompressGetFormat(pi, (LPCBITMAPINFOHEADER)lParam1,
1863                                (LPBITMAPINFOHEADER)lParam2);
1864   case ICM_DECOMPRESS_QUERY:
1865     return DecompressQuery(pi, (LPCBITMAPINFOHEADER)lParam1,
1866                            (LPCBITMAPINFOHEADER)lParam2);
1867   case ICM_DECOMPRESS_BEGIN:
1868     return DecompressBegin(pi, (LPCBITMAPINFOHEADER)lParam1,
1869                            (LPCBITMAPINFOHEADER)lParam2);
1870   case ICM_DECOMPRESS:
1871     return Decompress(pi, (ICDECOMPRESS*)lParam1, (DWORD)lParam2);
1872   case ICM_DECOMPRESS_END:
1873     return DecompressEnd(pi);
1874   case ICM_DECOMPRESS_SET_PALETTE:
1875     FIXME("(...) -> SetPalette(%p,%p,%p): stub!\n", pi, (LPVOID)lParam1, (LPVOID)lParam2);
1876     return ICERR_UNSUPPORTED;
1877   case ICM_DECOMPRESS_GET_PALETTE:
1878     return DecompressGetPalette(pi, (LPBITMAPINFOHEADER)lParam1,
1879                                 (LPBITMAPINFOHEADER)lParam2);
1880   case ICM_GETDEFAULTKEYFRAMERATE:
1881     if ((LPVOID)lParam1 != NULL)
1882       *(LPDWORD)lParam1 = 15;
1883     return ICERR_OK;
1884   default:
1885     if (uMsg < DRV_USER)
1886       return DefDriverProc(dwDrvID, hDrv, uMsg, lParam1, lParam2);
1887     else
1888       FIXME("Unknown message uMsg=0x%08X lParam1=0x%08lX lParam2=0x%08lX\n",uMsg,lParam1,lParam2);
1889   };
1890
1891   return ICERR_UNSUPPORTED;
1892 }
1893
1894 /* DllMain - library initialization code */
1895 BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved)
1896 {
1897   TRACE("(%p,%ld,%p)\n",(LPVOID)hModule,dwReason,lpReserved);
1898
1899   switch (dwReason) {
1900   case DLL_PROCESS_ATTACH:
1901     DisableThreadLibraryCalls(hModule);
1902     MSRLE32_hModule = hModule;
1903     break;
1904
1905   case DLL_PROCESS_DETACH:
1906     break;
1907   };
1908
1909   return TRUE;
1910 }