+ offsetof(zip_header_t, fmt.extra_len) + 2
+ == ZIP_HEADER_LEN ? 1 : -1];
+ char BUG_cdf_header_must_be_42_bytes[
+ offsetof(cdf_header_t, fmt.relative_offset_of_local_header) + 4
+ == CDF_HEADER_LEN ? 1 : -1];
+ char BUG_cde_must_be_16_bytes[
+ sizeof(cde_t) == CDE_LEN ? 1 : -1];
+};
+
+
+enum { zip_fd = 3 };
+
+
+/* This value means that we failed to find CDF */
+#define BAD_CDF_OFFSET ((uint32_t)0xffffffff)
+
+#if !ENABLE_FEATURE_UNZIP_CDF
+
+# define find_cdf_offset() BAD_CDF_OFFSET
+
+#else
+/* Seen in the wild:
+ * Self-extracting PRO2K3XP_32.exe contains 19078464 byte zip archive,
+ * where CDE was nearly 48 kbytes before EOF.
+ * (Surprisingly, it also apparently has *another* CDE structure
+ * closer to the end, with bogus cdf_offset).
+ * To make extraction work, bumped PEEK_FROM_END from 16k to 64k.
+ */
+#define PEEK_FROM_END (64*1024)
+/* NB: does not preserve file position! */
+static uint32_t find_cdf_offset(void)
+{
+ cde_t cde;
+ unsigned char *buf;
+ unsigned char *p;
+ off_t end;
+ uint32_t found;
+
+ end = lseek(zip_fd, 0, SEEK_END);
+ if (end == (off_t) -1)
+ return BAD_CDF_OFFSET;
+
+ end -= PEEK_FROM_END;
+ if (end < 0)
+ end = 0;
+
+ dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end);
+ xlseek(zip_fd, end, SEEK_SET);
+ buf = xzalloc(PEEK_FROM_END);
+ full_read(zip_fd, buf, PEEK_FROM_END);
+
+ found = BAD_CDF_OFFSET;
+ p = buf;
+ while (p <= buf + PEEK_FROM_END - CDE_LEN - 4) {
+ if (*p != 'P') {
+ p++;
+ continue;
+ }
+ if (*++p != 'K')
+ continue;
+ if (*++p != 5)
+ continue;
+ if (*++p != 6)
+ continue;
+ /* we found CDE! */
+ memcpy(cde.raw, p + 1, CDE_LEN);
+ FIX_ENDIANNESS_CDE(cde);
+ /*
+ * I've seen .ZIP files with seemingly valid CDEs
+ * where cdf_offset points past EOF - ??
+ * This check ignores such CDEs:
+ */
+ if (cde.fmt.cdf_offset < end + (p - buf)) {
+ found = cde.fmt.cdf_offset;
+ dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x",
+ (unsigned)found, end + (p-3 - buf));
+ dbg(" cdf_offset+cdf_size:0x%x",
+ (unsigned)(found + SWAP_LE32(cde.fmt.cdf_size)));
+ /*
+ * We do not "break" here because only the last CDE is valid.
+ * I've seen a .zip archive which contained a .zip file,
+ * uncompressed, and taking the first CDE was using
+ * the CDE inside that file!
+ */
+ }
+ }
+ free(buf);
+ dbg("Found cdf_offset:0x%x", (unsigned)found);
+ return found;
+};
+
+static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf)
+{
+ uint32_t magic;
+
+ if (cdf_offset == BAD_CDF_OFFSET)
+ return cdf_offset;
+
+ dbg("Reading CDF at 0x%x", (unsigned)cdf_offset);
+ xlseek(zip_fd, cdf_offset, SEEK_SET);
+ xread(zip_fd, &magic, 4);
+ /* Central Directory End? Assume CDF has ended.
+ * (more correct method is to use cde.cdf_entries_total counter)
+ */
+ if (magic == ZIP_CDE_MAGIC) {
+ dbg("got ZIP_CDE_MAGIC");
+ return 0; /* EOF */
+ }
+ xread(zip_fd, cdf->raw, CDF_HEADER_LEN);
+
+ FIX_ENDIANNESS_CDF(*cdf);
+ dbg(" filename_len:%u extra_len:%u file_comment_length:%u",
+ (unsigned)cdf->fmt.filename_len,
+ (unsigned)cdf->fmt.extra_len,
+ (unsigned)cdf->fmt.file_comment_length
+ );
+ cdf_offset += 4 + CDF_HEADER_LEN
+ + cdf->fmt.filename_len
+ + cdf->fmt.extra_len
+ + cdf->fmt.file_comment_length;
+
+ return cdf_offset;