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