#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "../../src/include/otezip/zip.h"

/* Deflate entry whose stream decodes to "a" but which declares 5 bytes and the
 * CRC of "a\0\0\0\0", i.e. what zero-padding the short output would produce */
static const uint8_t short_zip[] = {
	0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
	0x00, 0x00, 0xe0, 0xa9, 0x70, 0x62, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00,
	0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x2e,
	0x74, 0x78, 0x74, 0x4b, 0x04, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00,
	0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xa9,
	0x70, 0x62, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x78,
	0x74, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
	0x00, 0x37, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00
};

int main(void) {
	char path[] = "/tmp/otezip-short-XXXXXX";
	int fd = mkstemp (path);
	if (fd < 0) {
		perror ("mkstemp");
		return 1;
	}
	if (write (fd, short_zip, sizeof (short_zip)) != (ssize_t)sizeof (short_zip)) {
		perror ("write");
		close (fd);
		unlink (path);
		return 1;
	}
	close (fd);

	int failed = 0;
	int err = 0;
	zip_t *za = zip_open (path, ZIP_RDONLY, &err);
	if (!za) {
		fprintf (stderr, "FAIL: zip_open (err=%d)\n", err);
		failed = 1;
	} else {
		otezip_verify_crc = 1;
		/* The error may surface at open or while reading the entry */
		zip_file_t *zf = zip_fopen_index (za, 0, 0);
		if (zf) {
			char buf[16];
			zip_int64_t n;
			while ((n = zip_fread (zf, buf, sizeof (buf))) > 0) {
			}
			if (n == 0) {
				fprintf (stderr, "FAIL: deflate output shorter than its declared size was accepted\n");
				failed = 1;
			}
			zip_fclose (zf);
		}
		zip_close (za);
	}
	unlink (path);
	if (!failed) {
		puts ("TEST PASSED: Short deflate output is rejected.");
	}
	return failed;
}
