aboutsummaryrefslogtreecommitdiff
path: root/lib/zlib/inffast.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zlib/inffast.c')
-rw-r--r--lib/zlib/inffast.c51
1 files changed, 40 insertions, 11 deletions
diff --git a/lib/zlib/inffast.c b/lib/zlib/inffast.c
index 5e2a65ad4d2..b5a0adcce69 100644
--- a/lib/zlib/inffast.c
+++ b/lib/zlib/inffast.c
@@ -236,18 +236,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 */
- *out++ = *from++;
- *out++ = *from++;
- *out++ = *from++;
- len -= 3;
- } while (len > 2);
- if (len) {
- *out++ = *from++;
- if (len > 1)
- *out++ = *from++;
- }
+ /* minimum length is three */
+ /* Align out addr */
+ if (!((long)(out - 1) & 1)) {
+ *out++ = *from++;
+ len--;
+ }
+ sout = (unsigned short *)out;
+ if (dist > 2 ) {
+ unsigned short *sfrom;
+
+ sfrom = (unsigned short *)from;
+ loops = len >> 1;
+ do
+ *sout++ = get_unaligned(sfrom++);
+ while (--loops);
+ out = (unsigned char *)sout;
+ from = (unsigned char *)sfrom;
+ } else { /* dist == 1 or dist == 2 */
+ unsigned short pat16;
+
+ pat16 = *(sout - 1);
+ 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
+ *sout++ = pat16;
+ while (--loops);
+ out = (unsigned char *)sout;
+ }
+ if (len & 1)
+ *out++ = *from++;
}
}
else if ((op & 64) == 0) { /* 2nd level distance code */