Merge branch 'master' of git://git.denx.de/u-boot-arm
[platform/kernel/u-boot.git] / lib_generic / zlib.c
index f415f6b..26e5af1 100644 (file)
 #define ZUTIL_H
 #define ZLIB_INTERNAL
 
+#include <common.h>
+#include <compiler.h>
+#include <asm/unaligned.h>
 #include "u-boot/zlib.h"
+#undef OFF                             /* avoid conflicts */
+
 /* To avoid a build time warning */
 #ifdef STDC
 #include <malloc.h>
@@ -83,10 +88,10 @@ typedef unsigned long ulg;
 
 /* Diagnostic functions */
 #ifdef DEBUG
-#include <stdio.h>
        extern int z_verbose;
        extern void z_error    OF((char *m));
 #define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#define fprintf(fp,...)        printf(__VA_ARGS__)
 #define Trace(x) {if (z_verbose>=0) fprintf x ;}
 #define Tracev(x) {if (z_verbose>0) fprintf x ;}
 #define Tracevv(x) {if (z_verbose>1) fprintf x ;}
@@ -399,6 +404,7 @@ void inflate_fast OF((z_streamp strm, unsigned start));
  */
 #define OFF 1
 #define PUP(a) *++(a)
+#define UP_UNALIGNED(a) get_unaligned(++(a))
 
 /*
    Decode literal, length, and distance codes and write out the resulting
@@ -615,18 +621,47 @@ unsigned start;         /* inflate()'s starting value for strm->avail_out */
                     }
                 }
                 else {
+                   unsigned short *sout;
+                   unsigned long loops;
+
                     from = out - dist;          /* copy direct from output */
-                    do {                        /* minimum length is three */
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
-                        PUP(out) = PUP(from);
-                        len -= 3;
-                    } while (len > 2);
-                    if (len) {
-                        PUP(out) = PUP(from);
-                        if (len > 1)
-                            PUP(out) = PUP(from);
-                    }
+                    /* minimum length is three */
+                   /* Align out addr */
+                   if (!((long)(out - 1 + OFF) & 1)) {
+                       PUP(out) = PUP(from);
+                       len--;
+                   }
+                   sout = (unsigned short *)(out - OFF);
+                   if (dist > 2 ) {
+                       unsigned short *sfrom;
+
+                       sfrom = (unsigned short *)(from - OFF);
+                       loops = len >> 1;
+                       do
+                           PUP(sout) = UP_UNALIGNED(sfrom);
+                       while (--loops);
+                       out = (unsigned char *)sout + OFF;
+                       from = (unsigned char *)sfrom + OFF;
+                   } else { /* dist == 1 or dist == 2 */
+                       unsigned short pat16;
+
+                       pat16 = *(sout-2+2*OFF);
+                       if (dist == 1)
+#if defined(__BIG_ENDIAN)
+                           pat16 = (pat16 & 0xff) | ((pat16 & 0xff ) << 8);
+#elif defined(__LITTLE_ENDIAN)
+                           pat16 = (pat16 & 0xff00) | ((pat16 & 0xff00 ) >> 8);
+#else
+#error __BIG_ENDIAN nor __LITTLE_ENDIAN is defined
+#endif
+                       loops = len >> 1;
+                       do
+                           PUP(sout) = pat16;
+                       while (--loops);
+                       out = (unsigned char *)sout + OFF;
+                   }
+                   if (len & 1)
+                       PUP(out) = PUP(from);
                 }
             }
             else if ((op & 64) == 0) {          /* 2nd level distance code */
@@ -1040,6 +1075,8 @@ z_streamp strm;
     state->hold = 0;
     state->bits = 0;
     state->lencode = state->distcode = state->next = state->codes;
+    if (strm->outcb != Z_NULL)
+       (*strm->outcb)(Z_NULL, 0);
     Tracev((stderr, "inflate: reset\n"));
     return Z_OK;
 }
@@ -1365,7 +1402,7 @@ int flush;
     static const unsigned short order[19] = /* permutation of code lengths */
         {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
 
-    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+    if (strm == Z_NULL || strm->state == Z_NULL ||
         (strm->next_in == Z_NULL && strm->avail_in != 0))
         return Z_STREAM_ERROR;
 
@@ -1739,6 +1776,8 @@ int flush;
             Tracev((stderr, "inflate:       codes ok\n"));
             state->mode = LEN;
         case LEN:
+            if (strm->outcb != Z_NULL) /* for watchdog (U-Boot) */
+                (*strm->outcb)(Z_NULL, 0);
             if (have >= 6 && left >= 258) {
                 RESTORE();
                 inflate_fast(strm, out);
@@ -1950,7 +1989,11 @@ z_streamp strm;
     if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
         return Z_STREAM_ERROR;
     state = (struct inflate_state FAR *)strm->state;
-    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    if (state->window != Z_NULL) {
+       if (strm->outcb != Z_NULL)
+               (*strm->outcb)(Z_NULL, 0);
+       ZFREE(strm, state->window);
+    }
     ZFREE(strm, strm->state);
     strm->state = Z_NULL;
     Tracev((stderr, "inflate: end\n"));
@@ -1992,7 +2035,7 @@ void z_error (m)
     char *m;
 {
        fprintf(stderr, "%s\n", m);
-       exit(1);
+       hang ();
 }
 #endif